22

Is it possible to only blur a subregion of an image, instead of the whole image with OpenCV, to save some computational cost?

EDIT: One important point is that when blurring the boundary of the subregion, one should use the existing image content as much as possible; only when the convolution exceeds the boundary of the original image, an extrapolation or other artificial border conditions can be used.

nathancy
  • 42,661
  • 14
  • 115
  • 137
xuhdev
  • 8,018
  • 2
  • 41
  • 69

4 Answers4

21

To blur the whole image, assuming you want to overwrite the original (In-place filtering is supported by cv::GaussianBlur), you will have something like

 cv::GaussianBlur(image, image, Size(0, 0), 4);

To blur just a region use Mat::operator()(const Rect& roi) to extract the region:

 cv::Rect region(x, y, w, h);
 cv::GaussianBlur(image(region), image(region), Size(0, 0), 4);

Or if you want the blurred output in a separate image:

 cv::Rect region(x, y, w, h);
 cv::Mat blurred_region;
 cv::GaussianBlur(image(region), blurred_region, Size(0, 0), 4);

The above uses the default BORDER_CONSTANT option that just assumes everything outside the image is 0 when doing the blurring. I am not sure what it does with pixels at the edge of a region. You can force it to ignore pixels outside the region (BORDER_CONSTANT|BORDER_ISOLATE). SO it think it probably does use the pixels outside the region. You need to compare the results from above with:

 const int bsize = 10;
 cv::Rect region(x, y, w, h);
 cv::Rect padded_region(x - bsize, y - bsize, w + 2 * bsize, h + 2 * bsize)
 cv::Mat blurred_padded_region;
 cv::GaussianBlur(image(padded_region), blurred_padded_region, Size(0, 0), 4);

 cv::Mat blurred_region = blurred_padded_region(cv::Rect(bsize, bsize, w, h));
 // and you can then copy that back into the original image if you want: 
 blurred_region.copyTo(image(region));
Bull
  • 11,771
  • 9
  • 42
  • 53
  • Seems that this method does not take care of the boundary -- it still uses some sort of interpolation instead of what is really in the image outside the region. Am I right about this? – xuhdev Jun 13 '14 at 18:49
  • @xuhdev you are right. I have added an example to my answer to get around this. If the region might be near one or two boarders of the containing image, you will need to add some messiness to cope with that. – Bull Jun 14 '14 at 01:31
  • @xuhdev, upon looking at the filter engine code, I now think that maybe you are not right. Need to test. – Bull Jun 14 '14 at 02:24
  • I can see your edited solution. Yes, it works, but the actually it has blurred some unnecessary region which leads to extra work. Any way, have you tested the original method yet? Does it actually uses the border in the original matrix? – xuhdev Jun 16 '14 at 22:08
  • Doing this in parallel_for_ gives runtime error. I have disjoint stripes of images in different threads. – MrObjectOriented Jun 09 '20 at 10:40
11

Here's how to do it in Python. The idea is to select a ROI, blur it, then insert it back into the image

import cv2

# Read in image
image = cv2.imread('1.png')

# Create ROI coordinates
topLeft = (60, 140)
bottomRight = (340, 250)
x, y = topLeft[0], topLeft[1]
w, h = bottomRight[0] - topLeft[0], bottomRight[1] - topLeft[1]

# Grab ROI with Numpy slicing and blur
ROI = image[y:y+h, x:x+w]
blur = cv2.GaussianBlur(ROI, (51,51), 0) 

# Insert ROI back into image
image[y:y+h, x:x+w] = blur

cv2.imshow('blur', blur)
cv2.imshow('image', image)
cv2.waitKey()

Before -> After

nathancy
  • 42,661
  • 14
  • 115
  • 137
4

Yes it is possible to blur a Region Of Interest in OpenCV.

size( 120, 160 ); 
OpenCV opencv = new OpenCV(this);
opencv.loadImage("myPicture.jpg");
opencv.ROI( 60, 0, 60, 160 );
opencv.blur( OpenCV.BLUR, 13 );   
image( opencv.image(), 0, 0 );

For more information, check out this link. Good luck,

The_Doctor
  • 181
  • 5
  • 16
1

If you are using javacv provided by bytecode

then you can do like this way. It will only blur particular ROI.

Mat src = imread("xyz.jpg",IMREAD_COLOR);
Rect rect = new Rect(50,50,src.size().width()/3,100);
GaussianBlur(new Mat(src, rect), new Mat(src, rect), new Size(23,23), 30);
Singhak
  • 8,508
  • 2
  • 31
  • 34