2. 黑电平校正算法实现

任务目标

RAW图像传感器在无光照条件下仍会输出非零像素值,该偏移由暗电流引起,称为黑电平。本案例实现黑电平校正:从RAW图像中减去每个通道的黑电平值,并将结果重新映射到有效位深范围,以消除暗电流影响、提升动态范围。

实现方案

采用全局黑电平校正方法:对每个像素通道减去对应黑电平偏移量,负值截断为0,随后将数据线性拉伸至原始位深范围以恢复满量程动态范围。该方法适用于Bayer RAW或单通道RAW数据,无需额外依赖库,仅使用Python标准库与NumPy。

代码实现

import numpy as np

def black_level_correction(raw_img: np.ndarray, black_level: int, bit_depth: int = 12) -> np.ndarray:
    """
    对RAW图像执行黑电平校正。

    参数:
        raw_img: 输入RAW图像,uint16类型,形状为(H, W)或(H, W, C)
        black_level: 传感器黑电平偏移值(每个通道相同或已按通道给定)
        bit_depth: RAW图像位深,默认12bit

    返回:
        校正后的图像,uint16类型,像素范围[0, 2^bit_depth - 1]
    """
    # 确保输入为uint16
    raw = raw_img.astype(np.uint16)

    # 减去黑电平,负值截断为0
    corrected = raw.astype(np.int32) - black_level
    corrected = np.clip(corrected, 0, None).astype(np.uint16)

    # 线性拉伸至满量程,恢复动态范围
    max_val = (1 << bit_depth) - 1
    gain = max_val / (max_val - black_level)
    corrected = np.clip(corrected * gain, 0, max_val).astype(np.uint16)

    return corrected

if __name__ == "__main__":
    # 模拟12bit RAW数据:8x8单通道,含暗电流偏移
    np.random.seed(42)
    raw_data = np.random.randint(0, 4096, (8, 8), dtype=np.uint16)

    # 设定黑电平为512(12bit传感器典型值)
    bl = 512

    # 执行校正
    result = black_level_correction(raw_data, bl, bit_depth=12)

    # 验证:校正后最小像素值应接近0(原黑电平附近像素被压缩至低值)
    print("原始最小像素值:", raw_data.min())
    print("校正后最小像素值:", result.min())
    print("校正后最大像素值:", result.max())
    print("校正后像素均值:", result.mean())

运行方式

  1. 安装依赖:pip install numpy
  2. 将上述代码保存为 black_level_correction.py
  3. 运行:python black_level_correction.py

验证方法

程序输出校正前后的像素统计值。通过以下条件判定校正生效:

  • 校正后最小像素值应显著低于原始最小值,且接近0(因黑电平被减去)
  • 校正后最大像素值应接近4095(12bit满量程),表明动态范围被重新拉伸
  • 校正后均值较原始均值下降约black_level × gain的偏移量,但整体对比度保持

若需验证真实RAW文件,将raw_data替换为从RAW文件读取的numpy数组,并确保black_level与传感器规格一致即可。

关键说明

本实现假设黑电平为全局常量。若传感器各通道黑电平不同(如RGGB Bayer),需将black_level改为长度为通道数的数组,并按通道索引分别减去对应值。拉伸增益计算中,分母使用max_val - black_level,确保校正后满量程白点仍映射至最大值,避免高光细节丢失。