opencv- contourArea doesn't work as expected

67 Views Asked by At

I followed this opencv guide to sort the contours in the first image by size.

I calculated an edge map (the result is the middle image):

# load the image and initialize the accumulated edge image
image = cv2.imread("legos.png")
accumEdged = np.zeros(image.shape[:2], dtype="uint8")
# loop over the blue, green, and red channels, respectively
for chan in cv2.split(image):
    # blur the channel, extract edges from it, and accumulate the set
    # of edges for the image
    chan = cv2.medianBlur(chan, 11)
    edged = cv2.Canny(chan, 50, 200)
    accumEdged = cv2.bitwise_or(accumEdged, edged)
# show the accumulated edge map
cv2.imwrite("images/Edge_Map.png", accumEdged)

then I calculated and drawn some contours from it:

def draw_contour(image, c, color):
    # compute the center of the contour area
    M = cv2.moments(c)
    cX = int(M["m10"] / M["m00"])
    cY = int(M["m01"] / M["m00"])
    # draw the countour and its area on the image
    cv2.drawContours(image, [c], -1, color, 2)
    cv2.putText(image, str(cv2.contourArea(c)), (cX - 10, cY - 15), cv2.FONT_HERSHEY_SIMPLEX, 0.65, color,2)

# find contours in the accumulated image
cnts = cv2.findContours(edged.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = imutils.grab_contours(cnts)

sorted_cnts = sorted(cnts, key=cv2.contourArea, reverse=True)

draw_contour(image, sorted_cnts[0], (0, 0, 0))  # forth brick
draw_contour(image, sorted_cnts[4], (80, 0, 80))  # small circle
draw_contour(image, sorted_cnts[6], (255, 255, 255))  # third brick

the problem is that the contours are not sorted (the way I thought). I included the first, fifth and seventh contours along with their areas. The fifth (area 229) is clearly smaller than the seventh (area 130).

I would like to know what cv2.contourArea does in this case.

initial image edged image final image

1

There are 1 best solutions below

2
Arunbh Yashaswi On

I faced the same issue i dropped contourArea and wrote this function. using the The Shoelace formula we can find the area of contour.

def polygon_area(coords):
    n = len(coords)  
    area = 0
    for i in range(n):
        j = (i + 1) % n
        area += coords[i][0] * coords[j][1]
        area -= coords[j][0] * coords[i][1]
    area = abs(area) / 2.0
    return area

For example we can consider a triangle with vertices (1, 1), (2, 3), (4, 1):

vertices = [(1, 1), (2, 3), (4, 1)]
area = polygon_area(vertices)
print(area) 

Output :

3.0

Just a note be sure that the co-ordinates you are passing to it is for a closed polygon.