findContours returns contour with duplicate points
Question:
OpenCV’s findContours sometimes returns bad results
The code snippet attempts to find the largest contour in the edge images.
In the “bad” example, it seems as though most vertex’s of the contour are needlessly duplicated. This causes a subsequent wrong contourArea and pointPolygonTest behavior.
import cv2
import imutils
from scipy import misc
edges = misc.imread('edges3.png')
cnts = cv2.findContours(edges.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
sorted_cnts = sorted(cnts, key = lambda c:cv2.arcLength(c,True), reverse = True)
largest_cnt = sorted_cnts[0]
print("Largest contour area",cv2.contourArea(largest_cnt))
print("Largest contour arc length",cv2.arcLength(largest_cnt,True))
print("Largest contour num of vertx",len(largest_cnt))
Bad code output:
Largest contour area 14.0
Largest contour arc length 2639.200133085251
Largest contour num of vertx 667
Good code output:
Largest contour area 95534.0
Largest contour arc length 1321.8721450567245
Largest contour num of vertx 340
The two attached photos are almost identical and should return similar results. However, the first returns a contour with a very small area, and double the arc length and vertex number compared to second one.
Answers:
I cant upload picture in a comment. Is it possible that your edge detection has some fault and there is some minor opening? the resulting is top is counting the area next to the edge and break by opening. And bottom is counting the whole image? The blue area denotes the actual counted area. Because there is a break in the edge detection, then the area is actually pretty small. It is common for edge to partially fail on a few points.
if the assumption is there is some pixel break (you line is not continuous), the result form this assumption fits your description of
A. a very small area,
B. double the arc length and vertex number
C. Some point are duplicated as they are on the same line.
To deal with this opening is using morphological dilate or convex hull to close the gap.
OpenCV’s findContours sometimes returns bad results
The code snippet attempts to find the largest contour in the edge images.
In the “bad” example, it seems as though most vertex’s of the contour are needlessly duplicated. This causes a subsequent wrong contourArea and pointPolygonTest behavior.
import cv2
import imutils
from scipy import misc
edges = misc.imread('edges3.png')
cnts = cv2.findContours(edges.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)
sorted_cnts = sorted(cnts, key = lambda c:cv2.arcLength(c,True), reverse = True)
largest_cnt = sorted_cnts[0]
print("Largest contour area",cv2.contourArea(largest_cnt))
print("Largest contour arc length",cv2.arcLength(largest_cnt,True))
print("Largest contour num of vertx",len(largest_cnt))
Bad code output:
Largest contour area 14.0 Largest contour arc length 2639.200133085251 Largest contour num of vertx 667
Good code output:
Largest contour area 95534.0 Largest contour arc length 1321.8721450567245 Largest contour num of vertx 340
The two attached photos are almost identical and should return similar results. However, the first returns a contour with a very small area, and double the arc length and vertex number compared to second one.
I cant upload picture in a comment. Is it possible that your edge detection has some fault and there is some minor opening? the resulting is top is counting the area next to the edge and break by opening. And bottom is counting the whole image? The blue area denotes the actual counted area. Because there is a break in the edge detection, then the area is actually pretty small. It is common for edge to partially fail on a few points.
if the assumption is there is some pixel break (you line is not continuous), the result form this assumption fits your description of
A. a very small area,
B. double the arc length and vertex number
C. Some point are duplicated as they are on the same line.
To deal with this opening is using morphological dilate or convex hull to close the gap.