有以下几种方案可以尝试一下:
1. 修改 GDC 旋转配置 (gen_gdc_bin_rotation)
你提到的 gen_gdc_bin_rotation() 函数负责生成 GDC 的任务描述符。要消除黑边,必须确保 GDC 的输出裁剪(Crop) 或 输出尺寸设置 精确匹配有效像素。
方案 A:调整 GDC 输出尺寸(推荐)
在生成 GDC bin 时,确保 dst_w 和 dst_h 严格等于旋转后的有效像素,而不是对齐后的内存尺寸。
- 逻辑修正:
- 获取 Sensor 的有效宽高:
src_w = 1088, src_h = 1280。
- 旋转 90 度后,目标宽高应为:
dst_w = 1280, dst_h = 1088。
- 关键点:检查 GDC 配置结构中是否有
crop 或 rect 字段。如果有,确保源裁剪区域(Src Rect)只包含有效像素,不包含 Blanking 区。
方案 B:在 GDC 后增加软件裁剪(最稳妥)
由于硬件 GDC 的对齐限制(通常要求宽度 16/32/64 字节对齐),直接通过 GDC 去除几个像素的黑边可能比较困难(取决于具体 GDC 版本支持的粒度)。最简单的工程化做法是在 GDC 输出后,立即进行内存拷贝裁剪。
在 hobot_mipi_cam 的代码流程中,找到 GDC 回调或数据导出位置:
// 假设 gdc_output_img 是 GDC 旋转后的图像
// 已知黑边:Top 1, Bottom 2, Left 3, Right 0
// 期望输出:1280 x 1088
cv::Mat rotated_img = ...; // 从 GDC buffer 转换来的 cv::Mat
// 执行裁剪
// range: [y_start, y_end), [x_start, x_end)
cv::Mat clean_img = rotated_img(cv::Rect(3, 1, 1280 - 3, 1088 - 1 - 2));
// 注意:如果 rotated_img 的总尺寸不是 1280x1088+黑边,而是更大的对齐尺寸
// 你需要先确认 rotated_img 的实际 size。
// 根据你的描述,旋转后分辨率显示为 1280x2176 (双摄?) 或单摄的某个值。
// 如果是单摄 1280x1088 期望值,但实际有黑边,说明实际 Buffer 可能是 1280x1091 或类似。
2. 针对 mipi_cam_dual_channel 的特殊处理
你使用的是双通道脚本。SC132GS 双摄通常是两个独立的 Sensor。
- 现象回顾:旋转前
1088x2560,旋转后 1280x2176。
- 分析:
2560 = 1280 * 2。说明旋转前是两个 1088x1280 的图像左右拼接(Width 1088+1088? 不对,1088+1088=2176。这里是 1088x2560,说明是 上下拼接?即 Width 1088, Height 1280+1280=2560)。
- 如果旋转前是
1088(W) x 2560(H),旋转 90 度后,理论上应该是 2560(W) x 1088(H)。
- 但你得到的旋转后是
1280(W) x 2176(H)。这说明脚本内部可能先对单目图像进行了旋转,然后再拼接,或者使用了不同的拼接逻辑。
2176 = 1088 * 2。这说明旋转后的单目图像高度是 1088,宽度是 1280。然后两个图像上下拼接成了 1280x2176。
黑边来源锁定:
在单目旋转阶段,每个 1088x1280 的图像旋转成 1280x1088 时,产生了微量黑边。当两个这样的图像上下拼接时,黑边被保留在了最终图像的顶部、底部和中间接缝处(如果左右有黑边,拼接后会在左侧或右侧)。
解决方法:
在 gen_gdc_bin_rotation 中,针对单目图像进行处理,而不是处理拼接后的图像。
- 修改 GDC 输入:确保传入 GDC 的是单个 Sensor 的数据。
- 精确设置 GDC 输出:
- Source:
1088 x 1280
- Rotate:
90 deg
- Destination:
1280 x 1088
- 如果 GDC 无法完美对齐:
在代码中,对每个通道的图像分别进行裁剪,然后再拼接。
# Python 端伪代码(如果在 ROS 节点后处理)
def process_dual_cam(img_left_raw, img_right_raw):
# 假设已经过 GDC 旋转,但存在黑边
# 左图: 1280x1088 + 黑边 -> 裁剪为纯 1280x1088
left_clean = crop_black_borders(img_left_raw)
right_clean = crop_black_borders(img_right_raw)
# 重新拼接
final_img = np.vstack((left_clean, right_clean)) # 如果是上下拼接
return final_img
3. 官方参数调整建议(无需改代码)
尝试在 Launch 文件中寻找是否有关于 ISP Crop 或 VPS Crop 的参数。
- 检查
mipi_cam.launch.py 或对应的 yaml 配置文件。
- 查找关键词:
roi, crop, offset_x, offset_y。
- 原理:如果在 ISP 阶段就裁剪掉 Sensor 输出的无效行/列(即那 1-3 个像素的黑边源头),那么送给 GDC 的就是纯净的 1088x1280 数据,GDC 旋转后自然就是纯净的 1280x1088。
操作建议:
查阅 SC132GS 的 Datasheet,确认其 Active Pixel 的确切起始坐标。如果 Datasheet 说明有效像素从 (3, 1) 开始,那么在 ISP 配置中设置 crop_x=3, crop_y=1, crop_w=1088, crop_h=1280(注意宽高对应关系)。
总结行动指南
-
首选方案(软件裁剪):鉴于黑边像素固定且微小(Top 1, Bottom 2, Left 3),在接收到图像后,直接使用 OpenCV 或 NumPy 进行固定坐标裁剪。这是最快、最不影响帧率的方法。
# 对于单目旋转后的图像 (假设原始 Buffer 包含黑边)
# 请根据实际打印的 img.shape 调整切片索引
img_clean = img[1:-2, 3:]
-
次选方案(ISP 配置):检查 mipi_cam 的配置文件,看是否能配置 ISP 的 ROI(Region of Interest),在源头切除黑边。
-
底层方案(GDC 修改):如果必须修改 C++ 代码,请在 gen_gdc_bin_rotation 中检查 hb_vgs_rotation_ex 或类似 GDC API 的调用参数,确保 dst_rect 严格匹配有效像素,并确认源地址指针是否偏移到了有效像素起始处。