OpenCV (Java) submat doesn't appear to share buffer with parent mat?

Viewed 354

From what I've read online, when you make a submat in OpenCV, it shares the image buffer of the parent mat:

enter image description here

However, this does not seem to be the behavior I'm getting when using OpenCV from Java on Android.

Here's a snippet which makes a submat, and then fills it with solid blue. However, the original mat remains untouched when rendered to the screen:

//Create submat
submat1 = input.submat(new Rect(sub1pointA, sub1pointB));

//Fill submat with solid color
Imgproc.rectangle(
    submat1 ,
    new Point(0,0),
    new Point(submat1.width(), submat1.height()),
    new Scalar(0, 0, 255), -1);

If, however, I change the call to rectangle() to operate on the input mat, then I do indeed get a solid blue rectangle on the screen. What gives? Am I missing something obvious, or does a submat not share the buffer with its parent when using OpenCV for Java?

2 Answers

I figured out the issue. The code was running in a loop (as each frame is received from the camera), not just once. The submat was only created the first time around the loop, because it's supposed to share the buffer of the parent, so it should get updated when the parent is updated with the next frame from the camera. The issue was that I was rotating the frame from the camera in-place before passing it to my processing function:

Core.rotate(frame, frame, Core.ROTATE_90_COUNTERCLOCKWISE);
processFrame(frame);

It seems that when rotating by 90 degrees, the backing array is re-allocated (which I guess makes sense since the number of rows and columns would be inverted), and this re-allocation breaks the link with the previously created submat.

If I do not rotate in-place, but rather rotate onto a separate Mat, and then pass that Mat to my processing function, then everything works as expected (I get a blue rectangle on the screen).

Core.rotate(frame, rotatedFrame, Core.ROTATE_90_COUNTERCLOCKWISE);
processFrame(rotatedFrame);

The function will fail without warning in many cases. Another common pitfall is if you try to copy an RGBa image into GBR or vice versa

var selectedArea = RGBaImgToDisplay.submat(resultRect)
sampleImageColor.copyTo(selectedArea)

will not work, unless you first make sure that sampleImageColor is also an RGBa like so:

cvtColor(bgrImage, sampleImageColor, Imgproc.COLOR_BGR2RGBA);
Related