Matching contours

Hu moment invariants can be used for both object matching and recognition. In this section, we are going to see how to match contours based on Hu moment invariants. OpenCV provides cv2.matchShapes(), which can be used to compare two contours using three comparison methods. All these methods use Hu moment invariants. The three implemented methods are cv2.CONTOURS_MATCH_I1cv2.CONTOURS_MATCH_I2, and cv2.CONTOURS_MATCH_I3.

If A denotes the first object and B denotes the second object, then the following applies:

 are the Hu moments of A and B, respectively.

Finally, see the following:

In contours_matching.py, we are making use of cv2.matchShapes() to match several contours against a perfect circle contour.

First of all, we draw a perfect circle in an image by using the OpenCV function cv2.circle(). This is going to be the reference image. In order to build this image, build_circle_image() is called. Afterwards, we load the image match_shapes.png, where many different shapes are drawn. Once the two images are ready, the next step is to find contours in each of the two aforementioned images:

  1. Convert them to grayscale by using cv2.cvtColor()  
  2. Binarize them by using cv2.threshold() 
  3. Find contours by using cv2.findContours()

At this point, we are ready to compare all the contours extracted from match_shapes.png against the contour extracted from the image built using the build_circle_image() function:

for contour in contours:
# Compute the moment of contour:
M = cv2.moments(contour)

# The center or centroid can be calculated as follows:
cX = int(M['m10'] / M['m00'])
cY = int(M['m01'] / M['m00'])

# We match each contour against the circle contour using the three matching modes:
ret_1 = cv2.matchShapes(contours_circle[0], contour, cv2.CONTOURS_MATCH_I1, 0.0)
ret_2 = cv2.matchShapes(contours_circle[0], contour, cv2.CONTOURS_MATCH_I2, 0.0)
ret_3 = cv2.matchShapes(contours_circle[0], contour, cv2.CONTOURS_MATCH_I3, 0.0)

# Get the positions to draw:
(x_1, y_1) = get_position_to_draw(str(round(ret_1, 3)), (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 1.2, 3)
(x_2, y_2) = get_position_to_draw(str(round(ret_2, 3)), (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 1.2, 3)
(x_3, y_3) = get_position_to_draw(str(round(ret_3, 3)), (cX, cY), cv2.FONT_HERSHEY_SIMPLEX, 1.2, 3)

# Write the obtainted scores in the result images:
cv2.putText(result_1, str(round(ret_1, 3)), (x_1, y_1), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 0, 0), 3)
cv2.putText(result_2, str(round(ret_2, 3)), (x_2, y_2), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 255, 0), 3)
cv2.putText(result_3, str(round(ret_3, 3)), (x_3, y_3), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (0, 0, 255), 3)

 The output of the contours_matching.py script can be seen in the following screenshot:

As it can be seen, image result_1 displays matching scores using the matching mode cv2.CONTOURS_MATCH_I1, image result_2 displays matching scores using the matching mode cv2.CONTOURS_MATCH_I2 and, finally, result_3 displays matching scores using the matching mode cv2.CONTOURS_MATCH_I3.