I am working on preprocessing images of digits. Each image contains a single number and some unwanted contours .
This noise or contours can be in the form of lines or small dots. My task is to remove these contours. So I decided to use the following algorithm
Find all contours
Sort the contours according to the area in descending order
Iterate through contours from index 2 to last
create a boundingRect and fill that part of the image with 255
cv2.findContours(image, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) contours = sorted(contours, key = cv2.contourArea, reverse = True) for c in contours[2:]: (x, y, w, h) = cv2.boundingRect(c) image[y:y + h, x:x + w] = 255
Now the problem is that in case of first image boundingRect is returning (14,14,150,150) which covers the digit too. Now my question is that is there any better alternative to boundingRect so that only contour area can be replaced.
Output images were following:
Original image files are following
Advertisement
Answer
I’m able to achieve the desired output by these steps:
Inverse the color of the image (Or change the retrieving method to RETR_INTERNAL while finding contours). White pixels have value of 1 and blacks have the value of 0, thus black contours can not be detected by RETR_EXTERNAL operation.
Sort te contours according to area as you did
Fill the contours starting from the second largest contour with white.
Code:
# Images I copied from here were not single channel, so convert to single channel to be able to find contours. img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # Copy the original image to draw on it later on img_copy = img.copy() # Invert the color if using RETR_EXTERNAL img = cv2.bitwise_not(img) # Note that findContours function returns hierarchy as well as the contours in OpenCV4.x, in OpenCV3.x it used to return 3 values. contours, hierarchy = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # Sort the contours descending according to their area contours = sorted(contours, key =lambda x: cv2.contourArea(x), reverse = True) # Fill the detected contours starting from second largest for c in contours[1:]: print(c) img_copy = cv2.fillPoly(img_copy, [c], color=(255,255,255))
Output: (Black bar between windows is my background)