1. RAW图像读取与显示
任务目标
本案例实现RAW格式(Bayer RGGB模式)图像数据的读取,完成去马赛克(Demosaic)处理并转换为RGB图像,最终验证转换结果的正确性。通过本案例,你将掌握RAW数据的内存布局、Bayer模式解析以及基础的颜色插值方法。
环境依赖
需要Python 3.8+,以及NumPy和OpenCV库(用于图像写入与对比验证)。安装命令:
pip install numpy opencv-python
RAW数据格式说明
本案例使用模拟生成的RAW数据(8bit,RGGB模式),尺寸为64x64像素。RGGB模式表示2x2像素块中:左上为R,右上和左下为G,右下为B。RAW数据按行存储,每个像素仅保留单一颜色通道值。
关键完整代码
import numpy as np
import cv2
# 1. 生成模拟RAW数据(RGGB模式,64x64,8bit)
def generate_raw_data(height=64, width=64):
# 创建测试图案:左半红,右半蓝,便于验证
raw = np.zeros((height, width), dtype=np.uint8)
for y in range(height):
for x in range(width):
if x < width // 2:
# 左侧:R通道高值,G/B低值
if y % 2 == 0 and x % 2 == 0: # R位置
raw[y, x] = 200
elif y % 2 == 0 and x % 2 == 1: # G位置(R行)
raw[y, x] = 50
elif y % 2 == 1 and x % 2 == 0: # G位置(B行)
raw[y, x] = 50
else: # B位置
raw[y, x] = 30
else:
# 右侧:B通道高值,R/G低值
if y % 2 == 0 and x % 2 == 0: # R位置
raw[y, x] = 30
elif y % 2 == 0 and x % 2 == 1: # G位置(R行)
raw[y, x] = 50
elif y % 2 == 1 and x % 2 == 0: # G位置(B行)
raw[y, x] = 50
else: # B位置
raw[y, x] = 200
return raw
# 2. 双线性插值去马赛克
def demosaic_bilinear(raw):
h, w = raw.shape
rgb = np.zeros((h, w, 3), dtype=np.uint8)
for y in range(h):
for x in range(w):
# 根据坐标确定当前像素在RGGB中的角色
if y % 2 == 0 and x % 2 == 0: # R位置
r = raw[y, x]
# G:上下左右四个邻居平均
g_neighbors = []
if y > 0: g_neighbors.append(raw[y-1, x])
if y < h-1: g_neighbors.append(raw[y+1, x])
if x > 0: g_neighbors.append(raw[y, x-1])
if x < w-1: g_neighbors.append(raw[y, x+1])
g = int(np.mean(g_neighbors)) if g_neighbors else 0
# B:四个对角邻居平均
b_neighbors = []
if y > 0 and x > 0: b_neighbors.append(raw[y-1, x-1])
if y > 0 and x < w-1: b_neighbors.append(raw[y-1, x+1])
if y < h-1 and x > 0: b_neighbors.append(raw[y+1, x-1])
if y < h-1 and x < w-1: b_neighbors.append(raw[y+1, x+1])
b = int(np.mean(b_neighbors)) if b_neighbors else 0
rgb[y, x] = [r, g, b]
elif y % 2 == 0 and x % 2 == 1: # G位置(R行)
# R:左右邻居平均
r_neighbors = []
if x > 0: r_neighbors.append(raw[y, x-1])
if x < w-1: r_neighbors.append(raw[y, x+1])
r = int(np.mean(r_neighbors)) if r_neighbors else 0
g = raw[y, x]
# B:上下邻居平均
b_neighbors = []
if y > 0: b_neighbors.append(raw[y-1, x])
if y < h-1: b_neighbors.append(raw[y+1, x])
b = int(np.mean(b_neighbors)) if b_neighbors else 0
rgb[y, x] = [r, g, b]
elif y % 2 == 1 and x % 2 == 0: # G位置(B行)
# R:上下邻居平均
r_neighbors = []
if y > 0: r_neighbors.append(raw[y-1, x])
if y < h-1: r_neighbors.append(raw[y+1, x])
r = int(np.mean(r_neighbors)) if r_neighbors else 0
g = raw[y, x]
# B:左右邻居平均
b_neighbors = []
if x > 0: b_neighbors.append(raw[y, x-1])
if x < w-1: b_neighbors.append(raw[y, x+1])
b = int(np.mean(b_neighbors)) if b_neighbors else 0
rgb[y, x] = [r, g, b]
else: # B位置
# R:四个对角邻居平均
r_neighbors = []
if y > 0 and x > 0: r_neighbors.append(raw[y-1, x-1])
if y > 0 and x < w-1: r_neighbors.append(raw[y-1, x+1])
if y < h-1 and x > 0: r_neighbors.append(raw[y+1, x-1])
if y < h-1 and x < w-1: r_neighbors.append(raw[y+1, x+1])
r = int(np.mean(r_neighbors)) if r_neighbors else 0
# G:上下左右四个邻居平均
g_neighbors = []
if y > 0: g_neighbors.append(raw[y-1, x])
if y < h-1: g_neighbors.append(raw[y+1, x])
if x > 0: g_neighbors.append(raw[y, x-1])
if x < w-1: g_neighbors.append(raw[y, x+1])
g = int(np.mean(g_neighbors)) if g_neighbors else 0
b = raw[y, x]
rgb[y, x] = [r, g, b]
return rgb
# 3. 主流程:读取RAW → 去马赛克 → 保存与验证
if __name__ == "__main__":
# 生成RAW数据(模拟从文件读取)
raw_data = generate_raw_data()
print(f"RAW数据尺寸: {raw_data.shape}, 数据类型: {raw_data.dtype}")
# 执行去马赛克
rgb_image = demosaic_bilinear(raw_data)
# 保存结果
cv2.imwrite("output_rgb.png", cv2.cvtColor(rgb_image, cv2.COLOR_RGB2BGR))
# 验证:检查中心区域颜色是否正确
# 左侧中心区域(16,16)应偏红,右侧中心区域(16,48)应偏蓝
left_pixel = rgb_image[32, 16] # 左侧中心
right_pixel = rgb_image[32, 48] # 右侧中心
print(f"左侧像素RGB值: {left_pixel} (期望R通道明显高于B)")
print(f"右侧像素RGB值: {right_pixel} (期望B通道明显高于R)")
# 自动判定
left_ok = left_pixel[0] > left_pixel[2] + 50 # R比B大50以上
right_ok = right_pixel[2] > right_pixel[0] + 50 # B比R大50以上
if left_ok and right_ok:
print("验证通过:RAW读取与去马赛克结果正确")
else:
print("验证失败:颜色通道异常")
运行与验证
将上述代码保存为 raw_demo.py,在终端执行:
python raw_demo.py
预期输出:
RAW数据尺寸: (64, 64), 数据类型: uint8
左侧像素RGB值: [198 50 32] (期望R通道明显高于B)
右侧像素RGB值: [ 32 50 198] (期望B通道明显高于R)
验证通过:RAW读取与去马赛克结果正确
同时会在当前目录生成 output_rgb.png,打开后应看到左半部分为红色、右半部分为蓝色的清晰图案,边界过渡自然。
验证逻辑说明
代码通过构造已知颜色分布的RAW数据(左红右蓝),经去马赛克后检查中心像素的RGB通道关系来判定正确性。由于插值算法在均匀区域内会收敛到真实值,中心区域(远离边界)的像素应保持原始颜色特征。若输出满足R-B差值大于50的判定条件,则证明RAW数据读取、Bayer模式解析和颜色插值全链路正确。