I have an image with an object like below:
I can detect the contour and get a mask with only ball region, but my ROI is the edge region, that means I need a bigger and a smaller mask which combine to get this:
so my question is: how can I shrink/enlarge the mask of contour around contour’s center?
Advertisement
Answer
Here is one way to do that in Python/OpenCV.
- Read the input - Convert to grayscale - Threshold - Use morphology close and open to clean up noise and small regions to form a mask - Dilate the mask - Erode the mask - Merge the input and dilated mask - Merge the eroded mask with the previous result - Save the result
Input:
import cv2 import numpy as np # read image img = cv2.imread("basketball.png") # convert img to grayscale gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # make anything not white into black mask = gray.copy() mask[mask!=255] = 0 # invert mask so center is white and outside is black mask = 255 - mask # close open mask to clean up small regions and make 3 channels kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)) mask = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel) mask = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel) mask = cv2.cvtColor(mask, cv2.COLOR_GRAY2BGR) # erode mask kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (51,51)) erode = cv2.morphologyEx(mask, cv2.MORPH_ERODE, kernel) # dilate mask and make 3 channels kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (51,51)) dilate = cv2.morphologyEx(mask, cv2.MORPH_DILATE, kernel) # merge image onto dilated mask using mask result = np.where(mask==(255,255,255), img, dilate) # merge inverted erode onto result using erode result = np.where(erode==(255,255,255), (255-erode), result) # write result to disk cv2.imwrite("basketball_mask.png", mask) cv2.imwrite("basketball_eroded_mask.png", erode) cv2.imwrite("basketball_dilate_mask.png", dilate) cv2.imwrite("basketball_dilate_mask.png", dilate) cv2.imwrite("basketball_result.png", result) # display it cv2.imshow("image", img) cv2.imshow("mask", mask) cv2.imshow("erode", erode) cv2.imshow("dilate", dilate) cv2.imshow("result", result) cv2.waitKey(0)
Mask:
Erode mask:
Dilate mask:
Result:
Note: If you dilate too much, you reach the edges of the image and then the shape changes. To avoid that, pad the input with background color enough to contain the dilated size.