0

I've been facing this problem for days!

I have to implement an Interface with this structure for image storing:

typedef struct Image
{
    uint16_t image_width;
    uint16_t image_height;
    uint16_t image_depth;
    uint8_t data;
    Label description;
} Image;

In my c++ function, I need the image in cv::Mat type. So I have to convert the uint8_t type in uchar type (since cv::Mat stores the data with uchar type) and viceversa. I tried in so many ways, but everytime I try to access in any way the Mat image after the convertion, I get a segmentation fault.

Look at my code:

Image face;
Mat input;
Mat output;

input = imread( argv[i], 1 );
/*data = static_cast<uint8_t>(reinterpret_cast<uchar>(*input.data)); 
this is an alternative way found online, 
but it gives the same result. 
So I replaced it with the following line*/
uint8_t data = *input.data;
image_width = input.cols;
image_height = input.rows;
image_depth = input.channels();

face.data = data;
face.image_depth = image_depth;
face.image_height = image_height;
face.image_width = image_width;


output = Mat(face.image_height, face.image_width, CV_8UC3);
output.data = &face.data;

//both the following gives segmentation fault
imshow("Face", output);
cout << output << endl; //it starts printing the matrix, but it stops after a while with the seg fault

//but the following, the Mat before the convertion, does not
imshow("Face", input);

EDIT. What I need to do is implement the Inteface

using Multiface = std::vector<Image>;

class Interface {
public:
    Interface();
    virtual ReturnStatus createTemplate(
    const Multiface &faces,
    TemplateRole role,
    std::vector<uint8_t> &templ,
    std::vector<EyePair> &eyeCoordinates,
    std::vector<double> &quality) 
};

So, after reading the image via imread, I need to pass it to createTemplate in a vector of Image type, and then inside createTemplate create a Mat object from it. I wrote the previous code to check if the conversion was possible.

The issue is to have the same picture as Image struct and ad as Mat, making a sort of conversion beetween them.

  • 2
    Are you sure your struct is correct? A `uint8_t` is only a single 8-bit unsigned number. For anything even remotely "image"-like you would need an array of whatever-type instead. – ravnsgaard Jun 05 '18 at 11:32
  • Are you aware that `Image::data` can store exact 1 byte? Type `uint8_t` is on most common platforms very probably a `typedef` for `unsigned char` - it should work with implicit cast as well. I'm rather sure that your image data (in `cv::Mat`) is of type `unsigned char*` or something similar. (The little `*` makes the difference...) – Scheff's Cat Jun 05 '18 at 11:35
  • 1
    Please, describe your task. Provided code is totally wrong. You try to store image data both in `cv::Mat` and in your custom structure. `cv::Mat` gives access to its members, but it is a very bad practice to freely play with them. You also create `output` object of type `cv::Mat` from existing data incorrectly. `cv::Mat` has a special constructor for that. – wl2776 Jun 05 '18 at 11:36
  • It seems to me that you should take a few steps back, [get a couple of good books to read](https://stackoverflow.com/questions/388242/the-definitive-c-book-guide-and-list/388282#388282) and re-learn about pointers and the operators used for pointers. – Some programmer dude Jun 05 '18 at 12:04
  • I edited because I forgot to specify the type of "data": uint8_t data = *input.data; The interface to implement force me to use this type uint8_t, but I need to reconvert the Image struct to a cv::Mat to work on it, and I can't figure out how to do this – Casimira Barberio Jun 05 '18 at 12:45

2 Answers2

1

cv::Mat::data is a pointer. It points to the first element of the data.

By using *input.data you get what the pointer is pointing to, the first element of the data. It is equal to input.data[0].

So after the assignment data = *input.data, the variable data contains only the value of the first data-element, it doesn't point to the actual data. Therefore when you later do face.data = data you make face.data "point" somewhere completely wrong.

If you want face.data to also point to the actual data, why not simply do

face.data = input.data;
face.image_depth = input.channels();
face.image_height = input.rows;
face.image_width = input.cols;

Furthermore, &face.data is a pointer to a pointer. You should use plain output.data = face.data;

Some programmer dude
  • 400,186
  • 35
  • 402
  • 621
  • @slawekwin My answer is a basic suggestion to not use any of the intermediate and temporary variables, so the variable `data` is not needed at all. – Some programmer dude Jun 05 '18 at 12:02
  • Hi, I'll explain better. My issue is to have the same picture as Image struct and ad as Mat, making a sort of conversion beetween them. I used "data" as intermediate variable because it is of uint8_t type, as the Image struct requires. – Casimira Barberio Jun 05 '18 at 13:03
0

First, define, what class owns image data: cv::Mat, your struct Image or both.

In the last case you need to allocate memory in Image, then explicitly copy data from cv::Mat to Image, and deallocate it on object destruction.

If image data are owned by cv::Mat, then take into account that this class allocates memory for them and releases after all references to it are destructed. Otherwise, you can have dangling pointers to data that doesn't exist.

Learn about reference counting. OpenCV's matrices don't copy data all the time, they count references.

cv::Mat can also handle non-contiguous regions.

If your struct Image owns the data, then everything is up to you.

I would suggest to put cv::Mat in your struct Image

struct Image {
     cv::Mat image;
     // other members
}

And yes, uint8_t data; from your struct Image must be a pointer: uint8_t* data;

You should allocate and release memory for it.

wl2776
  • 4,099
  • 4
  • 35
  • 77