4. V4L2 裁剪矩形结构体:struct v4l2_rect 的成员及坐标系统

在 V4L2 的裁剪(CROP)与合成(COMPOSE)操作中,所有窗口和区域的定义都依赖于一个核心数据结构——struct v4l2_rect。理解该结构体的成员含义及其背后的坐标系统,是正确配置裁剪与合成参数的前提。

4.1 struct v4l2_rect 结构体定义

该结构体定义在 Linux 内核头文件 linux/videodev2.h 中,用于描述一个二维矩形区域。其成员非常直观,包含矩形左上角坐标以及矩形的宽高。

struct v4l2_rect {
    __s32   left;       /* 矩形左上角 X 坐标 */
    __s32   top;        /* 矩形左上角 Y 坐标 */
    __u32   width;      /* 矩形宽度(像素) */
    __u32   height;     /* 矩形高度(像素) */
};
数据类型说明: 注意 left 和 top 是 __s32(有符号 32 位整数),允许负坐标值;而 width 和 height 是 __u32(无符号 32 位整数),表示尺寸必须为非负值。

4.2 成员详细解析

成员 类型 含义 取值范围说明
left __s32 矩形左上角顶点的 X 坐标(水平方向) 可为负值,表示裁剪区域起始于图像有效数据边界之外
top __s32 矩形左上角顶点的 Y 坐标(垂直方向) 可为负值,表示裁剪区域起始于图像有效数据边界之上
width __u32 矩形的宽度,单位为像素 必须 ≥ 1,且 left + width 不应超出源图像边界(硬件限制)
height __u32 矩形的高度,单位为像素 必须 ≥ 1,且 top + height 不应超出源图像边界(硬件限制)

4.3 V4L2 坐标系统

V4L2 的坐标系统遵循标准的计算机图形学惯例,与大多数图像处理库(如 OpenCV)保持一致。理解该坐标系统对于正确设置 left 和 top 至关重要。

  • 原点位置: 坐标原点 (0, 0) 位于图像帧的左上角。
  • X 轴方向: 水平向右为正方向。
  • Y 轴方向: 垂直向下为正方向。
  • 像素寻址: 每个坐标点 (x, y) 对应一个像素单元。矩形区域包含从 left 到 left + width - 1,以及从 top 到 top + height - 1 的所有像素。
V4L2 坐标系统与 v4l2_rect 示意图 V4L2 坐标系统与 v4l2_rect 示意图 源图像帧(Source Frame) X Y (0, 0) v4l2_rect left top width height (left, top) 图例说明 裁剪/合成区域 坐标点 偏移量 尺寸

4.4 坐标系统与裁剪/合成的关系

在 CROP 和 COMPOSE 操作中,struct v4l2_rect 扮演着不同的角色,但其坐标系统始终遵循上述规则。

  • CROP(裁剪): v4l2_rect 定义的是从源图像中选取的一个矩形窗口。该窗口的坐标是相对于源图像左上角 (0, 0) 的。例如,left=10, top=20, width=100, height=80 表示从源图像的第 10 列、第 20 行开始,截取一个 100x80 像素的区域。
  • COMPOSE(合成): v4l2_rect 定义的是在目标缓冲区中放置图像数据的矩形窗口。该窗口的坐标是相对于目标缓冲区左上角 (0, 0) 的。例如,left=0, top=0, width=640, height=480 表示将图像数据填充到目标缓冲区的整个区域。
边界检查: 虽然 left 和 top 允许负值,但实际硬件驱动可能不支持负坐标或超出源图像边界的裁剪区域。在设置 v4l2_rect 时,应始终通过 VIDIOC_G/S_CROP 或 VIDIOC_G/S_SELECTION 查询设备的实际边界限制(V4L2_SEL_TGT_CROP_BOUNDS 或 V4L2_SEL_TGT_COMPOSE_BOUNDS),避免配置无效区域导致驱动报错或图像异常。

4.5 常见配置示例

以下示例展示了如何初始化一个 struct v4l2_rect 结构体,用于从 1920x1080 的源图像中心裁剪一个 1280x720 的区域。

struct v4l2_rect crop_rect;

/* 计算中心裁剪区域的偏移量 */
crop_rect.left   = (1920 - 1280) / 2;  /* 结果为 320 */
crop_rect.top    = (1080 - 720)  / 2;  /* 结果为 180 */
crop_rect.width  = 1280;
crop_rect.height = 720;

printf("Crop rect: left=%d, top=%d, width=%u, height=%u\n",
       crop_rect.left, crop_rect.top,
       crop_rect.width, crop_rect.height);
实战要点: 在编写应用程序时,建议始终使用 VIDIOC_G_SELECTION 查询当前设备的默认裁剪/合成区域,然后基于该默认值进行微调,而不是硬编码坐标值。这样可以提高代码对不同摄像头模组的兼容性。