4. 坏点校正
任务目标
传感器因工艺缺陷或老化会产生坏点,表现为固定位置的亮点(热像素)或暗点(死像素)。本案例实现一个最小可用的坏点校正模块:检测单帧图像中的坏点,并用邻域中值替换,消除固定噪点。
核心原理
坏点检测基于邻域统计:若某像素灰度值显著高于或低于其周围8邻域的中值(超过阈值),则判定为坏点。校正时直接用该邻域中值替换坏点像素值。该算法对单帧有效,适合静态场景或首次校正。
完整实现
#include <stdint.h>
#include <string.h>
#define W 640
#define H 480
#define THRESHOLD 40 // 坏点判定阈值
// 8邻域中值查找(简单插入排序,仅9个元素)
static uint8_t median9(uint8_t v[9]) {
uint8_t t;
for (int i = 1; i < 9; i++) {
for (int j = i; j > 0 && v[j] < v[j-1]; j--) {
t = v[j]; v[j] = v[j-1]; v[j-1] = t;
}
}
return v[4];
}
// 坏点检测与校正(单帧,原地操作)
void bad_pixel_correction(uint8_t *frame) {
uint8_t *out = frame; // 原地处理
uint8_t neighbors[9];
for (int y = 1; y < H-1; y++) {
for (int x = 1; x < W-1; x++) {
int idx = y * W + x;
uint8_t center = frame[idx];
// 提取3x3邻域
neighbors[0] = frame[idx - W - 1];
neighbors[1] = frame[idx - W];
neighbors[2] = frame[idx - W + 1];
neighbors[3] = frame[idx - 1];
neighbors[4] = center;
neighbors[5] = frame[idx + 1];
neighbors[6] = frame[idx + W - 1];
neighbors[7] = frame[idx + W];
neighbors[8] = frame[idx + W + 1];
uint8_t med = median9(neighbors);
// 检测:中心点与中值差异超过阈值则判为坏点
int diff = center > med ? center - med : med - center;
if (diff > THRESHOLD) {
out[idx] = med; // 用中值替换
}
}
}
// 边界像素不处理(保持原样)
}
编译与运行
# 编译(需支持C99或以上)
gcc -O2 -o badpixel badpixel.c
# 运行(假设frame.bin为640x480的8位灰度原始数据)
./badpixel frame.bin corrected.bin
若需独立可执行文件,在main()中读取输入文件、调用bad_pixel_correction()并写出结果即可。上述代码为核心算法,可直接嵌入ISP流水线。
验证方法
- 构造测试图:生成一张640x480灰度图,背景为均匀灰度128,在坐标(100,100)、(320,240)处分别设置像素值为255(亮点)和0(暗点)。
- 运行校正:处理该测试图。
- 通过条件:校正后,原坏点位置像素值变为128(邻域中值),其余像素保持不变。可用以下命令检查:
# 用Python快速验证(需numpy)
python3 -c "
import numpy as np
img = np.full((480,640), 128, dtype=np.uint8)
img[100,100] = 255
img[320,240] = 0
img.tofile('test_in.bin')
# 运行校正程序后读取输出
out = np.fromfile('test_out.bin', dtype=np.uint8).reshape(480,640)
assert out[100,100] == 128 and out[320,240] == 128
assert np.all(out[0,:] == 128) # 边界未处理
print('PASS: 坏点已校正,正常像素未受影响')
"
参数说明
THRESHOLD:灵敏度调节。值越小检测越激进,但可能误伤纹理边缘;值越大漏检越多。典型范围20~60。- 边界像素(第0/479行、第0/639列)未处理,因缺少完整邻域。若需处理边界,可复制边缘像素或跳过。
- 本算法为单帧静态校正,不适用于运动场景的实时坏点追踪。若需动态校正,应结合多帧时域检测。