3. V4L2 裁剪(Crop)概念:源裁剪与目标裁剪

在 V4L2 视频处理 pipeline 中,裁剪(Crop)是图像数据进入硬件或软件处理引擎前的关键预处理步骤。V4L2 将裁剪抽象为两个独立但关联的概念:源裁剪(Source Crop)与目标裁剪(Destination Crop / Compose)。理解这两者的区别,是正确配置 ISP、M2M 设备以及实现高效缩放的基础。

3.1 源裁剪 (Source Crop) —— 从原始帧中“切出”感兴趣区域

源裁剪定义从输入缓冲区(即传感器原始图像或解码后的帧)中选取一个矩形区域,该区域称为“感兴趣区域”(ROI)。后续所有处理(缩放、格式转换、编码)都仅针对这个子区域进行。

  • 作用对象:输入图像(Source Buffer)。
  • 坐标系统:相对于原始图像左上角 (0,0)。
  • 典型用途:去除黑边、聚焦画面中心、电子防抖裁剪、多路拼接前的单路裁剪。
  • V4L2 控制标识:V4L2_SEL_TGT_CROP。
关键理解:源裁剪不改变图像的分辨率,它只是定义了一个“窗口”。裁剪后的数据尺寸等于 src_rect.width × src_rect.height,但该数据会作为后续缩放或格式转换的输入。

3.2 目标裁剪 (Destination Crop / Compose) —— 定义输出图像中的放置位置

目标裁剪(在 V4L2 中常被称为 Compose)定义经过缩放或格式转换后的图像,在输出缓冲区中的放置位置和大小。它决定了最终图像在目标帧中的布局。

  • 作用对象:输出图像(Destination Buffer)。
  • 坐标系统:相对于输出缓冲区左上角 (0,0)。
  • 典型用途:画中画(PIP)、多路合成、将裁剪缩放后的图像贴到输出帧的特定位置。
  • V4L2 控制标识:V4L2_SEL_TGT_COMPOSE。
记忆技巧:“CROP”是“从源里切”,“COMPOSE”是“往目标里贴”。CROP 决定看什么,COMPOSE 决定放哪里、放多大。

3.3 裁剪与缩放的关系:从 CROP 到 COMPOSE 的映射

当设备同时支持裁剪和缩放时,V4L2_SEL_TGT_CROP 和 V4L2_SEL_TGT_COMPOSE 共同定义了一个完整的几何变换 pipeline:

  1. 输入:原始图像(例如 1920x1080)。
  2. 源裁剪:从原始图像中切出 src_rect(例如 1280x720,从 (320, 180) 开始)。
  3. 缩放:硬件或软件将裁剪出的 1280x720 图像缩放至 dst_rect 指定的尺寸(例如 640x360)。
  4. 目标放置:将缩放后的 640x360 图像放置在输出缓冲区的 compose_rect 位置(例如从 (100, 50) 开始)。

如果设备不支持缩放,则 src_rect 的尺寸必须等于 compose_rect 的尺寸,否则驱动会返回错误。

常见误区:不要混淆 V4L2_SEL_TGT_CROP 与 V4L2_SEL_TGT_COMPOSE 的尺寸关系。CROP 尺寸是缩放前的输入尺寸,COMPOSE 尺寸是缩放后的输出尺寸。如果不需要缩放,两者尺寸应一致。

3.4 V4L2_SEL_TGT_CROP 与 V4L2_SEL_TGT_COMPOSE 对比表

属性 V4L2_SEL_TGT_CROP (源裁剪) V4L2_SEL_TGT_COMPOSE (目标裁剪)
语义 从输入图像中选取子区域 在输出图像中定义放置区域
坐标基准 输入缓冲区坐标系 输出缓冲区坐标系
影响阶段 预处理(缩放/转换前) 后处理(缩放/转换后)
尺寸含义 缩放前的像素尺寸 缩放后的像素尺寸
典型应用 去黑边、电子防抖、ROI 提取 画中画、多路合成、帧布局
V4L2 标识 V4L2_SEL_TGT_CROP V4L2_SEL_TGT_COMPOSE
是否可缩放 否(仅定义窗口) 是(定义最终尺寸)

3.5 裁剪与缩放 Pipeline 流程图

下图展示了从源裁剪到目标裁剪的完整数据流,以及缩放器(Scaler)在其中的位置:

V4L2 裁剪与缩放 Pipeline V4L2 裁剪与缩放 Pipeline 原始图像 1920x1080 源裁剪 (CROP) V4L2_SEL_TGT_CROP 1280x720 @ (320,180) 缩放器 1280x720 → 640x360 (硬件/软件) 目标裁剪 (COMPOSE) V4L2_SEL_TGT_COMPOSE 640x360 @ (100,50) 输出缓冲区 1920x1080 说明: 1. 源裁剪 (CROP) 从原始图像中切出 ROI,不改变分辨率。 2. 缩放器将裁剪后的图像缩放到目标尺寸。 3. 目标裁剪 (COMPOSE) 将缩放后的图像放置到输出缓冲区的指定位置。

3.6 实际应用场景:画中画 (PIP) 配置示例

假设我们需要实现一个画中画功能:主画面为 1920x1080,子画面(PIP)为 320x180,放置在右下角。使用 V4L2 M2M 设备的配置流程如下:

struct v4l2_selection sel;

// 1. 配置源裁剪:从原始帧中切出子画面区域
sel.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;  // 输入队列
sel.target = V4L2_SEL_TGT_CROP;
sel.r.left = 0;      // 从原始帧左上角开始
sel.r.top = 0;
sel.r.width = 1280;  // 裁剪宽度
sel.r.height = 720;  // 裁剪高度
ioctl(fd, VIDIOC_S_SELECTION, &sel);

// 2. 配置目标裁剪:将缩放后的子画面放到输出帧右下角
sel.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  // 输出队列
sel.target = V4L2_SEL_TGT_COMPOSE;
sel.r.left = 1920 - 320 - 20;  // 右边距 20 像素
sel.r.top = 1080 - 180 - 20;   // 底边距 20 像素
sel.r.width = 320;   // 缩放后宽度
sel.r.height = 180;  // 缩放后高度
ioctl(fd, VIDIOC_S_SELECTION, &sel);
性能提示:在配置裁剪时,尽量让 src_rect 的宽度和高度对齐到 16 或 32 字节边界。许多硬件 ISP 和 DMA 引擎对非对齐裁剪会进行额外的填充或拷贝,导致性能下降 10%~30%。

3.7 常见问题与避坑指南

  • 裁剪坐标越界:src_rect.left + src_rect.width 不能超过输入图像的宽度,否则驱动会返回 -ERANGE。建议先通过 VIDIOC_G_SELECTION 查询设备支持的裁剪边界。
  • 缩放比例限制:并非所有设备都支持任意缩放比例。通常硬件缩放器有最小/最大缩放因子(如 1/16x ~ 16x),超出范围会静默截断或返回错误。
  • 格式对齐要求:YUV 格式下,裁剪的起始坐标和宽高必须满足色度子采样对齐(如 NV12 要求宽高为偶数,起始坐标为偶数)。
  • COMPOSE 与 CROP 的互斥性:某些简单设备不支持同时设置 CROP 和 COMPOSE,此时只能设置其中一个,另一个会被驱动自动计算。
调试建议:当裁剪结果不符合预期时,使用 v4l2-ctl --get-crop 和 v4l2-ctl --get-compose 查看当前设备的实际配置。同时检查驱动日志(dmesg)中是否有“crop rect clipped to bounds”之类的警告。