了解为啥它不能使用 memcpy 正确复制
Posted
技术标签:
【中文标题】了解为啥它不能使用 memcpy 正确复制【英文标题】:Understanding why it doesn't copy correctly using memcpy了解为什么它不能使用 memcpy 正确复制 【发布时间】:2019-06-09 12:40:29 【问题描述】:我对 C++ 中的 OpenCV 4.1.0 和 memcpy 有一些误解。问题是为什么图像放大很多? 我读到这样一张图片:
Mat img = imread("lena512.bmp", 1); // Black and White Image
namedWindow("Display window", WINDOW_AUTOSIZE);
imshow("Display window", img);
在这之后我有 2 字节数组:
int inputSize = width * height * channels;
byte* pixels = new byte[width * height * channels];
byte* out = new byte[width * height * channels];
我将 img 复制到像素数组:
memcpy(pixels, img.data, inputSize * sizeof(byte));
然后我想检查检索图像是否与输入相同:
Mat image = Mat(width, height , CV_8U);
memcpy(image.data, out, inputSize * sizeof(byte));
【问题讨论】:
宽度和/或高度和/或通道很可能是错误的。 图像宽度(像素/8)和缓冲区宽度(字节)可能不同。许多图像格式要求线宽是某个因子的整数倍。 【参考方案1】:Mat img = imread("lena512.bmp", 1); // Black and White Image
这就是问题所在,注释是谎言,并且通过使用幻数而不是命名常量,您无法轻易判断是这种情况。 1
在此上下文中表示 IMREAD_COLOR
- 即图像始终被读取为 3 通道 BGR 图像。
但是,在使用 memcpy
和原始指针的恶作剧之后,您可以通过以下方式创建新的 Mat
:
Mat image = Mat(width, height , CV_8U);
注意CV_8U
等同于CV_8UC1
。因此,您创建了一个单通道(灰度)Mat
,但为其提供了 3 通道数据。
因此得到垃圾是次要问题。更严重的问题是,您复制的数据是目标像素缓冲区可以容纳的数据的 3 倍——基本上,您破坏了不属于 Mat
的半兆字节内存。这可能以段错误结束,或者一些非常难以发现的错误(以防您覆盖其他数据结构使用的一些内存)。
更新:我错过了另一个问题(感谢@Micka 发现)。 cv::Mat
constructor 的参数顺序是行、列、数据类型。您似乎切换了宽度和高度,尽管由于您的输入图像看起来是方形的(即width == height
),这并不重要。
分配第二个Mat
的正确方法是
Mat image = Mat(height, width, CV_8UC3);
【讨论】:
非常感谢!哦,哇,那条评论真是个愚蠢的错误。现在使用 IMREAD_GRAYSCALE 效果更好。是的,关于段错误。我将它与 OpenCL 一起使用,有时我的屏幕变黑并重新启动整个桌面进程,我想知道为什么。如果那是 IMREAD_COLOR,为什么它会显示灰度? 另外,在 Mat 构造函数中,顺序是(高度、宽度、类型)而不是相反。 @MIcka 很好,完全错过了那个。我认为这里没关系,因为输入图像是正方形。我会更新答案。以上是关于了解为啥它不能使用 memcpy 正确复制的主要内容,如果未能解决你的问题,请参考以下文章
为啥 argparse 不能正确解析我的布尔标志? [复制]