博客硬件技术征程6 ISP调优与图像数据回灌:让相机在不同光照下都能稳定出图

征程6 ISP调优与图像数据回灌:让相机在不同光照下都能稳定出图

默认265282026-08-30
39
0

做视觉感知的项目,ISP(Image Signal Processor)的调教质量直接决定了后续AI模型的输入质量。征程6内置了ISP硬件pipeline,支持AE(自动曝光)、AWB(自动白平衡)、LSC(镜头阴影校正)、NR(降噪)等一系列处理。这篇记录我在一个AGV项目上对征程6 ISP做调优的过程,以及图像数据回灌(image data replay)的使用经验。

一、征程6 ISP Pipeline概览

征程6的ISP硬件pipeline大概长这样:

```

Raw Sensor Data

BLC (Black Level Correction)

LSC (Lens Shading Correction)

AE/AWB统计

Demosaic (去马赛克)

CCM (Color Correction Matrix)

Gamma校正

NR (Noise Reduction)

Sharpen

Output (YUV/RGB)

```

ISP调优的核心思路是:根据场景特点(室内/室外/夜间/逆光等),调整各模块的参数,让输出图像的亮度、对比度、色彩还原度符合后续AI模型的需求。

二、ISP参数配置

ISP参数通过设备树(device tree)和运行时API两种方式配置。静态参数在device tree里配,动态参数在运行时通过V4L2 ioctl调。

静态参数(Device Tree)

```

// arch/arm64/boot/dts/horizon/j6.dts

&isp {

// 分辨率

width = ;

height = ;

// 输出格式

output-format = "NV12"; // 或者"RGB"

// BLC参数

black-level = ; // 12bit raw,black level=64

// LSC参数(镜头阴影校正)

lsc-enable = ;

lsc-table = ; // 镜头标定数据

// AE参数

ae-mode = "auto"; // auto/manual/histogram

ae-target-brightness = ; // 目标亮度,8bit范围0-255

// AWB参数

awb-mode = "auto"; // auto/manual

awb-gain-r = ;

awb-gain-g = ;

awb-gain-b = ;

// Gamma

gamma-enable = ;

gamma-table = ;

// NR

nr-enable = ;

nr-strength = ; // 0-100

// Sharpen

sharpen-enable = ;

sharpen-strength = ;

};

```

运行时参数(V4L2)

```cpp

#include

int fd = open("/dev/video0", O_RDWR);

// 设置曝光时间

struct v4l2_control ctrl;

ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;

ctrl.value = 10000; // 曝光时间,单位微秒

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

// 设置增益

ctrl.id = V4L2_CID_GAIN;

ctrl.value = 100; // ISO增益

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

// 设置AWB模式

ctrl.id = V4L2_CID_AUTO_WHITE_BALANCE;

ctrl.value = 1; // 1=auto, 0=manual

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

```

三、ISP调优实战

场景1:室内 fluorescent 灯光

室内 fluorescent 灯有频闪问题(50Hz/60Hz),如果曝光时间和频闪周期不匹配,画面会有明暗条纹。

解决: 把曝光时间设成频闪周期的整数倍。

```cpp

// 50Hz市电,周期=20ms

// 曝光时间 = 20ms / N(N=1,2,3...)

// 比如 N=2,曝光时间=10ms=10000us

ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;

ctrl.value = 10000;

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

```

场景2:夜间低光照

夜间图像信噪比低,ISP的NR模块要开强一些,但 sharpening 要减弱,否则噪声会被放大。

```cpp

// 夜间参数

ctrl.id = V4L2_CID_NOISE_REDUCTION;

ctrl.value = 80; // NR强度加强

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

ctrl.id = V4L2_CID_SHARPNESS;

ctrl.value = 10; // Sharpen减弱

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

```

注意:

NR强度太高会导致图像模糊,细节丢失,可能影响小目标的检测精度。建议夜间场景把小目标的检测阈值适当降低,补偿图像模糊带来的影响。

场景3:逆光(背光)

逆光场景下前景很暗,背景很亮,AE如果按全局亮度测光,前景会过暗。

解决: 用局部测光或者手动设置曝光。

```cpp

// 手动曝光,根据前景亮度调整

ctrl.id = V4L2_CID_EXPOSURE_AUTO;

ctrl.value = V4L2_EXPOSURE_MANUAL;

ioctrl(fd, VIDIOC_S_CTRL, &ctrl);

ctrl.id = V4L2_CID_EXPOSURE_ABSOLUTE;

ctrl.value = 50000; // 手动增加曝光时间,让前景亮起来

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

```

代价是背景会过曝,但对于检测前景目标(行人、车辆)的应用来说,前景清晰更重要。

场景4:白天高动态范围(HDR)

白天同时有阳光直射区域和阴影区域,普通ISP处理不了这么大的亮度差异。

征程6支持硬件HDR,但需要在sensor端就开启HDR模式:

```cpp

// 开启HDR(sensor端)

ctrl.id = V4L2_CID_HDR_MODE;

ctrl.value = 1; // 1=HDR on, 0=off

ioctl(fd, VIDIOC_S_CTRL, &ctrl);

```

HDR模式会输出更宽的动态范围,但帧率可能会降低(因为需要多帧合成)。我项目里开了HDR后帧率从30fps降到了20fps,但画面质量提升明显,阴影里的目标也能看清了。

四、图像数据回灌(Image Data Replay)

