What is ratio of color channel is taken for RGB to gray scale conversion by OpenCV?

Hi!
I am testing gray scale conversion of RGB using OpenCV. The documentation says OpenCV combines RGB in ratio of {0.299,0.587,0.114} respectively. I have tried that in a custom loop and combined the channels in mentioned ratio to form a gray image. For comparison with OpenCV inbuilt function cv::cvtColor() and my loop generated gray image I took Sum of absolute error between them and found a difference with very large value (approx. 1 lakh for a 480p image). May i know what is exact ratio been used by OpenCV.
Thank you.

I ensure i put ratio as BGR and not RGB. I am attaching my code.

#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <iostream>
#include <chrono>
#include <filesystem>

int main(){
    std::filesystem::path inpath = "../test/synthetic/colored480/";            // Input path
    // std::string otpath = "../test/output/CPP/480/";

    for (const auto & entry : std::filesystem::directory_iterator(inpath)){
        std::cout<<"file: "<<entry.path()<<std::endl;                          
        cv::Mat input = cv::imread(entry.path());                              // Reading image from path

        cv::Mat Gray1 = cv::Mat::zeros(input.rows, input.cols, CV_8UC1);       // for inbuilt function result
        cv::Mat Gray2 = cv::Mat::zeros(input.rows, input.cols, CV_8UC1);       // for custom loop result

        cv::cvtColor(input, Gray1, cv::COLOR_BGR2GRAY);                        // gray image using inbuilt function
        
        // color convertion to gray without using function
        for (int i = 0; i < input.rows; i++) {                           // loop through all pixels rowwise and column wise
            for (int j = 0; j < input.cols; j++) {
                Gray2.at<uchar>(i, j) =   int(0.114*input.at<cv::Vec3b>(i, j)[0]  // B
                                        + 0.587*input.at<cv::Vec3b>(i, j)[1]      // G
                                        + 0.299*input.at<cv::Vec3b>(i, j)[2]);    // R
            }
        }

        cv::Mat diff = cv::Mat::zeros(input.rows, input.cols, CV_8UC1);    // difference image
        cv::absdiff(Gray1, Gray2, diff);                                   // absolute difference between inbuilt and custom gray image
        // sum all the absolute difference
        double sum = cv::sum(diff)[0];  

        std::cout<<"sum: "<<sum<<std::endl;

    }
    return 0;
}

remember you’re speaking to an international audience. nobody here knows what a “lakh” is, except those of us who deal with indians regularly, and even we may feign ignorance

100e3 / (640*480) = 0.1 so you’re talking about differences of a fraction of a single count per pixel. that is imperceptible.

you might want to investigate rounding modes. or dig into OpenCV source to find the specific coefficients.

you should also visually compare (look at) your Gray1 and Gray2 pictures, or the diff Mat. see any single differences that are perceptible? that is just to make sure there is no integer overflow/wraparound happening.

1 Like

1 lakh = 100,000
Next time I will keep that in mind.

I have solved this problem!
I found there is a round() operation after computing the grayscale value.

// color convertion to gray without using function
        for (int i = 0; i < input.rows; i++) {                           // loop through all pixels rowwise and column wise
            for (int j = 0; j < input.cols; j++) {
                Gray2.at<uchar>(i, j) =   round(0.114*input.at<cv::Vec3b>(i, j)[0]      // B
                                              + 0.587*input.at<cv::Vec3b>(i, j)[1]      // G
                                              + 0.299*input.at<cv::Vec3b>(i, j)[2]);    // R
            }
        }