2. 解析RAW图像并显示统计信息

任务目标

读取RAW图像文件,解析Bayer格式数据,输出图像尺寸、位深、黑电平、白电平及直方图统计信息,为后续ISP调优提供输入图像的基础数据参考。

环境依赖

本案例使用Python实现,依赖numpy用于数值计算,rawpy用于RAW文件解析。安装命令:

pip install numpy rawpy

实现代码

import rawpy
import numpy as np

def parse_raw_and_stats(raw_path):
    """
    解析RAW文件,输出尺寸、位深、黑电平、白电平及直方图统计。
    """
    # 1. 打开RAW文件
    raw = rawpy.imread(raw_path)
    
    # 2. 获取Bayer原始数据(不插值)
    bayer = raw.raw_image  # 形状 (height, width),dtype 为 uint16 或 uint8
    
    # 3. 图像尺寸与位深
    height, width = bayer.shape
    bit_depth = raw.raw_pattern  # 仅用于确认模式,实际位深从raw_image dtype获取
    # 更准确的位深:rawpy 中 raw_image 的 dtype 决定位深
    if bayer.dtype == np.uint16:
        bits = 16
    elif bayer.dtype == np.uint8:
        bits = 8
    else:
        bits = int(np.ceil(np.log2(np.iinfo(bayer.dtype).max + 1)))
    
    # 4. 黑电平与白电平(rawpy 提供)
    black_level = raw.black_level_per_channel  # 每个通道的黑电平
    white_level = raw.white_level  # 白电平(标量)
    
    # 5. 直方图统计(基于Bayer原始数据)
    hist, bin_edges = np.histogram(bayer, bins=256, range=(0, white_level))
    
    # 6. 输出信息
    print(f"图像尺寸: {width} x {height}")
    print(f"位深: {bits} bit")
    print(f"黑电平 (每通道): {black_level}")
    print(f"白电平: {white_level}")
    print(f"直方图 (256 bins, 范围 0~{white_level}):")
    for i in range(0, 256, 16):  # 每16个bin打印一行,避免输出过长
        bin_start = int(bin_edges[i])
        bin_end = int(bin_edges[i+1])
        count = int(hist[i])
        print(f"  bin[{bin_start:5d}~{bin_end:5d}): {count}")
    
    raw.close()
    return {
        "width": width,
        "height": height,
        "bit_depth": bits,
        "black_level": black_level,
        "white_level": white_level,
        "histogram": hist
    }

if __name__ == "__main__":
    import sys
    if len(sys.argv) != 2:
        print("用法: python raw_stats.py <RAW文件路径>")
        sys.exit(1)
    stats = parse_raw_and_stats(sys.argv[1])
    # 可在此处对stats做进一步处理

运行方式

python raw_stats.py sample.dng

将sample.dng替换为实际RAW文件路径。支持rawpy可解析的格式(如DNG、CR2、NEF等)。

验证方法

运行后观察输出:

  • 图像尺寸:应与RAW文件的实际像素尺寸一致(可用其他工具如exiftool核对)。
  • 位深:常见为12bit或14bit,rawpy会将数据提升到uint16存储,因此输出通常为16bit——这是rawpy的存储行为,实际传感器位深需从RAW元数据获取。若需精确传感器位深,可读取raw.camera_white_level和raw.black_level_per_channel推算,或使用rawpy的raw.color_desc等属性。
  • 黑电平/白电平:数值范围合理(如黑电平约64~2048,白电平约1023~16383,视传感器而定)。
  • 直方图:打印的256个bin中,像素计数总和应等于width * height,且分布应集中在黑电平与白电平之间,无大量像素超出白电平(若超出说明白电平设置可能偏低)。

可通过以下代码快速验证像素总数:

total_pixels = sum(hist)
assert total_pixels == width * height, f"直方图像素总数 {total_pixels} 不等于图像像素数 {width*height}"

常见问题

  • rawpy无法打开文件:确认文件格式受支持且未损坏;部分厂商RAW需安装对应解码库。
  • 黑电平为数组:black_level_per_channel返回每个颜色通道的黑电平,若需全局值可取其最小值或平均值,具体取决于ISP处理需求。
  • 直方图bin范围:当前代码将范围固定为0~white_level,若图像暗部集中,可调整range参数以更精细观察。