将cv :: Mat转换为无符号的int像素

时间:2017-08-23 18:53:23

标签: c++ opencv

我试图将cv :: Mat转换为无符号的int缓冲区图像,转换不起作用,我得到一个黑色图像

    Mat srcIm, edges;
    srcIm = imread("15016889798859437.jpg");
    cv::cvtColor(srcIm, srcIm, cv::COLOR_BGR2RGB);
    unsigned int *finalSrc = new unsigned int[srcIm.rows*srcIm.cols*3];

    unsigned char *input = (unsigned char*)(srcIm.data);

        for (int i = 0; i < srcIm.rows; i++) {
            for (int j = 0; j < srcIm.cols; j++) {
                 int r, g, b;
                r = input[srcIm.step * j + i];
                g = input[srcIm.step * j + i + 1];
                b = input[srcIm.step * j + i + 2];

                int rgb = ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff);

                finalSrc[i+ j*srcIm.rows] = rgb;
            }
        }

        cv::Mat videoFrame(srcIm.rows, srcIm.cols, CV_32SC1, finalSrc);

更新代码:

在评论之后,我已经解决了错误,但我仍然得到白色图像。

unsigned int *finalSrc = new unsigned int[srcIm.rows*srcIm.cols];

    unsigned char *input = (unsigned char*)(srcIm.data);

    int cn = srcIm.channels();

    for (int i = 0; i < srcIm.rows; i++)
    {
        for (int j = 0; j < srcIm.cols; j++)
        {
            int r, g, b;

            r = input[(i * srcIm.cols * srcIm.channels()) + (j*srcIm.channels()) + 0];
            g = input[(i * srcIm.cols * srcIm.channels()) + (j*srcIm.channels()) + 1];
            b = input[(i * srcIm.cols * srcIm.channels()) + (j*srcIm.channels()) + 2];

            int rgb = ((r & 0x0ff) << 16) | ((g & 0x0ff) << 8) | (b & 0x0ff);

        }
    }

    cv::Mat videoFrame(srcIm.rows, srcIm.cols, CV_32S, finalSrc);


    imshow("v", videoFrame);

1 个答案:

答案 0 :(得分:2)

恕我直言,有很多机会可以简化代码。

  1. 放弃cvtColor。无论如何,你正在遍历元素,所以只需在循环体中交换rb,就可以避免转换。

  2. finalSrc数组是所需大小的3倍。它是单个频道Mat,因此您只需要srcIm.rows * srcIm.cols元素。

  3. 不需要这么复杂的索引。 Mat s的形状相同,因此您可以迭代元素。

  4. 甚至不进行迭代,而是使用算法 - std::transform非常适合这种情况。

  5. 不要期望能够使用cv::imshow来显示结果。来自文档:

      

    如果图像是16位无符号或32位整数,则像素除以256.即,值范围[0,255 * 256]映射到[0,255]。

    您的值使用24位,因此绝大多数都会超过255*256,并且会饱和为白色。

  6. 注意:我正在使用“已键入”Mat s(例如cv::Mat3bcv::Mat1i)。那些“知道”包含的数据类型,这使得使用它们更简单。

    注意:我正在用一系列值填充输入图像。第一个像素将包含(B=0, G=1, R=2),第二个(B=3, G=4, R=5),依此类推。这样可以很容易地验证结果。

    代码:

    #include <opencv2/opencv.hpp>
    #include <numeric>
    
    int main()
    {
        // Generate a sample image.
        cv::Mat3b srcIm(4, 4);
        std::iota(srcIm.data, srcIm.data + srcIm.rows * srcIm.cols * 3, 0);
    
        cv::Mat1i videoFrame(srcIm.rows, srcIm.cols);
    
        // Perform the conversion
        std::transform(srcIm.begin(), srcIm.end(), videoFrame.begin()
            , [](cv::Vec3b const& v) {
                return v[0] | (v[1] << 8) | (v[2] << 16);
            });
    
        // Display results
        for (auto const& v : videoFrame) {
            std::cout << std::setw(6) << std::setfill('0') << std::hex << v << "\n";
        }
    
        return 0;
    }
    

    输出:

    020100
    050403
    080706
    0b0a09
    0e0d0c
    11100f
    141312
    171615
    1a1918
    1d1c1b
    201f1e
    232221
    262524
    292827
    2c2b2a
    2f2e2d
    

    你提到你想把结果作为一个数组。同样的原则也适用。

    std::unique_ptr<unsigned int[]> result(new unsigned int[srcIm.rows * srcIm.cols]);
    
    std::transform(srcIm.begin(), srcIm.end(), result.get()
        , [](cv::Vec3b const& v) {
            return v[0] | (v[1] << 8) | (v[2] << 16);
        });