1

I need to transfer the image data from a Mat object (OpenCV) to a const unsigned char* within a ZXing::ImageView object; typically, I just use (assuming the object is named "object") object.data at my own risk and go from there if there are issues with the transfer. However, in this case, the data member variable is empty. This Mat object does produce an image with imshow though so I'm not sure where else to look. I have gone through the documentation but my limited experience and lack of knowledge keeps me from effectively going through it at a reasonable pace or in a relevant direction. Here is my code:

#include <opencv2/opencv.hpp>
#include <ZXing/ReadBarcode.h>
using namespace cv;

Mat applyThreshold(Mat gradient);
Mat erodeAnddilate(Mat threshold_applied);
void readBarCode(Mat dest);

int main() {
    std::string file = "C:\\Users\\these\\Desktop\\cropped.JPG";
    namedWindow("imageview", WINDOW_NORMAL);
    Mat src = imread(file, IMREAD_COLOR);
    Mat thresh_applied = applyThreshold(src);
    Mat dest = erodeAnddilate(thresh_applied);
    readBarCode(dest);
    imshow("imageview", dest);
    waitKey(0);
    
    return 0;
}

Mat applyThreshold(Mat gradient) {
    Mat dest, gray;
    cvtColor(gradient, gray, COLOR_BGR2GRAY);
    threshold(gray, dest, 0, 255, THRESH_BINARY + THRESH_OTSU);

    return dest;
}

Mat erodeAnddilate(Mat threshold_applied) {
    Mat dest;
    Mat kernel = getStructuringElement(MORPH_RECT, Size(3, 3));
    morphologyEx(threshold_applied, dest, MORPH_CLOSE, kernel, Point(-1, -1), 2);
    return dest;
}

void readBarCode(Mat dest) {
    ZXing::ImageView test(dest.data, dest.size().width, dest.size().height, ZXing::ImageFormat::None);
    ZXing::Result truth = ZXing::ReadBarcode(test);
    int momentoftruth = 0;
}

The function readBarCode() is where the issue lies. And apologies for the probably terrible code everywhere else, I have a lot to learn. :)

EDIT: The accepted solution was the only one officially given, but all of the comments collectively helped me realize my error in thinking about the data variable in question. I see the data variable as a pointer now, and will take shallow vs deep copying into consideration as a potential solution. I have a better understanding of what's going on with my Mat object and consider my question answered. Thanks everyone.

