V4L2 学习笔记(热成像专题)

设备信息

  • 设备: YXG309T 红外热成像传感器(识别为 uvcvideo HikCamera: UVC Camera
  • USB: ID 2bdf:0102 HIK HikCamera
  • UVC Extension Unit: Unit=10, 23个 Selector, 512字节
  • 分辨率: 256x196(固定,S_FMT 全部 EIO),实际热成像区 256x192

核心发现:YUYV = 16-bit 温度数据容器

YUYV 格式在这里不是视频格式,而是 16-bit 原始温度数据的传输容器。

  • 每 4 字节(Y0 U0 Y1 V0)实际是两个连续像素的 低字节 + 高字节
  • U/V 通道携带的是高字节数据,不是颜色信息
  • 同一份数据:映射伪彩色 = 热成像图,换算公式 = 温度值
  • 不需要额外的数据通道,不需要第二个设备节点

帧结构 (256 x 196 = 100352 bytes)

┌─────────────────────────────────────┐
│  行 0~191: 256x192 热成像像素数据    │ ← 16-bit LE, 每像素2字节
│  ┌─────────────────────────────┐    │
│  │  最热点 H: 红圈标记          │    │
│  │  最冷点 L: 蓝圈标记          │    │
│  │  中心 +: 十字准心            │    │
│  └─────────────────────────────┘    │
│  行 192: 元数据块 1                 │ ← 状态/配置信息
│  行 193: 元数据块 2                 │ ← 可能含 min/max/校准值
│  行 194~195: 填充                  │ ← 全 0
└─────────────────────────────────────┘

温度换算

T(°C) = raw_value / scale + offset

// 当前估算: scale=200, offset=0  (需校准)
// 实测范围: raw=4872~5369 → ~24.4°C~26.8°C

已完成示例

001 — 查询设备能力 VIDIOC_QUERYCAP

  • 文件: 001_v4l2_info.c
  • 打开 /dev/videoX,查询 v4l2_capability
  • 热成像设备显示为 uvcvideo 驱动(UVC 兼容模式)

002 — 格式枚举和协商

  • 文件: 002_v4l2_fmt.c
  • ENUM_FMT / ENUM_FRAMESIZES / G_FMT / TRY_FMT / S_FMT
  • 热成像设备 S_FMT 全部返回 EIO(固定格式),需用 G_FMT 获取

003 — 控件调节

  • 文件: 003_v4l2_ctrl.c
  • QUERYCTRL / QUERYMENU / G_CTRL / S_CTRL
  • 热成像设备 无任何 V4L2 控件(无亮度/对比度等)

004 — 输入/输出选择

  • 文件: 004_v4l2_input.c
  • ENUMINPUT / G_INPUT / S_INPUT / ENUMOUTPUT / ENUMSTD
  • 热成像设备通常只有 1 个输入源

005 — read() 方式采集

  • 文件: 005_v4l2_read.c
  • UVC 热成像设备 不支持 read(),需用 mmap

006 — mmap Streaming I/O ⭐

  • 文件: 006_v4l2_mmap.c
  • V4L2 核心流程:
    S_FMT → REQBUFS → QUERYBUF+mmap → QBUF×N → STREAMON
                                                ↕
                                      DQBUF → 处理 → QBUF 归还
                                                ↕
                                            循环采集
                                                ↓
                                      STREAMOFF → munmap → REQBUFS(0)
    
  • 实测: 4 缓冲区, ~25fps, 每帧 100352 bytes
  • 热成像设备的唯一采集方式

013 — 热成像温度数据提取

  • 文件: 013_v4l2_thermal.c
  • 从 mmap 帧中提取 256x192 的 16-bit 温度原始值
  • 输出: thermal_raw.pgm(16-bit), thermal_8bit.pgm(灰度图), thermal_temps.csv(温度矩阵)
  • 打印最热点/最冷点位置及温度

014 — Framebuffer 实时显示

  • 文件: 014_v4l2_fb.c
  • 实时热成像显示,火焰伪彩色
  • HUD 信息: 中心温度、最高温(红标)、最低温(蓝标)
  • 右侧色标条,中心十字准心
  • /dev/fb0 800x600 32bpp,2x 缩放

XU 自定义协议探测

  • Extension Unit ID=10,GUID: {a29e7641-de04-47e3-8b2b-f4341aff003b}
  • 23 个 control selector(1~23)
  • Selectors 1/2/3/5/10: 支持 GET_CUR + SET_CUR(可读写)
  • Selectors 4/6: 仅 GET_CUR(只读)
  • 可能用途: 分辨率切换、帧率控制、校准参数等
  • 文件: 007_check_xu.c

待完成(标准 V4L2)

007 — poll() 非阻塞采集

  • poll()select() 等待帧就绪
  • 结合 DQBUF 实现超时机制
  • 适合多路复用场景(同时采集视频 + 处理用户输入)

008 — userptr 模式

  • 应用程序自己分配内存,通过 USERPTR 传递给驱动
  • 对比 mmap:优缺点、适用场景
  • 了解 DMABUF(零拷贝共享)

009 — 裁剪和缩放 VIDIOC_SELECTION

  • VIDIOC_G_SELECTION / VIDIOC_S_SELECTION
  • target: CROP(裁剪)/ COMPOSE(缩放)
  • 原生分辨率下裁剪 ROI 再采集

010 — V4L2 Events

  • VIDIOC_SUBSCRIBE_EVENT — 订阅事件
  • VIDIOC_DQEVENT — 取出事件
  • 典型事件:失焦、断开连接、控件变化

011 — Memory-to-Memory 设备

  • M2M 设备模型,硬件编解码器(H264、JPEG)
  • 同时维护 capture 和 output 两个队列

012 — V4L2 subdev

  • v4l2-subdev 子设备接口,Sensor / ISP 级别控制
  • 通过 padpad-level format 操作

TODO / 可继续方向

  • 校准温度公式: 用已知温度物体测 raw 值,算出真实 scale/offset
  • 解析行 192~193 元数据: 找出校准参数、帧统计信息
  • 通过 XU 修改分辨率: 研究 unit=10 的 selector 协议
  • 007 — poll() 非阻塞采集
  • 008 — userptr 模式
  • 015 — 伪彩色增强: 自适应动态范围、多色表切换
  • 016 — 帧处理: 多帧降噪、温度追踪、ROI 测温

常用调试命令

v4l2-ctl -d /dev/video0 --all          # 查看完整设备信息
v4l2-ctl -d /dev/video0 --list-formats  # 列出格式
v4l2-ctl -d /dev/video0 --list-ctrls    # 列出控件
lsusb -d 2bdf:0102 -v                   # USB 描述符
cat /sys/class/video4linux/video0/name  # 设备名称

编译方法

gcc -o 00X_v4l2_xxx 00X_v4l2_xxx.c -lm
sudo ./00X_v4l2_xxx        # framebuffer 显示需要 sudo