4. 坏点校正
任务目标
传感器制造缺陷或老化会导致个别像素点输出异常(过亮、过暗或恒定值),即坏点(Dead Pixel)。本案例实现一个最小可复现的坏点校正模块:检测图像中的孤立坏点,并使用邻域中值滤波进行校正,同时保证正常像素不受影响。
核心思路
坏点检测基于邻域统计:若中心像素值与周围8邻域的中值偏差超过设定阈值,则判定为坏点。校正时直接用该邻域中值替换坏点值。该方案对稀疏坏点(占像素总数<0.1%)有效,适用于RAW域或灰度图像。
完整实现
import numpy as np
def dead_pixel_correction(image, threshold=40):
"""
坏点检测与校正(灰度图,单通道)
:param image: 2D numpy数组,uint8或uint16
:param threshold: 像素值与邻域中值的差超过该值则判为坏点
:return: 校正后图像, 坏点掩码(True表示坏点)
"""
img = image.astype(np.int32)
h, w = img.shape
padded = np.pad(img, 1, mode='reflect')
corrected = img.copy()
bad_mask = np.zeros((h, w), dtype=bool)
for i in range(h):
for j in range(w):
# 提取3x3邻域(含中心)
neighborhood = padded[i:i+3, j:j+3].flatten()
center_val = img[i, j]
median_val = np.median(neighborhood)
# 检测:中心与邻域中值差异过大
if abs(center_val - median_val) > threshold:
bad_mask[i, j] = True
# 校正:用排除中心后的邻域中值替换
neighbors = neighborhood[neighborhood != center_val]
corrected[i, j] = np.median(neighbors) if len(neighbors) > 0 else median_val
return corrected.astype(image.dtype), bad_mask
if __name__ == "__main__":
# 构造测试图:8x8灰度图,含3个坏点
test_img = np.array([
[50, 52, 48, 51, 49, 50, 53, 51],
[51, 200, 50, 49, 52, 48, 50, 52], # (1,1)亮点坏点
[49, 50, 51, 48, 50, 51, 49, 50],
[50, 48, 52, 51, 49, 50, 48, 51],
[52, 50, 49, 50, 0, 51, 52, 50], # (4,4)暗点坏点
[48, 51, 50, 52, 50, 49, 51, 48],
[50, 49, 51, 48, 52, 50, 49, 52],
[51, 50, 48, 51, 49, 52, 50, 255] # (7,7)亮点坏点
], dtype=np.uint8)
corrected_img, mask = dead_pixel_correction(test_img, threshold=40)
print("检测到坏点坐标:", np.argwhere(mask).tolist())
print("校正后坏点位置像素值:", corrected_img[mask])
print("校正后完整图像:\n", corrected_img)
运行与验证
运行方式:直接执行脚本(需安装NumPy):
pip install numpy
python dead_pixel_correction.py
预期输出:检测到3个坏点,坐标分别为(1,1)、(4,4)、(7,7)。校正后这三个位置的像素值应接近周围邻域正常水平(约50±3),而非原始异常值(200、0、255)。
通过判定标准:
- 坏点掩码准确识别全部3个注入坏点,且无误检(正常像素未被标记);
- 校正后坏点处像素值落入邻域正常范围(48~53),图像整体无明显异常突变;
- 正常像素值保持不变(校正前后完全一致)。
关键说明
- 阈值
threshold需根据传感器噪声水平调整:暗光下噪声增大时适当提高阈值(如60~80),防止将噪声误判为坏点。 - 本实现针对稀疏孤立坏点设计。若存在坏点簇(2×2以上连续坏点),需扩大邻域范围(如5×5)或改用线性插值,但会显著增加计算量。
- 实际ISP流水线中,坏点校正通常在RAW域(Bayer格式)进行,需按通道分别处理,并配合坏点表(静态坏点坐标预存)以降低逐帧检测开销。本案例演示动态检测逻辑,可直接迁移至Bayer各通道。