从 IplImage 转换为 Mat 且 cvarrToMat 缺少/跳过图像数据字节

Posted

技术标签:

【中文标题】从 IplImage 转换为 Mat 且 cvarrToMat 缺少/跳过图像数据字节【英文标题】:Conversion from IplImage to Mat with cvarrToMat missing/skipping image data bytes 【发布时间】:2019-03-11 12:14:32 【问题描述】:

我正在尝试将图像从容器 IplImage 转换为 Mat 对象,而不是使用 cvarrToMat

我意识到转换后的 Mat 图像最后会显示一些随机数据字节(也就是内存中的一些未初始化字节),但我不明白为什么会发生这种情况和/或如何解决这个问题?请参阅下面的代码和结果。

我正在使用 opencv 2.4.13.7 并在 Visual Studio 2017 (Visual C++ 2017) 中工作

我生成了一个具有像素级可识别数据的数据数组,以包含 3*4 分辨率图像的数据,该图像具有 8 位深度和 3 个颜色通道。当打印来自转换图像的数据时,它显示它在数据的每一行末尾跳过一个像素(3 个字节)。

#include "pch.h"
#include <iostream>
#include "cv.hpp"
#include "highgui.hpp"

using namespace std;
using namespace cv;

int main()

IplImage* ipl = NULL;
const char* windowName = "Mat image";
int i = 0;

ipl = cvCreateImage(cvSize(3, 4), IPL_DEPTH_8U, 3);
char array[3* 4 * 3] =  11,12,13, 21,22,23, 31,32,33, 41,42,43, 51, 52, 53, 61, 62, 63, 71, 72, 73, 81, 82, 83, 91, 92, 93, 101, 102, 103, 111, 112, 113, 121, 122, 123 ;

ipl->imageData = array;

printf("ipl->imageData = [ ");
for (i = 0; i < (ipl->width*ipl->height*ipl->nChannels); i++) 
    printf("%u, ", ipl->imageData[i]);

printf("]\n\n");


Mat ipl2 = cvarrToMat(ipl);
cout << "ipl2 = " << endl << " " << ipl2 << endl << endl;

//display dummy image in window to use waitKey function
Mat M(3, 3, CV_8UC3, Scalar(0, 0, 255));
namedWindow(windowName, CV_WINDOW_AUTOSIZE);
imshow(windowName, M);

waitKey(0);

cvReleaseImage(&ipl);

结果: Console window output for 3*4 resolution image

如果仅对 2*2 像素分辨率的图像执行相同操作,则在行尾仅跳过两个字节。我也无法解释。

Console window output for same code only with 2*2 resolution image

我想要进行这种转换的原因是因为我在 C 中有一个工作例程,将图像数据从文件(关于带有原始图像数据的旧图像文件格式的长篇故事)导入 IplImage 以进行进一步处理,我现在想保留 - 但我想开始将图像作为 Mat 处理,因为这似乎得到了更广泛的支持并且通常更易于使用,至少在我看到这个之前是这样。

【问题讨论】:

不幸的是,我现在没有可用的 OpenCV 2.4.xxx 设置来复制您的代码。代替cout &lt;&lt; [...] &lt;&lt; ipl2 &lt;&lt; [...],您能否迭代ipl2 的所有元素并比较这些值?不久前,我们从 OpenCV 2.4.xxx 迁移到 OpenCV 3.4.xxx,现在有了一个大型项目,迁移到 OpenCV 4.0.xxx。我们在过渡期间使用了cvarrToMat,根本无法观察到任何变化(相对于图像数据本身)。只是想说鼓励你从IplImage 转到Mat C API 已弃用,建议不要使用它.... 看起来数据以某种方式对齐... 看看 widthStep 并从 IplImage 对齐 .... 我的猜测是数据对齐为每行以 2 为基数 .... 可能 4x4 矩阵不会显示此错误...如上一条评论所示,我没有 2.4 来测试它,但我认为它是这样的.此外,文档说不要直接使用 ImageData 而是使用 setData.... @HansHirse 你能建议一种“迭代所有元素”并显示它们的方法,而不是我所做的吗?正如您可能已经猜到的那样,我是 C++ API 的新手,我所做的正是文档 docs.opencv.org/2.4/doc/tutorials/core/… 中建议的内容 【参考方案1】:

免责声明:这不是问题本身的答案,但应该有助于作者进一步调查他的问题。另外,请参阅问题下方的 cmets。

作为一个小测试,我使用这个 3x3 图像(你几乎看不到 - 请查看我的问题的“原始”输入以获取链接):

Image Watch(Visual Studio 扩展)中,它看起来像这样:

让我们试试下面的代码:

    // Read input image.
    cv::Mat img = cv::imread("test.png", cv::IMREAD_COLOR);

    // Output pixel values.
    for (int x = 0; x < img.cols; x++)
    
        for (int y = 0; y < img.rows; y++)
        
            printf("%d ", img.at<cv::Vec3b>(y, x)[0]);
            printf("%d ", img.at<cv::Vec3b>(y, x)[1]);
            printf("%d \n", img.at<cv::Vec3b>(y, x)[2]);
        
    

我们会得到这个输出:

0 255 255
0 255 255
255 255 255
255 0 255
255 255 255
255 0 255
0 0 255
0 255 255
255 0 255

现在,您可以使用嵌套循环来检查您的IplImage iplMat ipl2 中的图像数据(或更好的:像素值)是否相同。

【讨论】:

以上是关于从 IplImage 转换为 Mat 且 cvarrToMat 缺少/跳过图像数据字节的主要内容,如果未能解决你的问题,请参考以下文章

从 Mat 元素到 IplImage 的 opencv 转换 *

从 Iplimage 到 Mat 的转换不保留深度信息

将 IplImage 转换为 Mat 时出错

opencv:将iplimage转换为mat后出错

opencv:将 Mat 转换为 IplImage 问题

opencv中Mat与IplImage,CVMat类型之间转换