I created a clothes mask to extract the clothes object from a image, but there are some white noises included in the mask, the following is the illustration (the outside black area is the background).
I want to get rid of the "white" edge noise from the mask, and I have tried using the naive method of checking if the pixel value is >= 240, the result improves but still not perfect, as shown below:
I want to completely remove the white noise but not sure how to do that. I am using python opencv and would appreciate if anyone could help me on this.
Thanks!
By dilating the threshold image I was able to take a slightly larger bite out of the image and remove all of the white, but a 1px edge was removed from some innocent areas.
Here is the result:
And here is the code, based on this answer:
import cv2
import numpy as np
# Create binary threshold
img = cv2.imread('shirt.jpg')
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, gray = cv2.threshold(gray, 220, 255, cv2.THRESH_BINARY)
# Dilate the image to join small pieces to the larger white sections
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3, 3))
gray = cv2.dilate(gray, kernel)
# Create the mask by filling in all the contours of the dilated edges
mask = np.zeros(gray.shape, np.uint8)
_, contours, _ = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
for cnt in contours:
if 10 < cv2.contourArea(cnt) < 5000:
# cv2.drawContours(img, [cnt], 0, (0, 255, 0), 2)
cv2.drawContours(mask, [cnt], 0, 255, -1)
# Erode the edges back to their orig. size
# Leaving this out creates a more greedy bite of the edges, removing the single strands
# mask = cv2.erode(mask, kernel)
cv2.imwrite('im.png', img)
cv2.imwrite('ma.png', mask)
mask = cv2.cvtColor(255 - mask, cv2.COLOR_GRAY2BGR)
img = img & mask
cv2.imwrite('fi.png', img)
This answer has the benefit of the contours part allowing you to keep white areas of smaller sizes if you mess around with the magic number 10 (I'm assuming this may not be the only image you want to run this code over.) If that is not necessary, then the code could be a lot simpler, by just 1) taking the original threshold, 2) dilating it 3) masking it out on the original image.