三种Bayer数据的插值算法(CCD插值算法)

最近实习的公司要求提供几个用于插值的函数接口,用于对CCD直接提供的拜尔数据进行插值成为彩色图像,并封装为dll。具体的实现代码应公司规定无法带出或上传,在此总结一下实现几种算法的思路并简略描述其效果。

三种Bayer数据的插值算法(CCD插值算法)

首先从相机CCD的硬件结构先说明一下需要插值的原因,因为CCD上的每一个点只能接受的是光强度的信息,所以CCD的每一个像素点上覆盖了一片滤光片,使得每个像素点只能对一种颜色感光。所以CCD初始获得的信息都是如上图所示,这种每个像素只有一个通道的Bayer数据,而我们看到的彩色图像都是经过插值得到的。以每个2*2的方阵为一个单位,由于人眼对绿光比较敏感,所以有两个绿色像素,一个红色像素和一个蓝色像素。由于CCD开始取值的点(即位于(1,1)点的像素取的有颜色和位置)存在差异,因此需要提供RGGB(a),BGGR(b),GBRG(c),GRBG(d)四种格式的接口。

对于市场上的产品,这类插值算法一般在相机自身的硬件平台内完成,但开发和测试的时候我们经常能拿到数据的拜尔图。这次要写这个接口也是因为原本硬件平台的插值算法存在一定问题,导致了密集线对的显示存在拉链效应和伪彩。

