machine learning – How to remove blurred background of images?

machine learning – How to remove blurred background of images?

This particular problem isnt too difficult to solve. Its not as bad as it could be since theres only one foreground object which means we can solve it using simple methods. @Ceopees instinct of edge detection is the correct one since its the most obvious way that the foreground will differ from a blurry background.

I grayscaled the image and use a Canny edge detector. I didnt really tune it at all so we get a bunch of edges, but we only care about finding the edges of the leaves. Thankfully, we dont have to spend a bunch of time tuning it for each image since we only care about the biggest continuous edge.

enter

I dilate the image to connect up nearby edges (canny gives 1 pixel wide lines which are easily disconnected) and then use findContours to get an outline of all of the white lines. I sort through and pick the biggest contour by area and use that one to create a mask.

enter

The jaggedness of the mask bothers me so I do an opening operation (to cut off thin jaggies) followed by a median blur (to smooth out the edges).

enter

Then all there is to do is use the mask to crop out the image and its done. (I had to change it to a jpg to make the 2mb limit so there might be some compression artifacts on here).

enter

Heres the code (Note this is in OpenCV 3.4, if youre using a different major version then youll have to modify the findContours line)

import cv2
import numpy as np

# load image
img = cv2.imread(leaf.jpg);

# grayscale
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY);

# canny
canned = cv2.Canny(gray, 0, 100);

# dilate to close holes in lines
kernel = np.ones((3,3),np.uint8)
mask = cv2.dilate(canned, kernel, iterations = 1);

# find contours
# Opencv 3.4, if using a different major version (4.0 or 2.0), remove the first underscore
_, contours, _ = cv2.findContours(mask, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE);

# find the biggest contour
biggest_cntr = None;
biggest_area = 0;
for contour in contours:
    area = cv2.contourArea(contour);
    if area > biggest_area:
        biggest_area = area;
        biggest_cntr = contour;

# draw contours
crop_mask = np.zeros_like(mask);
cv2.drawContours(crop_mask, [biggest_cntr], -1, (255), -1);

# opening + median blur to smooth jaggies
crop_mask = cv2.erode(crop_mask, kernel, iterations = 5);
crop_mask = cv2.dilate(crop_mask, kernel, iterations = 5);
crop_mask = cv2.medianBlur(crop_mask, 21);

# crop image
crop = np.zeros_like(img);
crop[crop_mask == 255] = img[crop_mask == 255];

# show
cv2.imshow(leaf, img);
cv2.imshow(gray, gray);
cv2.imshow(canny, canned);
cv2.imshow(mask, crop_mask);
cv2.imshow(cropped, crop);
cv2.waitKey(0);

If you want to generalize this to include multiple foreground objects you could filter the contours by size and reject contours smaller than a certain threshold.

machine learning – How to remove blurred background of images?

Leave a Reply

Your email address will not be published.