How to initialize an image with image data (OpenCV Mat to juce::Image)


#1

Hello folks. I am trying to initalize a Juce Image from a OpenCV Mat. But I am unable to initalize it. I get either pure grey or black window. Can someone help me? Here is my code:

// cvImageMat is cv::Mat
cvImageMat = cv::imread(std::string("C:\\Users\\Bora\\Pictures\\opencv\\brick.png"), cv::IMREAD_COLOR);

// image is juce::Image
image = Image(Image::PixelFormat::RGB, cvImageMat.size().width, cvImageMat.size().height, true);
Image::BitmapData data (image, 0, 0, image.getWidth(), image.getHeight(), Image::BitmapData::readWrite);
data.data = cvImageMat.data;

This code belongs to my constructor. I am painting this image in my paint function:

void paint(Graphics& g) override
{
     g.drawImage(image, 0, 0, getWidth(), getHeight(), 0, 0, image.getWidth(), image.getHeight());
}

I have omitted declaration of variables in header file for brewity here.

I am getting black screen with this setup. Can someone shed light on me? Should I get pixel data from Mat manuelly with for loops?


#2

Simply assigning the data pointers will not work.
If you have the same pixel packing in both images, you can simply copy the memory block:

// some asserts to be safe:
jassert (cvImageMat.cols == image.getWidth());    
jassert (cvImageMat.rows == image.getHeight());
memcpy (image.data, cvImageMat.data, image.getWidth() * image.getHeight() * 4);

If the format is different, you have to convert pixel by pixel…


#3

Thank you. However, what do you mean by format? Channel count or the actual file format (png, jpg etc)?


#4

No, the file format doen’t matter here any longer, because the cv::imageread converts it already to an array (they call it Mat / matrix to be mathematically more general I guess). But the raw pixels are aligned in a e certain way, which can be different for various purposes.

If you are lucky the format is per pixel 8 bit alpha, 8 bit red, 8 bit green, 8 bit blue and then the next pixel and so on…

If not, you have to see if you can find something in the OpenCV documentation, how to access the colour values for each pixel and iterate through the pixel data (I am making the openCV up, because I don’t know how you access the components)

for (int y=0; y<data.height; ++y)
    for (int x=0; x<data.width; ++x)
        data.setPixelColour (x, y, Colour::fromRGB (cvImageMat.at(x, y)[0], cvImageMat.at(x, y)[1], cvImageMat.at(x, y)[2]));

It can also be that the pixels are retrieved in a different colourspace, it can be that the colourplanes (red, green, blue alpha) are stored separately. All these combinations find their use somewhere.
But I think there is a method called cv::cvtColor() that should save you from doing it by hand…

But I haven’t used openCV, so that’s grey theory…

Good luck :slight_smile:


#5

I just thank god for sending you to me :slight_smile: I have solved, I can show a cv::Mat as a juce::ımage now.


#6

FYI, if you’re using @daniel’s code verbatim, it will almost definitely be a crazy expensive operation to convert between the datatypes (though it will be guaranteed to work).

It would be worth looking into seeing if there’s a way to assign the low-level image formats in the cv::Mat and juce::Image to be the same (i.e. same pixel depth, data layout) - that way you could just do a direct data copy/move between containers without all the extra overhead.


#7

Indeed, that’s why I said try to use the same format and use memcpy, see my first post.
If all else fails, iterating pixelwise is an option, though very expensive, just as you say…

But then, if the pixels are stored differently, you don’t have much choice, do you?
juce has only 4 byte formats, and only in one order, so if OpenCV doesn’t use the same alignment…

What I would do is to use OpenCV to bring the image into the same alignment suitable for juce using the cvtColor method I linked above and memcpy it over…

But luckily the OP has already solved his problem so enough said… :wink:


#8

Right, didn’t mean to knock your suggestion (I somehow didn’t make the connection to your prior memcpy suggestion when I wrote my post), I just want to make sure @borasemiz knows what he’s getting himself into by using pixel iteration…

Glad the problem has reached a conclusion!


#9

No problem. Sorry, seems I was a bit oversensitive…