【问题标题】:Color to grayscale conversion彩色到灰度转换
【发布时间】:2019-10-10 00:28:42
【问题描述】:

我使用 C++ openCV 程序进行第一原理 HDL(Verilog)图像对象检测的算法开发。我终于设法让 HDL 版本达到精明检测的程度。为了验证这两者,两者都需要具有相同的输出。我发现它们的细微差别是由 openCV imread 颜色到灰度转换偏向绿色造成的。在 openCV C++ 方法中,平滑后的图像整体更亮。从 rgb2gray 方法来看,openCV 使用了一个偏差,即 (RX+GY+B*Z)/3 而在 HDL 中我一直使用 (R+G+B)/3 作为我要求它完成 Gaussian、Sobel 和 Canny 滤波器。人类可视化是次要的,乘以非整数是不可取的。

是否有用于转换的标准线性灰度转换或覆盖现有方法的方法? ...

int main()
{
            int thold = 15;

            clock_t start;
            double duration;
            const int sobelX[3][3] = { {-1, 0, 1}, {-2, 0, 2}, {-1, 0, 1} };  //Where origionally floats in python
            const int sobelY[3][3] = { {-1, -2, -1}, {0, 0, 0}, {1, 2, 1} }; //Where origionally floats in python
            const int kernel[5][5] = { {1,6,12,6,1},
                                                                                                {6,42,79,42,6},
                                                                                                                        {12,79,148,79,12},
                                                                                                                        {6,42,79,42,6},
                                                                                                                        {1,6,12,6,1} };// 1/732
            // Above normalised kernal for smoothing,  see origional python script for method 
            start = std::clock();
            int height, width, intPixel, tSx, tSy, tS, dirE, dirEE, maxDir, curPoint, contDirection, cannyImgPix, nd, tl, tm, tr, mr, br, bm, bl, ml = 0;
            int contNum = 128;
            int contPixCount = 0;
            int curContNum = 0;
            int contPlace = 0;
            int oldContPlace = 0;
            int g = 0;
            bool maxPoint;
            struct pixel {
                        int number;
                        int h;
                        int w;

            };
            std::vector<pixel> contourList;
            //double floatPixel = 0.0;
            int kernalCumulator = 0;
            const int mp = 3;
        //  Scalar color(0, 0, 255);
            //          duration = ((clock()) - start) / (double)CLOCKS_PER_SEC;
            //          start = clock();
            //          cout << "Start image in" << duration << '\n';
            //          Mat dst;
            Mat rawImg = imread("C:\\Users\\&&&\\Documents\\pycode\\paddedGS.png",0);
            printf("%d",rawImg.type());

//          Mat rawImg = imread("C:\\Users\\&&&\\Documents\\openCV_Master\\openCVexample\\openCVexample\\brace200.jpg ", 0);
            height = rawImg.rows;
            width = rawImg.cols;
            cout << "Height of image " << height << '\n';
            cout << "Width of image " << width << '\n';
            Mat filteredImg = Mat::zeros(height, width, CV_8U);
            printf("%d", filteredImg.type());
            Mat sobelImg = Mat::zeros(height, width, CV_8U);
            Mat directionImg = Mat::zeros(height, width, CV_8U);
            Mat cannyImg = Mat::zeros(height, width, CV_8U);
            Mat contourImg = Mat::zeros(height, width, CV_16U);

//          rawImg.convertTo(rawImg, CV_8UC1);

            duration = ((clock()) - start) / (double)CLOCKS_PER_SEC;
            start = clock();
            cout << "Start image in" << duration << '\n';
            // Loop to threshold already grayscaled image           
            /*
            for (int h = 0; h < (height); h++)
            {
                        for (int w = 0; w < (width); w++)
                        {
                                    g = (int)rawImg.at<uchar>(h, w,0);
                                    cout << g << "g";
                                    g+= (int)rawImg.at<uchar>(h, w, 1);
                                    cout << g << "g";
                                    g+= (int)rawImg.at<uchar>(h, w, 2);
                                    cout << g << "g";
                                    g = g/3;
                                    rawGImg.at<uchar>(h,w) = g;
                        }
            }

            */
            //          imshow("thresholded Image", rawImg);
            //          waitKey();
            // Loop to smooth using Gausian 5 x 5 kernal

//          imshow("raw Image", rawImg);


            for (int h = 3; h < (height - 3); h++)
            {
                        for (int w = 3; w < (width - 3); w++)
                        {
                                    if (rawImg.at<uchar>(h, w) >=6 )//Thresholding included
                                    {
                                                for (int xk = 0; xk < 5; xk++)
                                                {
                                                            for (int yk = 0; yk < 5; yk++)
                                                            {
                                                                        intPixel = rawImg.at<uchar>((h + (xk - mp)), (w + (yk - mp)));
                                                                        kernalCumulator += intPixel*(kernel[xk][yk]);//Mutiplier required as rounding is making number go above 255,  better solution?
                                                            }
                                                }
                                    }
                                    else
                                                kernalCumulator = 0;

                                    kernalCumulator = kernalCumulator / 732;
                                    if (kernalCumulator < 0 || kernalCumulator > 255)
                                    {
        //                                      cout << "kernal Value: " << kernalCumulator;
            //                                  cout << " intPixel:" << intPixel << '\n';
                                    }
                                    filteredImg.at<uchar>(h, w) = (uchar)kernalCumulator;
                                    kernalCumulator = 0;
                        }
            }

【问题讨论】:

标签: c++ opencv grayscale hdl


【解决方案1】:

我们的视觉不会线性感知亮度,因此对于通常的应用程序来说,使用某种试图模仿人类感知的转换是有意义的。

对于您的应用程序,您有 2 个选项:在 HDL 中使用类似的转换(这可能并不容易或不理想),或者为 OpenCV 自定义 rgb 到灰度,使用您使用的相同转换。

一个简短的 sn-p(更像是伪代码,你必须弄清楚细节)是这样的:

cv::Mat linearRgbToGray(const cv::Mat &color) {
    cv::Mat gray(color.size(), CV_8UC1);
    for (int i = 0; i < color.rows; i++)
        for (int j = 0; j < color.cols; j++)
           gray.at(i, j) = (color.at(i, j)[0] + color.at(i, j)[1] + color.at(i, j)[2]) / 3;
}

【讨论】:

  • 嗨,保罗,感谢您的快速回复。结果证明您的伪代码非常接近实际有效的 C++ 代码。见下文。不是特别精通 C++ 我曾尝试过类似的方法来访问每个 RGB 元素 at. 越界并认为这是我如何处理单个通道而不是类型的问题,或者我返回了 1/4出于某种原因的图像
【解决方案2】:

根据上面 Paul92 的建议

cv::Mat linearRgbToGray(const cv::Mat &color) {
            cv::Mat gray(color.size(), CV_8UC1);
            for (int i = 0; i < color.rows; i++)
                        for (int j = 0; j < color.cols; j++)
                                    gray.at<uchar>(i, j) = ((color.at<cv::Vec3b>(i, j)[0] + color.at<cv::Vec3b>(i, j)[1] + color.at<cv::Vec3b>(i, j)[2]) / 3);
            return gray;
}

上面的代码有效并且克服了我之前遇到的越界错误。谢谢你,罗伯。

【讨论】:

    猜你喜欢
    • 2011-12-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-01-11
    • 2015-10-07
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多