“This is the 24th day of my participation in the First Challenge 2022. For details: First Challenge 2022”
preface
In computer vision, an outline is usually a series of points at the boundary of an object in an image. Therefore, contour usually describes the key information of object boundary and contains the main information about object shape, which can be used for shape analysis and object detection and recognition. In this article, you’ll first learn the basic concepts of contours through simple examples, and then learn how to detect contours through practical examples.
Outline introduction
Contour is regarded as all the points contained in the boundary curve of an object. Through the analysis of these points, shape judgment, object detection and recognition can be carried out in computer vision process. OpenCV provides a number of functions to detect and manipulate contours. Before diving into these functions, let’s first look at the basic structure of the contours through function simulation:
def get_test_contour() :
cnts = [np.array(
[[[600.320]], [[460.562]], [[180.563]], [[40.320]],
[[179.78]], [[459.77]]], dtype=np.int32)]
return cnts
Copy the code
As shown above, the contour is an array of points of type Np.int32. Call this function to get the contour represented by this array, which contains only one contour:
contours = get_test_contour()
print("contour shape: '{}'".format(contours[0].shape))
print("'detected' contours: '{}' ".format(len(contours)))
Copy the code
Once we have the contour, we can apply OpenCV to provide all the functions associated with the contour. Note that the get_one_contour() function contains only simple contours, whereas in a real scenario, the real contours detected would typically have hundreds of points, so debugging the code would be time-consuming, It would be useful to set up a simple contour, such as the get_one_contour() function here, to debug and test contour-related functions.
OpenCV provides cv2.drawContours() for drawing contours in an image. We can call this function to see what the contours look like:
def draw_contour_outline(img, cnts, color, thickness=1) :
for cnt in cnts:
cv2.drawContours(img, [cnt], 0, color, thickness)
Copy the code
In addition, we might also want to draw contour points in the image:
def draw_contour_points(img, cnts, color) :
for cnt in cnts:
# Dimensional compression
squeeze = np.squeeze(cnt)
Walk through all points of the contour array
for p in squeeze:
To draw dots, you need to convert the list to a center tuple
p = array_to_tuple(p)
# Draw outline points
cv2.circle(img, p, 10, color, -1)
return img
def array_to_tuple(arr) :
""" Convert a list to a tuple """
return tuple(arr.reshape(1, -1) [0])
Copy the code
Finally, call the draw_contour_outline() and draw_contour_points() functions to draw Outlines and outline points and visualize:
Create and copy the canvas to show different detection effects
canvas = np.zeros((640.640.3), dtype="uint8")
image_contour_points = canvas.copy()
image_contour_outline = canvas.copy()
image_contour_points_outline = canvas.copy()
Draw the wheel outline point
draw_contour_points(image_contour_points, contours, (255.0.255))
# Draw outline
draw_contour_outline(image_contour_outline, contours, (0.255.255), 3)
Draw Outlines and outline points at the same time
draw_contour_outline(image_contour_points_outline, contours, (255.0.0), 3)
draw_contour_points(image_contour_points_outline, contours, (0.0.255))
# visualization function
def show_img_with_matplotlib(color_img, title, pos) :
img_RGB = color_img[:, :, ::-1]
ax = plt.subplot(1.3, pos)
plt.imshow(img_RGB)
plt.title(title, fontsize=8)
plt.axis('off')
# draw an image
show_img_with_matplotlib(image_contour_points, "contour points".1)
show_img_with_matplotlib(image_contour_outline, "contour outline".2)
show_img_with_matplotlib(image_contour_points_outline, "contour outline and points".3)
# visualization
plt.show()
Copy the code
Contour detection
Now that we have introduced the concept of contours and seen how to draw contours through examples, we will show you how to detect contours in OpenCV. To do this, we first draw some predefined shapes and then use the drawn shapes to explain how to perform contour detection:
def build_sample_image() :
""" Draw some basic shapes """
img = np.ones((500.500.3), dtype="uint8") * 70
cv2.rectangle(img, (50.50), (250.250), (255.0.255), -1)
cv2.rectangle(img, (100.100), (200.200), (70.70.70), -1)
cv2.circle(img, (350.350), 100, (255.255.0), -1)
cv2.circle(img, (350.350), 50, (70.70.70), -1)
return img
# Load the image and convert it to grayscale image
image = build_sample_image()
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# Apply the cv2.threshold() function to obtain binary image
ret, thresh = cv2.threshold(gray_image, 70.255, cv2.THRESH_BINARY)
Copy the code
The above function draws two filled rectangles and two filled circles. This function creates an image with two outer contours and two inner contours and, after loading the image, converts it to a grayscale image and retrieves a binary image that will be used to find the contours using the cv2.findContours() function.
Next, call cv2.findContours() to detect the contour of the graph created using the build_sample_image() function. The cv2.findContours() function is used as follows:
cv2.findContours(image, mode, method[, contours[, hierarchy[, offset]]]) -> image, contours, hierarchy
Copy the code
Where, the method parameter sets the approximate method used to retrieve points related to each detected contour, cv2.findContours() returns the contour in the detected binary image (for example, the image after threshold processing), each contour contains all the contour points that define the boundary, Retrieved contours can be output in different modes:
The output mode | instructions |
---|---|
cv2.RETR_EXTERNAL | Output only external contours |
cv2.RETR_LIST | Output all contours without hierarchical relationships |
cv2.RETR_TREE | Output all contours by establishing hierarchical relationships |
The output vector Hierarchy contains information about hierarchical relationships, providing an index for each detected contour. For the ith contours[I], hierarchy[I][j] (the value of j is [0,3]) contains the following contents:
The index | instructions |
---|---|
hierarchy[i][0] | The index of the next contour at the same hierarchy level. A negative value indicates that there is no next contour |
hierarchy[i][1] | The index of a previous contour at the same level of hierarchy. A negative value indicates that there is no previous contour |
hierarchy[i][2] | The index of the first child contour, which, when negative, indicates that there is no parent contour |
hierarchy[i][3] | Index of the parent contour, which, when negative, indicates that there is no next contour |
Call the cv2.findContours() function to find the contours in the test image:
# Contour detection
contours, hierarchy = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
contours2, hierarchy2 = cv2.findContours(thresh, cv2.RETR_LIST, cv2.CHAIN_APPROX_NONE)
contours3, hierarchy3 = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_NONE)
Print the number of contours obtained using different mode parameters
print("detected contours (RETR_EXTERNAL): '{}' ".format(len(contours)))
print("detected contours (RETR_LIST): '{}' ".format(len(contours2)))
print("detected contours (RETR_TREE): '{}' ".format(len(contours3)))
image_contours = image.copy()
image_contours_2 = image.copy()
# Draw the detected contour
draw_contour_outline(image_contours, contours, (0.0.255), 5)
draw_contour_outline(image_contours_2, contours2, (255.0.0), 5)
# visualization
show_img_with_matplotlib(image, "image".1)
show_img_with_matplotlib(cv2.cvtColor(thresh, cv2.COLOR_GRAY2BGR), "threshold = 100".2)
show_img_with_matplotlib(image_contours, "contours (RETR EXTERNAL)".3)
show_img_with_matplotlib(image_contours_2, "contours (RETR LIST)".4)
Copy the code