0
votes

I'm trying to convert an image from the container IplImage to a Mat object instead using cvarrToMat

I realized that the converted Mat image would display a number of random data bytes at the end (aka just some uninitialized bytes from memory) but I don't understand why this is happening and/or how to fix this? See the code and results below.

I'm using opencv 2.4.13.7 and working in Visual Studio 2017 (Visual C++ 2017)

I produced a data array with pixelwise recognizable data to contain data of a 3*4 resolution image with a depth of 8 bit and 3 color channels. When the data from the converted image is printed it shows that it skips a pixel (3 bytes) at each row end of the data.

#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);
}

Result: Console window output for 3*4 resolution image

If the same is done for only a 2*2 pixel resolution image then only two bytes are skipped at the row end.. I can not explain this either.

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

The reason why I would like to do this conversion is because I have a working routine in C of importing image data from a file (long story about old image file formats with raw image data) to an IplImage for further processing which I would like to keep for now - but I would like to start processing the images as Mat as this seems more widely supported and more simple to use in general, at least until I saw this.

1
Unfortunately, I have no OpenCV 2.4.xxx setup available right now to replicate your code. Instead of cout << [...] << ipl2 << [...], could you please iterate all elements of ipl2 and compare the values? We moved from OpenCV 2.4.xxx to OpenCV 3.4.xxx a while ago, and now to OpenCV 4.0.xxx with a kind of large project. We used cvarrToMat during the transition and could not observe any changes at all (with respect to the image data itself). Just wanted to say that to encourage you to move from IplImage to Mat.HansHirse
C API is deprecated, and is encouraged not to use it.... It looks like the data is aligned somehow... Take a look to widthStep and align from IplImage.... My guess is that data is aligned to be base 2 per row .... probably 4x4 matrix do not show this error... As in the previous comment, I do not have 2.4 to test it with, but I think it is something like that. Also, the documentation says not to use ImageData directly but with setData....api55
@HansHirse Can you suggest a way to "iterate all elements" and display them rather than what I did? As you might have guessed I am new to the C++ API and what I did was just what was suggested in the doc docs.opencv.org/2.4/doc/tutorials/core/…h.azephra

1 Answers

0
votes

Disclaimer: That is not an answer to the question itself, but should help the author to further investigate his problem. Also, see the comments beneath the question.

As a small test, I use this 3x3 image (you can hardly see - have a look at the "raw" input of my question for the link):

Small 3x3 image

In Image Watch (Visual Studio extension), it'll look like this:

Visualisation

Let's try the following code:

    // 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]);
        }
    }

We'll get this output:

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

Now, you could use the nested loops to check, whether the image data (or better: the pixel values) are identical in your IplImage ipl and in your Mat ipl2.