OpenCV findContours() just returning one external contour
Question:
I’m trying to isolate letters in a captcha, I managed to filter a captcha and that result in this black and white image:
But when I tried to separate the letters with findContours method of OpenCV it just found a external contour that wraps my entire image, resulting in this image (black contour outside image).
I’m using this code with Python 3 and OpenCV 3.4.2.17:
img = threshold_image(img)
cv2.imwrite("images/threshold.png", img)
image, contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for i, contour in enumerate(contours):
area = cv2.contourArea(contour)
cv2.drawContours(img, contours, i, (0, 0, 0), 3)
cv2.imwrite('images/output3.png', img)
I just want my final result is 5 contours outside each character.
Answers:
You used flag RETR_EXTERNAL, which means it is looking only for outermost contours of objects, but not holes. In your case the white object that covers a whole image with few holes (letters/digits) is found. You have two choices:
-
Inverse colors in your image with “bitwise_not”
-
Collect all contours with RETR_LIST flag. Note that it will also collect holes inside digits.
The contour to be extracted should be in white, background being black. I have modified your code a bit, eliminated the lines which were not adding any value.
import cv2
img = cv2.imread('image_to_be_read',0)
backup = img.copy() #taking backup of the input image
backup = 255-backup #colour inversion
I am using RETR_TREE as the contour retrieval mode, which retrieves all the contours and creates full family hierarchy list. Please find the documentation for the same here
_, contours, _ = cv2.findContours(backup, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
In opencv4, the finContours method has been changed. Please use:
contours, _ = cv2.findContours(backup, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
Then iterate through contours and draw the rectangle around the contours
for i, contour in enumerate(contours):
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1)
Save the image
cv2.imwrite('output3.png', img)
I got result which looks like this –
I’m trying to isolate letters in a captcha, I managed to filter a captcha and that result in this black and white image:
But when I tried to separate the letters with findContours method of OpenCV it just found a external contour that wraps my entire image, resulting in this image (black contour outside image).
I’m using this code with Python 3 and OpenCV 3.4.2.17:
img = threshold_image(img)
cv2.imwrite("images/threshold.png", img)
image, contours, _ = cv2.findContours(img, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
for i, contour in enumerate(contours):
area = cv2.contourArea(contour)
cv2.drawContours(img, contours, i, (0, 0, 0), 3)
cv2.imwrite('images/output3.png', img)
I just want my final result is 5 contours outside each character.
You used flag RETR_EXTERNAL, which means it is looking only for outermost contours of objects, but not holes. In your case the white object that covers a whole image with few holes (letters/digits) is found. You have two choices:
-
Inverse colors in your image with “bitwise_not”
-
Collect all contours with RETR_LIST flag. Note that it will also collect holes inside digits.
The contour to be extracted should be in white, background being black. I have modified your code a bit, eliminated the lines which were not adding any value.
import cv2
img = cv2.imread('image_to_be_read',0)
backup = img.copy() #taking backup of the input image
backup = 255-backup #colour inversion
I am using RETR_TREE as the contour retrieval mode, which retrieves all the contours and creates full family hierarchy list. Please find the documentation for the same here
_, contours, _ = cv2.findContours(backup, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
In opencv4, the finContours method has been changed. Please use:
contours, _ = cv2.findContours(backup, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
Then iterate through contours and draw the rectangle around the contours
for i, contour in enumerate(contours):
x, y, w, h = cv2.boundingRect(contour)
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 1)
Save the image
cv2.imwrite('output3.png', img)
I got result which looks like this –