7

I'm developing an Android app which uses a background Service to programmatically capture a screenshot of whatever is on the screen currently. I obtain the screenshot as a Bitmap.

Next, I successfully imported OpenCV into my Android project.

What I need to do now is blur a subset of this image, i.e. not the entire image itself, but a [rectangular] area or sub-region within the image. I have an array of Rect objects representing the rectangular regions that I need to blur within the screenshot.

I've been looking around for a tutorial on doing this with OpenCV in Java, and I haven't found a clear answer. The Mat and Imgproc classes are obviously the ones of interest, and there's the Mat.submat() method, but I've been unable to find a clear, straightforward tutorial on getting this done.

I've googled a lot, and none of the examples I've found are complete. I need to do this in Java, within the Android runtime.

What I need is: Bitmap >>> Mat >>> Imgproc>>> Rect >>> Bitmap with ROI blurred.

Any experienced OpenCV devs out here, can you point me in the right direction? This is the only thing I'm stuck at.

Related:

Gaussian blurring with OpenCV: only blurring a subregion of an image?.

How to blur a rectagle with OpenCv.

How to blur some portion of Image in Android?.

Yash Sampat
  • 30,051
  • 12
  • 94
  • 120
  • In very simple terms, you could extract the ROI into a separate Mat, apply your filtering to that Mat and reinsert it into the original image. Or am I missing something here? – Andreas Jan 30 '20 at 07:46
  • I think I missed something because the question seems so simple to me! In c++ if img is your Mat and r is your Rect, then img(r) would be an image itself and you can give it to the blur function independently => blur(img(r), img(r), ksize); – MeiH Feb 02 '20 at 08:31

2 Answers2

13

The C++ code to achieve this task is shared below with comments and sample images:

// load an input image
Mat img = imread("C:\\elon_tusk.png");

img:

enter image description here

// extract subimage
Rect roi(113, 87, 100, 50);
Mat subimg = img(roi);

subimg:

enter image description here

// blur the subimage
Mat blurred_subimage;
GaussianBlur(subimg, blurred_subimage, Size(0, 0), 5, 5);

blurred_subimage:

enter image description here

// copy the blurred subimage back to the original image
blurred_subimage.copyTo(img(roi));

img:

enter image description here

Android equivalent:

Mat img = Imgcodecs.imread("elon_tusk.png");
Rect roi = new Rect(113, 87, 100, 50);
Mat subimage = img.submat(roi).clone();
Imgproc.GaussianBlur(subimg, subimg, new Size(0,0), 5, 5);
subimg.copyTo(img.submat(roi));
karlphillip
  • 92,053
  • 36
  • 243
  • 426
  • that is kinda the same what I wrote, but I gave an upvote to you anyway for more detailed answer! – kalzso Feb 03 '20 at 07:54
  • Updated answer with Android code. Don't know if it works though, couldn't test it. [Look at this file](https://github.com/opencv/opencv/blob/master/samples/android/tutorial-2-mixedprocessing/src/org/opencv/samples/tutorial2/Tutorial2Activity.java) to see how to **import** stuff from OpenCV. – karlphillip Feb 03 '20 at 09:51
  • 3
    Perfect input image choice – nathancy Feb 03 '20 at 21:43
  • @karlphillip: thank you for taking the trouble. Your code most likely is the correct answer. Will report back after trying it out ... ;) – Yash Sampat Feb 05 '20 at 08:07
  • 1
    I don't think that you need to do a copy roi back. as far as I remember Mat subimage = img.submat(roi) shall create a pointer to the region of the original image. and if you blur subimage, you will automatically blur the original (IF YOU DONT CLONE IT). – hagor Feb 07 '20 at 10:16
  • karlphillip I've been working with your code, which I believe is correct, but I've been unable to reach the logical end. Could you please help me out with this [question](https://stackoverflow.com/q/60333766) which is a continuation of our discussion here? @hagor could you also take a look please? I will add a bounty for the same once SO lets me. Request your kind help with the same, and thank you for your time ... :) – Yash Sampat Feb 21 '20 at 07:48
  • @Y.S what do you mean by logical end? – hagor Feb 26 '20 at 22:42
3

You could just implement your own helper function, let's call it roi (region of interest). Since images in opencv are numpy ndarrays, you can do something like this:

def roi(image: np.ndarray, region: QRect) -> np.ndarray:
    a1 = region.upperLeft().x()
    b1 = region.bottomRight().y()
    a2 = region.upperLeft().x()
    b2 = region.bottomRight().y()
    return image[a1:a2, b1:b2]

And just use this helper function to extract the subregions of the image that you are interested, blur them and put the result back on the original picture.

kalzso
  • 502
  • 2
  • 6
  • 27