OpenCV将3个通道连接到32位值
OpenCV concatenate 3 channels to 32-bit value?
我正在寻找在openCV中将3通道RGB帧转换为1通道图像的最快方法。但是我需要将像素的所有三种颜色(R, G, B)连接成一个32位值。
每个像素应该包含一个例子:
pixel[0:31]= 01001001 11110000 11111111 00000000
前8位是来自帧的红色(在帧中的相同位置),第二个8位是绿色,第三个8位是蓝色,最后8位不重要。
我试过了:
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]);
}}
但是这是慢的,因为我需要遍历帧中的每个像素。
谢谢
尝试了一些变体:
- 方法0a:如问题中所示,@Sveva
- 方法0b:与问题中一样,使用颠倒的for循环,@Miki
- 方法1:只使用索引查询一次mat的值,@Miki
- 方法2:使用指针从mat中查询值,@Miki
-
方法3:转换为BGRA和
memcpy
, @RyanP注意:仅当matisContinuos()
时有效。
结果(时间单位:毫秒)
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
考虑
反转for循环有很大的加速,因为OpenCV Mat
是行主要排序的。最快的方法是使用指针的方法2。方法1稍微慢一些,但可能更具可读性。方法3相当快,但是单个memcpy
仅在矩阵isContinuos()
时才有效。如果不是这种情况,您需要对每一行进行循环,并对每一行执行memcpy
,这将会(只是一点点)慢。
注意
OpenCV存储BGR值(不是RGB)。方法0a、0b、1、2输出值为:B G R 0
。你只需要交换索引0和2来得到R G B 0
。对于方法3,您需要使用cvtColor
和参数COLOR_BGR2RGBA
。
#include <opencv2opencv.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 << "tt";;
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 << "tt";
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 << "tt";
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 << "tt";
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 << "tt";
cout << "0x" << hex << v3[0] << endl;
int dummy;
cin >> dummy;
return 0;
}
使用拆分和合并通道功能
看起来很复杂,但比每次处理一个像素要容易得多。
参见stackoverflow.com/questions/14582082/merging-channels-in-opencv查看示例
相关文章:
- C++将 16 位值转换为 32 位值
- 使用 AVX2 将 8 位从 32 位值 (__m256i) 解压缩到__m256的最快方法
- 为什么字符指针会得到一个 32 位值 (ffffff88)
- 将 32 位浮点数和不强制转换的 32 位整数与双精度进行比较,当其中一个值可能太大而无法完全适合另一种类型时
- 加载/存储8位和32位之间的值
- 在 C 语言中将 32 位 int 块连接在 16 个字符数组中
- 在C++中拆分32位值,并在MATLAB中连接块
- 在32位整数中编码4个值
- 将二进制值转换为十六进制值(32位)
- 移植将 32 位浮点数与使用 64 位进行比较的代码,此值表示什么
- 无法使用 <math.h 中的 C/C++ nextafter/nexttowards 函数获取下一个 32 位浮点值>
- 使用 32 位梅森费尔托斯特生成 64 位值
- 以最有效的形式将32位值存储为C字符串
- 将 32 个 0/1 值打包到单个 32 位变量的位中的最快方法是什么?
- 32位办公环境vba应用中uint64值的检索
- 32位二进制报文的异或反值
- OpenCV将3个通道连接到32位值
- 将32位值强制转换为HANDLE
- 在文件中存储32位浮点值的可移植性问题
- 需要一个散列函数来创建ipv6 16字节地址和TCP 2字节端口号的32位值