图像数据回灌是调试ISP和感知pipeline的神器。它的原理是把之前采集的raw图像数据(从sensor出来的原始数据)保存下来,然后重复灌入ISP和BPU,方便复现问题和对比不同ISP参数的效果。

回灌数据的采集

```bash

# 从V4L2采集raw数据

v4l2-ctl --device=/dev/video0 \

--set-fmt-video=width=1920,height=1080,pixelformat=RG12 \

--stream-mmap \

--stream-count=100 \

--stream-to=./raw_data.raw

```

pixelformat=RG12表示12bit raw数据。采集100帧保存到raw_data.raw。

回灌数据的播放

```bash

# 把raw数据回灌到ISP

v4l2-ctl --device=/dev/video0 \

--set-fmt-video=width=1920,height=1080,pixelformat=RG12 \

--stream-mmap \

--stream-from=./raw_data.raw \

--stream-count=100

```

回灌过程中可以实时调整ISP参数,看不同参数下的输出效果。

在代码里做回灌

```cpp

#include

#include

// 打开回灌文件

int raw_fd = open("./raw_data.raw", O_RDONLY);

void* raw_data = mmap(NULL, file_size, PROT_READ, MAP_PRIVATE, raw_fd, 0);

// 设置ISP为回灌模式

struct v4l2_format fmt;

fmt.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;

fmt.fmt.pix.width = 1920;

fmt.fmt.pix.height = 1080;

fmt.fmt.pix.pixelformat = v4l2_fourcc('R', 'G', '1', '2');

ioctl(isp_fd, VIDIOC_S_FMT, &fmt);

// 发送回灌数据到ISP

struct v4l2_buffer buf;

buf.type = V4L2_BUF_TYPE_VIDEO_OUTPUT;

buf.index = 0;

buf.bytesused = 1920 * 1080 * 2; // 12bit = 2 bytes per pixel (packed)

buf.m.userptr = (unsigned long)raw_data;

ioctl(isp_fd, VIDIOC_QBUF, &buf);

// 启动回灌

ioctl(isp_fd, VIDIOC_STREAMON, &buf.type);

// ISP处理完成后,从capture端读取处理后的图像

struct v4l2_buffer cap_buf;

cap_buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;

ioctl(isp_fd, VIDIOC_DQBUF, &cap_buf);

// cap_buf里的数据就是ISP处理后的图像

```

回灌调试工作流

我的工作流:

1. 采集问题场景的raw数据:在出现问题的场景下采集几秒的raw数据

2. 保存不同ISP参数的YAML配置:记录下当时的ISP参数

3. 回灌raw数据,调整ISP参数:在实验室里反复回灌,调整参数看效果

4. 对比不同参数的输出:把不同参数下的输出图像保存下来,肉眼对比

5. 找到最优参数后更新设备树:把最优参数固化到device tree里

一个小技巧:

采集raw数据的时候,同时采集ISP输出的YUV/RGB图像和BPU的推理结果。这样回灌的时候不仅能调ISP,还能验证ISP调优后对BPU推理精度的影响。

五、ISP调优对AI模型精度的影响

ISP调优不只是让画面"好看",更重要的是让画面"对AI友好"。

案例:

我项目里NR强度从50调到80后,画面干净了,但小目标的检测精度从72%掉到了65%。原因是NR把目标的边缘细节也抹掉了,小目标本来就只有几个像素,再一抹就融进背景里了。

ISP-AI联合调优策略:

1. 先固定AI模型,调ISP参数,看不同参数下的检测精度

2. 找到ISP参数的"sweet spot":精度最高的参数组合

3. 如果ISP调到头了精度还不够,再考虑调整AI模型(比如增加小目标检测头的分辨率)

```python

# ISP-AI联合调优脚本

isp_params = {

'nr_strength': [30, 50, 70, 90],

'sharpen_strength': [10, 30, 50, 70],

'gamma': [0.8, 1.0, 1.2],

}

best_map = 0

best_params = {}

for nr in isp_params['nr_strength']:

for sharpen in isp_params['sharpen_strength']:

for gamma in isp_params['gamma']:

# 设置ISP参数

set_isp_params(nr=nr, sharpen=sharpen, gamma=gamma)

# 回灌数据

replay_raw_data()

# 跑BPU推理

results = run_inference()

# 计算mAP

mAP = compute_map(results, ground_truth)

if mAP > best_map:

best_map = mAP

best_params = {'nr': nr, 'sharpen': sharpen, 'gamma': gamma}

print(f"Best mAP: {best_map}, params: {best_params}")

```

六、注意事项总结

1. ISP调优要和AI模型联合优化:不要只追求画面好看,要追求对AI检测友好。

2. 频闪问题通过曝光时间解决:50Hz用10ms/20ms曝光,60Hz用8.33ms/16.67ms。

3. 夜间NR和sharpen要平衡:NR太高丢细节,sharpen太高放大噪声。

4. 逆光用局部测光或手动曝光:前景清晰比背景不过曝更重要。

5. HDR提升动态范围但降帧率:根据应用需求权衡。

6. 回灌是调试神器:采集问题场景的raw数据,实验室里反复调参。

7. 回灌时同步采集BPU结果:验证ISP调优对AI精度的影响。

8. ISP参数要分场景配置:白天/夜晚/室内/室外各一套参数,根据环境光自动切换。

9. 12bit raw比8bit YUV信息量大:采集raw数据而不是压缩后的YUV,保留更多信息。

10. 设备树参数修改后重启生效:运行时参数通过V4L2 ioctl动态调整。

硬件技术
社区征文征程6
评论0
0/600