• Bayer转换算法


    一 Bayer图像格式分类

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

    二 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();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

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

  • 相关阅读:
    基于Springboot的校园疫情管理系统
    4-10构造器
    Mysql-体系结构
    Babylonjs PointerEventTypes.POINTERMOVE 获取不到模型信息
    Windows下的RabbitMQ安装教程(遇到很多无语的问题,已解决)
    分布式 | 如何与 DBLE 进行“秘密通话”
    Liunx 进程通信
    XCTF1-web Robots
    3.5 This关键字
    高并发笔记
  • 原文地址:https://blog.csdn.net/zhoukehu_CSDN/article/details/126482534