色彩转换系列之RGB图转灰度图原理及实现

写在前面
彩色图转灰度图在图像处理中应用非常非常广泛,而且很多算法只对灰度图有效,所以彩色图转灰度是十分重要和关键的。

RGB(红绿蓝)是依据人眼识别的颜色定义出的空间,可表示大部分颜色。但在科学研究一般不采用RGB颜色空间,因为它的细节难以进行数字化的调整。它将色调,亮度,饱和度三个量放在一起表示,很难分开。它是最通用的面向硬件的彩色模型。该模型用于彩色监视器和一大类彩色视频摄像。

    RGB颜色空间 基于颜色的加法混色原理,从黑色不断叠加Red,Green,Blue的颜色,最终可以得到白色光,如图:

                                                  

将R、G、B三个通道作为笛卡尔坐标系中的X、Y、Z轴,就得到了一种对于颜色的空间描述,如图:

                                                                   

                  

RGB转灰度图 
对于彩色转灰度,有一个很著名的心理学公式:

                                                Gray = R*0.299 + G*0.587 + B*0.114

直接计算因为是浮点型计算,所以复杂度较高,速度较低。所以我们考虑优化,可以将小数转为整数,除法变为移位,乘法也变为移位(整数计算比浮点型快,移位运算和加减法比乘除法快),但是这种方法也会带来一定的精度损失,我们可以根据实际情况选择需要保留的精度位数。下面给出不同精度(2-20位)的计算公式:

Grey = (R*1 + G*2 + B*1) >> 2
 
Grey= (R*2 + G*5 + B*1) >> 3
 
Grey= (R*4 + G*10 + B*2) >> 4
 
Grey = (R*9 + G*19 + B*4) >> 5
 
Grey = (R*19 + G*37 + B*8) >> 6
 
Grey= (R*38 + G*75 + B*15) >> 7
 
Grey= (R*76 + G*150 + B*30) >> 8
 
Grey = (R*153 + G*300 + B*59) >> 9
 
Grey = (R*306 + G*601 + B*117) >> 10
 
Grey = (R*612 + G*1202 + B*234) >> 11
 
Grey = (R*1224 + G*2405 + B*467) >> 12
 
Grey= (R*2449 + G*4809 + B*934) >> 13
 
Grey= (R*4898 + G*9618 + B*1868) >> 14
 
Grey = (R*9797 + G*19235 + B*3736) >> 15
 
Grey = (R*19595 + G*38469 + B*7472) >> 16
 
Grey = (R*39190 + G*76939 + B*14943) >> 17
 
Grey = (R*78381 + G*153878 + B*29885) >> 18
 
Grey =(R*156762 + G*307757 + B*59769) >> 19
 
Grey= (R*313524 + G*615514 + B*119538) >> 20

 
实现:
#include <iostream>
#include <opencv2/core.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
 
cv::Mat RGB2GRAY(cv::Mat src, bool accelerate=false){
    CV_Assert(src.channels()==3);
    cv::Mat dst = cv::Mat::zeros(src.size(), CV_8UC1);
    cv::Vec3b rgb;
    int r = src.rows;
    int c = src.cols;
    
      for (int i = 0; i < r; ++i){
         for (int j = 0; j < c; ++j){
            rgb = src.at<cv::Vec3b>(i, j);
            uchar B = rgb[0]; uchar G = rgb[1]; uchar R = rgb[2];
            if (accelerate = false){
                dst.at<uchar>(i, j) = R*0.299 + G*0.587 + B*0.114;   //原式
            }
            else{
                dst.at<uchar>(i, j) = (R * 4898 + G * 9618 + B * 1868) >> 14;  //优化
            }
         }
       }
    return dst;
}
 
int main(){
    cv::Mat src = cv::imread("I:\\Learning-and-Practice\\2019Change\\Image process algorithm\\Img\\lena.jpg");
 
    if (src.empty()){
        return -1;
    }
    cv::Mat dst,dst1;
 
    //opencv自带
    double t2 = (double)cv::getTickCount(); //测时间
    cv::cvtColor(src, dst1, CV_RGB2GRAY);
    t2 = (double)cv::getTickCount() - t2;
    double time2 = (t2 *1000.) / ((double)cv::getTickFrequency());
    std::cout << "Opencv_rgb2gray=" << time2 << " ms. " << std::endl << std::endl;
 
    //RGB2GRAY
    double t1 = (double)cv::getTickCount(); //测时间
    dst = RGB2GRAY(src, true);
    t1 = (double)cv::getTickCount() - t1;
    double time1 = (t1 *1000.) / ((double)cv::getTickFrequency());
    std::cout << "My_rgb2gray=" << time1 << " ms. " << std::endl << std::endl;
 
 
    cv::namedWindow("src", CV_WINDOW_NORMAL);
    imshow("src", src);
    cv::namedWindow("My_rgb2gray", CV_WINDOW_NORMAL);
    imshow("My_rgb2gray", dst);
    cv::namedWindow("Opencv_rgb2gray", CV_WINDOW_NORMAL);
    imshow("Opencv_rgb2gray", dst1);
    cv::waitKey(0);
    return 0;
 
}

效果

参考:

https://blog.csdn.net/just_sort/article/details/87102898

https://blog.csdn.net/xdrt81y/article/details/8289963
————————————————

                            版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
                        
原文链接:https://blog.csdn.net/weixin_40647819/article/details/92596879

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值