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参数以更精细观察。