【圖像處理】圖像灰度化


寫在前面的話

老式黑白電視只有一個通道的圖像數據,通過灰度值在黑白電視上顯示灰度圖像,即圖像的亮度,是Y通道數據。

后來出現了彩色電視,為了兼容老式黑白電視,使用YCrCb(YUV)方式傳輸圖像。

如下分析一下彩色圖像轉成灰度圖的方法和原理。

 

彩色圖和灰度圖說明

彩色圖像可以有4個通道,的BGR-[A](Blue Green Red Alpha)藍,綠,紅和透明4個通道。

也可以是BGR(Blue Green Red)藍,綠,紅3個通道三通道。

BGR的數據存儲格式如下所示:

 

 灰度圖是單通道圖像,數據存儲格式如下所示:

 

轉化分析

在opencv中可以使用API將彩色圖像轉成灰度圖。

將彩色圖像轉成灰度圖的方式有如下兩種方式

方式一:

RGB  YCrCb JPEG (or YCC)

Y = 0.299R+0.587G+0.114B

Cr = (RY)0.713+delta

Cb = (BY)0.564+delta

 

方式二:

RGB ↔ CIE

 Y = 0.212671R+0.715160G+0.072169B

 

 

opencv默認將RGB圖像轉成Gray的方式是

RGB  GRAY

RGB[A] to Gray: Y = 0.299R+0.587G+0.114B

 

效果如下:

 

 

使用opencv的API進行灰度化處理代碼

    void toGray(cv::Mat& inImage, cv::Mat& outGrayImage) {
        cv::cvtColor(inImage, outGrayImage, cv::COLOR_RGB2GRAY);

        cv::imshow("raw-image", inImage);
        cv::imshow("gray-image", outGrayImage);
    }

遍歷圖像矩陣,使用CIE方式將BGR轉Gray的公式計算如下:

    void toGrayImpl(cv::Mat &inImage, cv::Mat &outGrayImage) {
        outGrayImage = cv::Mat::zeros(inImage.rows, inImage.cols, CV_8UC1);
        for (int i = 0; i < inImage.rows; ++i) {
            unsigned char *ptSrcRow = inImage.ptr<uchar>(i);
            unsigned char *ptDstRow = outGrayImage.ptr<uchar>(i);
            for (int j = 0; j < inImage.cols; ++j) {
                int pos = j * inImage.channels();
                // Y = B * 0.072169f + G * 0.715160f + R * 0.212671f;
                ptDstRow[j] = cv::saturate_cast<uchar>(0.212671f * (float) ptSrcRow[pos + 2] +
                                                       0.71516f * (float) ptSrcRow[pos + 1] +
                                                       0.072169f * (float) ptSrcRow[pos]);
            }
        }

        cv::imshow("raw-image", inImage);
        cv::imshow("gray-image", outGrayImage);
    }

 通過YCrCb方式轉成灰度圖:

    void toGrayImplByYCrCb(cv::Mat &inImage, cv::Mat &outGrayImage) {
        outGrayImage = cv::Mat::zeros(inImage.rows, inImage.cols, CV_8UC1);
        for (int i = 0; i < inImage.rows; ++i) {
            for (int j = 0; j < inImage.cols; ++j) {
                // BGR -> Gray
                // Y = B * 0.114 + G * 0.587 + R * 0.299;
                outGrayImage.at<uchar>(i, j) = 0.299 * (float) inImage.at<cv::Vec3b>(i, j)[2]
                                               + 0.587 * (float) inImage.at<cv::Vec3b>(i, j)[1]
                                               + 0.114 * (float) inImage.at<cv::Vec3b>(i, j)[0];
            }
        }

        cv::imshow("raw-image", inImage);
        cv::imshow("gray-image-YCrCb", outGrayImage);
    }

另外一種方式,直接使用opencv的API將BGR圖像轉成YCrCb格式,提取Y通道的數據imageList[0]

    void toGrayByYCrCbSplit(cv::Mat &inImage, cv::Mat &outGrayImage) {
        cv::cvtColor(inImage, outGrayImage, cv::COLOR_BGR2YCrCb);
        std::vector<cv::Mat> imageList;
        cv::split(outGrayImage, imageList);

        cv::imshow("raw-image", inImage);
        cv::imshow("gray-image-Y", imageList[0]);
        cv::imshow("gray-image-Cr", imageList[1]);
        cv::imshow("gray-image-Cb", imageList[2]);
    }

將彩色圖轉成YCrCb,如下是Y通道的灰度圖,Cr是R通道和Y的差值,Cb是B通道和Y的差值。

  

參考文檔:

https://docs.opencv.org/3.3.1/de/d25/imgproc_color_conversions.html#color_convert_rgb_gray


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM