简体   繁体   English

OpenCV将3个通道连接为32位值?

[英]OpenCV concatenate 3 channels to 32-bit value?

I am looking for the fastest way of converting 3 channels RGB frame to 1 channel picture in openCV. 我正在寻找在openCV中将3通道RGB帧转换为1通道图片的最快方法。 But I need to concatenate all three colors (R, G, B) of the pixel into one 32-bit value. 但是我需要将像素的所有三种颜色(R,G,B)连接为一个32位值。

Every pixel should consist for an example: 每个像素都应包含一个示例:

pixel[0:31]= 01001001 11110000 11111111 00000000 像素[0:31] = 01001001 11110000 11111111 00000000

The first 8 bits are RED color from the frame (at the same position in frame), second 8 bits are from green color and third 8 bits are from blue, last 8 bits are not important. 前8位是帧中的红色(在帧中的同一位置),后8位是绿色的,后8位是蓝色的,后8位并不重要。

I tried this: 我尝试了这个:

for (y = 100; y < 500; y++){
     for (x = 100; x < 500; x++) {
        int pixel =((edges.at<Vec3b>(y, x)[0])<<16)|
                    ((edges.at<Vec3b>(y, x)[1])<<8)|
                    (edges.at<Vec3b>(y, x)[2]);
}}

But this is to slow, because I need to go through every pixel in the frame. 但这很慢,因为我需要遍历帧中的每个像素。

Thanks 谢谢

Use the split and merge channels functions. 使用拆分合并通道功能。

The look complicated but are a lot easier than doing it a pixel at a time. 外观复杂,但要比做一个像素在同一时间轻松了许多。

See stackoverflow.com/questions/14582082/merging-channels-in-opencv for sample 见样品stackoverflow.com/questions/14582082/merging-channels-in-opencv

Tried some variants: 尝试了一些变体:

  • Method 0a : as in the question, @Sveva 方法0a :如问题@Sveva
  • Method 0b : as in the question, with for loops inverted, @Miki 方法0b :如问题所示,for循环反转,@Miki
  • Method 1 : querying value from mat only once using indices, @Miki 方法1 :使用索引@Miki仅从mat查询一次值
  • Method 2 : querying value from mat using pointers, @Miki 方法2 :使用@Miki指针从Mat查询值
  • Method 3 : converting to BGRA and memcpy , @RyanP NOTE: works only if mat isContinuos() . 方法3 :转换为BGRA和memcpy ,@ RyanP注意:仅当mat isContinuos()

Results (time in milliseconds) 结果 (以毫秒为单位)

isContinuos? 1
Method 0a: 113.704              0x1020300
Method 0b: 20.0975              0x1020300
Method 1: 20.1939               0x1020300
Method 2: 15.7434               0x1020300
Method 3: 22.5592               0xff030201

Considerations 注意事项

Inverting the for loops has a major speedup, because OpenCV Mat are row-major ordered. 反转for循环的速度大大提高,因为OpenCV Mat行进行了大排序。 The fastest method is Method 2, using pointers. 最快的方法是使用指针的方法2。 Method 1 is slightly slower, but probably more readable. 方法1稍慢一些,但可能更具可读性。 Method 3 is quite fast, but a single memcpy works only if the matrix isContinuos() . 方法3相当快,但是只有当矩阵为isContinuos() ,单个memcpy才有效。 If not the case, you need to loop on each row, and memcpy each row, and this is going to be (only a little) slower. 如果不是这种情况,则需要在每一行上循环,并在每一行进行memcpy ,这将(仅稍微慢一些)。

NOTE 注意

OpenCV stores BGR values (not RGB). OpenCV存储BGR值(不是RGB)。 Methods 0a, 0b, 1 and 2 output the values as: BGR 0 . 方法0a,0b,1和2的输出值为: BGR 0 You just need to swap the index 0 and 2 to get RGB 0 . 您只需要交换索引0和2即可获得RGB 0 For Method 3, you need to use cvtColor with parameter COLOR_BGR2RGBA . 对于方法3,您需要将cvtColor与参数COLOR_BGR2RGBA一起使用。

Code

#include <opencv2\opencv.hpp>
#include <vector>
#include <iostream>
using namespace std;
using namespace cv;

int main()
{
    // Test Image
    Mat3b img(2000, 3000, Vec3b(1, 2, 3));
    cout << "isContinuos? " << img.isContinuous() << endl;

    // Method 0a: method from question. Credits to @Sveto
    double tic0a = double(getTickCount());
    vector<int> v0a(img.rows * img.cols, 0);
    for (int c = 0; c < img.cols; ++c)
    {
        for (int r = 0; r < img.rows; ++r)
        {
            v0a[r*img.cols + c] = ((img.at<Vec3b>(r, c)[0]) << 24) |
                ((img.at<Vec3b>(r, c)[1]) << 16) |
                (img.at<Vec3b>(r, c)[2]) << 8;
        }
    }
    double toc0a = (double(getTickCount()) - tic0a) * 1000. / getTickFrequency();
    cout << "Method 0a: " << toc0a << "\t\t";;
    cout << "0x" << hex << v0a[0] << endl;

    // Method 0b: method from question, loops inverted
    double tic0b = double(getTickCount());
    vector<int> v0b(img.rows * img.cols, 0);
    for (int r = 0; r < img.rows; ++r)
    {
        for (int c = 0; c < img.cols; ++c)
        {
            v0b[r*img.cols + c] = ((img.at<Vec3b>(r, c)[0]) << 24) |
                ((img.at<Vec3b>(r, c)[1]) << 16) |
                (img.at<Vec3b>(r, c)[2]) << 8;
        }
    }
    double toc0b = (double(getTickCount()) - tic0b) * 1000. / getTickFrequency();
    cout << "Method 0b: " << toc0b << "\t\t";
    cout << "0x" << hex << v0b[0] << endl;


    // Method 1: custom loop with indices
    double tic1 = double(getTickCount());
    vector<int> v1(img.rows * img.cols, 0);
    for (int r = 0; r < img.rows; ++r)
    {
        for (int c = 0; c < img.cols; ++c)
        {
            const Vec3b& b = img(r, c);
            v1[r*img.cols + c] = (b[0] << 24) | (b[1] << 16) | (b[2] << 8);
        }
    }
    double toc1 = (double(getTickCount()) - tic1) * 1000. / getTickFrequency();
    cout << "Method 1: " << toc1 << "\t\t";
    cout << "0x" << hex << v1[0] << endl;

    // Method 2: custom loop with pointers
    double tic2 = double(getTickCount());
    vector<int> v2(img.rows * img.cols, 0);
    for (int r = 0; r < img.rows; ++r)
    {
        uchar* p = img.ptr<uchar>(r);
        for (int c = 0; c < img.cols; ++c)
        {
            int val = ((*p) << 24); ++p;
            val |= ((*p) << 16); ++p;
            val |= ((*p) << 8); ++p;
            v2[r*img.cols + c] = val;
        }
    }
    double toc2 = (double(getTickCount()) - tic2) * 1000. / getTickFrequency();
    cout << "Method 2: " << toc2 << "\t\t";
    cout << "0x" << hex << v2[0] << endl;


    // Method 3: using BGRA conversion. Credits @RyanP
    // NOTE: works only if img.isContinuos()
    double tic3 = double(getTickCount());
    Mat4b rgba3;
    cvtColor(img, rgba3, COLOR_BGR2BGRA);
    vector<int> v3(img.rows * img.cols, 0);
    memcpy(v3.data(), rgba3.data, img.rows * img.cols * sizeof(int));

    double toc3 = (double(getTickCount()) - tic3) * 1000. / getTickFrequency();
    cout << "Method 3: " << toc3 << "\t\t";
    cout << "0x" << hex << v3[0] << endl;

    int dummy;
    cin >> dummy;

    return 0;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM