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流水线。

验证方法

  1. 构造测试图:生成一张640x480灰度图,背景为均匀灰度128,在坐标(100,100)、(320,240)处分别设置像素值为255(亮点)和0(暗点)。
  2. 运行校正:处理该测试图。
  3. 通过条件:校正后,原坏点位置像素值变为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列)未处理,因缺少完整邻域。若需处理边界,可复制边缘像素或跳过。
  • 本算法为单帧静态校正,不适用于运动场景的实时坏点追踪。若需动态校正,应结合多帧时域检测。