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

Converting cv::Mat to unsigned int pixels

本文关键字:int 无符号 像素 转换 cv Mat      更新时间:2023-10-16

我正在尝试将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. 放下cvtColor.无论如何,您都在迭代元素,因此只需在循环体中交换rb,就可以避免转换。

  2. finalSrc阵列是所需大小的 3 倍。这是一个单通道Mat,所以你只需要srcIm.rows * srcIm.cols元素。

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

  4. 甚至不要迭代,而是使用算法 -std::transform非常适合这个。

  5. 不要指望能够使用cv::imshow可视化结果。从文档中:

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

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

注意:我使用的是"类型化"Mats(例如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);
});