图像处理之去马赛克(附源码)
概念和背景
去马赛克(Demosaic/Debayer)是图像信号处理(ISP)中的关键步骤,旨在将拜耳阵列(Bayer Pattern)捕获的单通道灰度图像(每个像素仅含R、G或B中的一种颜色信息)转换为全彩色RGB图像。其本质是通过插值算法恢复缺失的两个颜色通道数据。
例如:
openAI 的 GPT 大模型的发展历程。
拜尔阵列原理
相机传感器表面覆盖滤色片阵列(CFA),最常见的排列是 RGGB拜耳阵列,当然还有BGGR拜耳阵列、GRBG拜耳阵列和GBRG拜耳阵列,共4种阵列。
由于每个像素仅记录 一个颜色分量(如红色像素点只感知红光强度),所以其他两个颜色分量需通过周围像素插值计算。
实现方式
1.插值法
实现方法有很多,比如最近邻插值算法,双线性插值算法,双三次插值算法等等,这里给大家简单说了一下常见的传统插值法
2.当然还可以用频域的方法:
小波变换:在频域分离高频(细节)和低频(颜色),分别处理。
傅里叶插值:利用频域稀疏性重建图像,较少用于实时系统。
3.机器学习方法
4. 混合方法
传统+深度学习:先用双线性插值生成粗结果,再用CNN优化细节(如某为P系列手机ISP)。
分频处理:低频用传统插值,高频用神经网络恢复。
源码
这里用Pyhon简单的复现一下去马赛克
import cv2
import numpy as np
def generate_bayer_image(color_img):
"""正确生成RGGB拜耳阵列"""
height, width = color_img.shape[:2]
bayer_img = np.zeros((height, width), dtype=np.uint8)
# 转换为RGB格式
rgb_img = cv2.cvtColor(color_img, cv2.COLOR_BGR2RGB)
# 正确填充RGGB
bayer_img[0::2, 0::2] = rgb_img[0::2, 0::2, 0] # R
bayer_img[0::2, 1::2] = rgb_img[0::2, 1::2, 1] # G
bayer_img[1::2, 0::2] = rgb_img[1::2, 0::2, 1] # G
bayer_img[1::2, 1::2] = rgb_img[1::2, 1::2, 2] # B
return bayer_img
def demosaic_bilinear(bayer_img):
"""改进的双线性插值"""
h, w = bayer_img.shape
R = np.zeros((h, w), np.float32)
G = np.zeros((h, w), np.float32)
B = np.zeros((h, w), np.float32)
# 分离通道(基于正确拜耳阵列)
R[0::2, 0::2] = bayer_img[0::2, 0::2]
G[0::2, 1::2] = bayer_img[0::2, 1::2]
G[1::2, 0::2] = bayer_img[1::2, 0::2]
B[1::2, 1::2] = bayer_img[1::2, 1::2]
# 各通道专用插值核
# 红色通道插值核(水平+垂直)
kernel_R = np.array([[0, 0.25, 0],
[0.25, 1, 0.25],
[0, 0.25, 0]], dtype=np.float32)
# 蓝色通道插值核(同R)
kernel_B = kernel_R.copy()
# 绿色通道插值核(对角线加权)
kernel_G = np.array([[0, 0.25, 0],
[0.25, 1, 0.25],
[0, 0.25, 0]], dtype=np.float32)
R = cv2.filter2D(R, -1, kernel_R)
G = cv2.filter2D(G, -1, kernel_G)
B = cv2.filter2D(B, -1, kernel_B)
# 合并为RGB并限制范围
rgb = np.clip(cv2.merge([R, G, B]), 0, 255).astype(np.uint8)
return cv2.cvtColor(rgb, cv2.COLOR_RGB2BGR) # 转换回BGR供OpenCV显示
if __name__ == "__main__":
img = cv2.imread('shou.jpg')
bayer = generate_bayer_image(img)
cv2.imwrite('bayer.png', bayer)
demosaiced = demosaic_bilinear(bayer)
cv2.imwrite('demosaiced.jpg', demosaiced)
cv2.imshow('Bayer', bayer)
cv2.imshow('Demosaiced', demosaiced)
cv2.waitKey(0)
小结
可以看见这个图片,左边是我自己拍的原图,中间的图片是生成的灰度图,右边的就是ISP去马赛克的图了,这里只要我们再把这个去马赛克的图再经过白平衡就可以还原到最左边的原图的样子了,只不过最后可能会有稍许偏差。
当然作者后面会提供Verilog代码实现的。