(如下图,图片来自 https://blog.csdn.net/QCC_navigate/article/details/78430925)

三种Bayer数据的插值算法(CCD插值算法)

1.邻近插值

(1) 绿色分量重建

整个平面内一般一半的点是有像素的,而且全都间隔排列。对没有像素存在的点,全部取其左边位置的绿色像素强度。

三种Bayer数据的插值算法(CCD插值算法)

(2) 红色和蓝色分量重建

对每一个红色和蓝色的像素,将右边、下面、右下角的值都赋值为它的值。

三种Bayer数据的插值算法(CCD插值算法)

该方法在实际处理中,对竖直的密集线对表现比较好,只有少量噪点;而水平的密集线对基本呈现密集的点状图案,无法看出线条,类似于前面说的伪彩色现象。

2.基于边界梯度的插值

(1) 绿色分量重建

首先恢复红色和蓝色采样点处的绿色分量,即图a和图b中心采样点处的绿色分量,图b绿色分量重建过程与图a相似,故以图a为例。中心红色采样点R(i,j)处水平方向和垂直方向检测算子计算如下: 

三种Bayer数据的插值算法(CCD插值算法)

当水平算子小于垂直算子时,中心点R(i,j)存在水平边缘的概率较大,中心绿色分量的计算沿水平方向进行,公式如下 :

三种Bayer数据的插值算法(CCD插值算法)

当水平算子大于垂直算子时,中心点R(i,j)存在垂直边缘的概率较大,中心绿色分量的计算沿垂直方向进行,公式如下 : 

三种Bayer数据的插值算法(CCD插值算法)

倘若水平和垂直的算子相等,则中心点处的绿色分量的计算为水平和垂直方向的平均值,公式如下: 

三种Bayer数据的插值算法(CCD插值算法)

(2) 绿色采样点处的红色和蓝色分量重建

图d的蓝色和红色分量的重建过程与图c相似,故以图c为例。中心点处的蓝色分量的重建使用左右两点的B-G空间的线性插值,红色分量的重建使用上下两点的R-G空间的线性插值,具体如下:

三种Bayer数据的插值算法(CCD插值算法)

(3) 红色(蓝色)采样点处的蓝色(红色)分量的重建

最后对红、蓝处的蓝、红像素分别进行重建。根据图像,每个红色像素被四个角上的蓝色像素包围,蓝色像素也是相同。因此只需要对四个角上取平均值即可。红色像素点的重建方式如下,蓝色也类似:

三种Bayer数据的插值算法(CCD插值算法)

该方法对水平和竖直的密集线对展现都比较良好,除了有少量噪点,线对和背景的对比度不够高。

3.汉密尔顿插值

在Bayer CFA中,由于绿色像素点的数量是红色和蓝色像素数量的两倍,故其包含更多的原始图像的边缘信息。因此,亚当斯和汉密尔顿根据该思想在1997年提出了一种边缘自适应的插值算法。

其具体实现方法如下:

(网上的许多文章和硕士毕业论文中的一些系数和顺序存在一定的问题,经过实践后采用了博文https://www.cnblogs.com/qiqibaby/p/8719252.html的方法,比较准确。

(1) 绿色分量重建

首先恢复红色和蓝色采样点处的绿色分量,即图a和图b中心采样点处的绿色分量,图b绿色分量重建过程与图a相似,故以图a为例。中心红色采样点R(i,j)处水平方向和垂直方向检测算子计算如下: 

三种Bayer数据的插值算法(CCD插值算法)

当水平算子小于垂直算子时,中心点R(i,j)存在水平边缘的概率较大,中心绿色分量的计算沿水平方向进行,公式如下 :

三种Bayer数据的插值算法(CCD插值算法)

当水平算子大于垂直算子时,中心点R(i,j)存在垂直边缘的概率较大,中心绿色分量的计算沿垂直方向进行,公式如下 : 

三种Bayer数据的插值算法(CCD插值算法)

倘若水平和垂直的算子相等,则中心点处的绿色分量的计算为水平和垂直方向的平均值,公式如下: 

三种Bayer数据的插值算法(CCD插值算法)

(2) 绿色采样点处的红色和蓝色分量重建

图d的蓝色和红色分量的重建过程与图c相似,故以图c为例。中心点处的蓝色分量的重建使用左右两点的B-G空间的线性插值,红色分量的重建使用上下两点的R-G空间的线性插值,具体如下:

三种Bayer数据的插值算法(CCD插值算法)

(3) 红色(蓝色)采样点处的蓝色(红色)分量的重建 
最后进行图a中心点蓝色的恢复和和图b中心点红色的恢复,由于图b的重建过程与图a相似,故以图a为例。观察R周围最近的蓝色像素点,处于R像素点左上,左下、右上、右下四个位置。为了更好的选择插值方向,保存边缘信息,与绿色分量的恢复类似,需要首先沿两个斜四十五度方向计算像素的梯度,再沿梯度较小的方向插值。

左下右上和左上右下的梯度计算如下:

三种Bayer数据的插值算法(CCD插值算法)

根据梯度的比较结果,选择合适的插值防线,计算如下: 

三种Bayer数据的插值算法(CCD插值算法)

其中第2、3步的顺序可调换。

这种方法的时间复杂度不高,而且能够提供比较好的插值效果。对于非常亮的白光区域,采用上面两种方法会有个别的某种纯色255强度的点,而该方法的插值对亮色的表现比较平滑。对于密集线对,无论横竖方向都不会出现颗粒状的问题,线条比较完整,且与背景对比度高。

4.需要注意的小问题

在cpp中用uchar类型访问和计算每一个点的强度时,通过方法2、3计算的结果会发生上溢或下溢(大于255或小于0),此时uchar类型的计算会直接将下溢的值从255开始往下减,因此会导致暗场景和很亮的场景中的区域出现彩色亮点或暗点。解决方法比较多,取(i+255)%255的值也可,先将其赋值为一个float变量然后将其调整到0~255内也可。

另外在访问数据时尽量直接用uchar类型的指针,这样访问速度最快。用iplimage其次,计算速度约为1-60ms,2-330ms。用Mat的数据格式访问最慢,甚至需要几秒钟。但理论上Mat应该更快,可能是数据转换消耗了时间,在此做下记录。

还有,纯的Bayer数据可能是8位、12位、14位的,对于后两种情况,每个数据存放在一个16bit的单元中,访问时要用short类型指针进行访问。而且要用一定算法从12/14位映射到8位,我用的方法是直接右移4位,网上有用log的更准确的方法,此处不做赘述。

关于Bayer数据的插值算法有很多的文章与研究,在工业界较为成熟的应用还是汉密尔顿插值法。在设计程序时要考虑到具体的平台与需求,挑选合适的算法进行处理。