viracocha
  • 111
  • 1
  • 6
  • 1
    As an exercise to yourself, and to potentially attract higher quality answers, consider paring this down to a [example]. The practice of displaying only the minimal set of code that displays the same error can help you to understand the problem better, and removes a lot of the noise that potential answerers have to wade through. – JohnFilleau Nov 12 '20 at 15:21
  • I apologize for questioning your suggestion, but wouldn't all of this code be necessary to know what I've done to the relevant Mat object? I considered just posting the function itself, but the image processing done before that step in the program changes the Mat object a fair amount. – viracocha Nov 12 '20 at 15:26
  • 1
    What do you mean by "empty"? – molbdnilo Nov 12 '20 at 15:28
  • Your program follows a linear set of commands. If each one is a black box with a known input and a desired output, you can test if each box produces the desired output. If it does, remove it from your example and replace it with a static value. This works for basic troubleshooting, too. If you know what the expecting output should be at every step of a process, you use the half-split method to test at the middle. If the tested value is good, you eliminate the first half from consideration. If the first half is bad, you eliminate the last half from consideration. – JohnFilleau Nov 12 '20 at 15:28
  • As a concrete of example of something you can eliminate, you can likely reproduce this effect by making a toy `Mat`, instead of producing one from `imread`. That cuts down the file access, and lets us know exactly what should be in `Mat`. For all we know the issue lies in the `imread` function or the image file itself. `readBarCode()` might be totally fine. – JohnFilleau Nov 12 '20 at 15:30
  • To your point, the problem may NOT be reproducible using a toy `Mat` object. You may need one or more of the steps you show here. At the very least you can hopefully define a set of test input/output pairs for each of your functions, make a `main` that feeds these inputs to your functions, and tests that the output matches the expected. – JohnFilleau Nov 12 '20 at 15:32
  • @molbdnilo The image data that is usually stored there, in this instance, is not available there, even though showing the image is still possible. The data must still be there, I just don't know where it could be even though I've looked through the data structure in the VS2019 debugger. – viracocha Nov 12 '20 at 15:32
  • @JohnFilleau I understand what you mean though, I can work on reducing the code given to a more compact sample. – viracocha Nov 12 '20 at 15:34
  • So right now you're testing the contents of `data` by using your debugger? That's valid, I just want to make sure what your measurement approach is. – JohnFilleau Nov 12 '20 at 15:34
  • @JohnFilleau I gotcha. I'm testing each stage of image processing prior to `readBarCode()` by calling `imShow()` for each Mat object that's ouputted. As for `ZXing::ReadBarcode()`, I'm using the debugger on the `dest` Mat object that's brought in as an argument to test why the ZXing function is returning a "No results found" result. – viracocha Nov 12 '20 at 15:37
  • Shouldn't I at least see the first character however? Currently the value for `data` is "". – viracocha Nov 12 '20 at 15:41
  • 2
    If the first element is zero, that is exactly as it should be. (I deleted my previous comment since the VS debugger probably interprets it as a C-style string.) – molbdnilo Nov 12 '20 at 15:41
  • @molbdnilo I'm getting a warning to avoid extended discussion haha, but I do see what you mean, the value actually isn't empty, but its a null terminator character. That implies I need to "seek" back to the beginning before transfer right? – viracocha Nov 12 '20 at 15:49
  • 2
    Is the `data` variable empty in `dest` in `main()`? According to the CV docs, creating a `Mat` by copy should just copy a pointer to the data. Their values for `data` should be the same (and should both be pointers, not strings). Your debugger sees that they're `uchar*` and assumes that they're c-style strings. Right click the variable in the debug inspection window and change its "format" or "display" or something to "pointer"? I don't have visual studio installed at the moment. – JohnFilleau Nov 12 '20 at 15:50
  • You don't need to "seek" anything. `data` is a `uchar*`. It's a pointer. It's not a null-character. It's not a string. It's just a pointer. Your debugger won't be able to smartly display the contents of the data because it needs to use that in conjunction with its size to determine how to interpret the data pointer to by that pointer. – JohnFilleau Nov 12 '20 at 15:52
  • @JohnFilleau You're right, I typed without thinking; I may just need to hit the documentation a few more times and go through my code more carefully before coming back. I thank you for this back and forth. :) – viracocha Nov 12 '20 at 15:57
  • 1
    For future reference, you can `std::cout << M << '\n':` where `M` is a `cv::Mat` to display the contents of the matrix in a nice text-based format. https://stackoverflow.com/questions/7970988/print-out-the-values-of-a-mat-matrix-in-opencv-c – JohnFilleau Nov 12 '20 at 15:58

1 Answers1

2

Try to pass the reference to your Mat object to the functions, or if you want to copy the data for creating a new image, use explicitly the clone() method to get deep copy of your image.

Like either:

Mat applyThreshold(Mat& gradient) {
    Mat dest, gray;
    cvtColor(gradient, gray, COLOR_BGR2GRAY);
    threshold(gray, dest, 0, 255, THRESH_BINARY + THRESH_OTSU);

    return dest;
}

or:

// ...
Mat thresh_applied = applyThreshold(src.clone());
// ...
zardosht
  • 3,014
  • 2
  • 24
  • 32
  • I thank you for the suggestions, but both they did not solve my issue. The data variable remains empty. – viracocha Nov 12 '20 at 15:46
  • 2
    The `.data` is a pointer to the underlying n-dimensional (in case of an image 2D) array. What do you mean it is empty? It normally must have a value, because it is a pointer. The underlying data is not copied when you for example assign an image to another one, or pass an image as parameter. Both images point to the same data. See [here](https://subscription.packtpub.com/book/application_development/9781782161486/1/ch01lvl1sec11/exploring-the-cv-mat-data-structure) for example. – zardosht Nov 12 '20 at 15:59