Bayer转换算法

一 Bayer图像格式分类

Bayer图像根据实际探测器不同颜色分量的排列方式可以分为4种格式:RGGB、GRBG、BGGR、GBRG,分别对应OpenCV里的BayerBG、BayerGB、BayerRG、BayerGR格式。如下图所示:
Bayer转换算法_第1张图片

二 Bayer图像转换算法

常用的Bayer转换算法是对图像的每个像素位置取其3×3邻域内的相同分量对当前位置缺少的分量进行估计,从而得到3通道的彩色图像。以BayerBG格式的图像为例,在Bayer图像中,所有的像素位置其插值方式可分为4种,分别为:偶数行偶数列、偶数行奇数列、奇数行偶数列、奇数行奇数列(按C++的风格,这里行列的起始均为0)。
例如,
1)对于偶数行偶数列(row=2,col=2),当前Bayer图像该位置为B分量,其R分量可以由Bayer图像3×3邻域的4个R分量取均值进行估计,G分量可以由Bayer图像3×3邻域的4个G分量取均值进行估计。
2)对于偶数行奇数列(row=2,col=3),当前Bayer图像该位置为G分量,其R分量可以由Bayer图像3×3邻域的2个R分量取均值进行估计,B分量可以由Bayer图像3×3邻域的2个B分量取均值进行估计。
3)对于奇数行偶数列(row=3,col=2),当前Bayer图像该位置为G分量,其R分量可以由Bayer图像3×3邻域的2个R分量取均值进行估计,B分量可以由Bayer图像3×3邻域的2个B分量取均值进行估计。
4)对于奇数行奇数列(row=3,col=2),当前Bayer图像该位置为R分量,其G分量可以由Bayer图像3×3邻域的4个G分量取均值进行估计,B分量可以由Bayer图像3×3邻域的4个B分量取均值进行估计。

三 Bayer转换示例代码

针对BayerBG格式转RGB图像的代码如下:

/**
 * @brief BayerBG2RGB,BayerBG格式图像转为RGB图像
 * @param src,输入图像,CV_8UC1格式Bayer图像
 * @param dst,输出图像,CV_8UC3格式彩色图像
 */
void BayerBG2RGB(const cv::Mat& src,cv::Mat& dst)
{
    //BG格式的Bayer图像排列如下
    /*
     * B G B G B G B
     * G R G R G R G
     * B G B G B G B
     * G R G R G R G
     * B G B G B G B
     * G R G R G R G
     * B G B G B G B
    */

    //按3×3的邻域处理,边缘需填充至少1个像素的宽度
    int nBorder = 1;
    cv::Mat bayer;
    cv::copyMakeBorder(src,bayer,nBorder,nBorder,nBorder,nBorder,cv::BORDER_REPLICATE);

    cv::Mat rgb(bayer.size(),CV_8UC3);
    rgb.setTo(cv::Scalar(0,0,0));
    uchar* pBayer = (uchar*)bayer.ptr();
    uchar* pRGB = (uchar*)rgb.ptr();
    int nW = bayer.cols;
    int nH = bayer.rows;

    //注意:OpenCV中约定用Mat存储3通道彩色图像时,第0通道为B分量,第1通道表示G分量,第2通道表示R分量
    //在从cv::cvtColor函数的注释中有如下解释:
    /* Note that the default color format in OpenCV is often referred to as RGB but it is actually BGR (the
     * bytes are reversed). So the first byte in a standard (24-bit) color image will be an 8-bit Blue
     * component, the second byte will be Green, and the third byte will be Red.
    */

    for(int i=nBorder; i<nH-nBorder; i++)
    {
        for(int j=nBorder; j<nW-nBorder; j++)
        {
            //3×3邻域像素定义
            /*
             * |M00 M01 M02|
             * |M10 M11 M12|
             * |M20 M21 M22|
            */
            int nM00 = (i-1)*nW+(j-1); int nM01 = (i-1)*nW+(j+0);  int nM02 = (i-1)*nW+(j+1);
            int nM10 = (i-0)*nW+(j-1); int nM11 = (i-0)*nW+(j+0);  int nM12 = (i-0)*nW+(j+1);
            int nM20 = (i+1)*nW+(j-1); int nM21 = (i+1)*nW+(j+0);  int nM22 = (i+1)*nW+(j+1);

            if(i%2 == 0)
            {
                if(j%2 == 0)     //偶数行偶数列
                {
                    pRGB[i*nW*3+j*3+0]=pBayer[nM11];//b
                    pRGB[i*nW*3+j*3+2]=((pBayer[nM00]+ pBayer[nM02]+pBayer[nM20]+pBayer[nM22])>>2);//r
                    pRGB[i*nW*3+j*3+1]=((pBayer[nM01]+ pBayer[nM10]+pBayer[nM12]+pBayer[nM21])>>2);//g
                }
                else             //偶数行奇数列
                {
                    pRGB[i*nW*3+j*3+1]=pBayer[nM11];//g
                    pRGB[i*nW*3+j*3+2]=(pBayer[nM01]+pBayer[nM21])>>1;//r
                    pRGB[i*nW*3+j*3+0]=(pBayer[nM10]+pBayer[nM12])>>1;//b
                }
            }
            else
            {
                if(j%2 == 0)     //奇数行偶数列
                {
                    pRGB[i*nW*3+j*3+1]=pBayer[nM11];//g
                    pRGB[i*nW*3+j*3+2]=(pBayer[nM10]+pBayer[nM12])>>1;//r
                    pRGB[i*nW*3+j*3+0]=(pBayer[nM01]+pBayer[nM21])>>1;//b
                }
                else             //奇数行奇数列
                {
                    pRGB[i*nW*3+j*3+2]=pBayer[nM11];//r
                    pRGB[i*nW*3+j*3+1]=(pBayer[nM01]+pBayer[nM21]+pBayer[nM10]+pBayer[nM12])>>2;//g
                    pRGB[i*nW*3+j*3+0]=(pBayer[nM00]+pBayer[nM02]+pBayer[nM20]+pBayer[nM22])>>2;//b
                }
            }
        }
    }

    dst = rgb(cv::Rect(nBorder,nBorder,src.cols,src.rows)).clone();
}

作者将其结果与OpenCV的cvtColor函数的处理结果进行了比较,视觉上没有发现明显差异。但是,在边缘处理上,cvtColor函数的效果更好,暂未明确其内部处理机制。

你可能感兴趣的:(科研,学习,算法,opencv,计算机视觉)