OpenCV computer image processing - convexity defect + point polygon test + shape matching + contour layering and cv.findContours()

OpenCV computer image processing - convexity defect + point polygon test + shape matching + contour layering and cv.findContours()


1. Convexity defect

Generally speaking, convex curves are convex or flat curves. If they are convex (concave) inside, we call them convexity defects. OpenCV provides a method cv.convexityDefects()

This function returns an array where each row contains these values ​​- [start point, end point, furthest point, approximate distance to farthest point], we can visualize it with an image, we draw a line connecting the start point and the end point, Then draw a circle at the farthest point

import cv2 as cv
import numpy as np

img = cv.imread(r'E:\image\test14.png')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, 2, 1)
cnt = contours[0]
hull = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull)
for i in range(defects.shape[0]):
    s, e, f, d = defects[i, 0]
    start = tuple(cnt[s][0])
    end = tuple(cnt[e][0])
    far = tuple(cnt[f][0])
    cv.line(img, start, end, [0, 255, 0], 2)
    cv.circle(img, far, 5, [0, 0, 255], -1)
cv.imshow('img', img)
cv.waitKey(0)
cv.destroyAllWindows()

insert image description here

In the content of the previous outline, we mentioned a function cv.convexHull(). When the property of this function returnPoints = False, we can find the convexity defect

Code Explanation : It's time for the exciting code parsing again! Lines 4-5 are the old-fashioned way to read the image and convert it into a grayscale image. Line 6 sets the threshold through the threshold() function. Line 7 finds the contour through the findContours() method. Take out the first contour and use it The convexHull() function checks the convexity defects of the contour, and then uses the convexityDefects() function to obtain the relevant information of the corresponding points of these convexity defects, including the starting point and ending point, etc.

2. Point polygon test

A new function is involved in the point polygon test: cv.pointPolygonTest(), as the name implies, it is a test function, the first parameter is the contour, the second parameter is our test point, and the third parameter refers to measureDist , if its value is True, this function will find the signed distance, otherwise it will only reflect whether the point is inside, above or outside the contour line (return 1, -1 and 0 respectively)

import cv2 as cv
import numpy as np
img = cv.imread(r'E:\image\test12.png')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, 2, 1)
cnt = contours[0]
img02 = cv.drawContours(img, [cnt], 0, (0, 0,255), 3)
dist = cv.pointPolygonTest(cnt, (20, 20), True)
dist2 = cv.pointPolygonTest(cnt, (192.5, 156), True)
print("point:(20,20) = " + str(dist))
print("point:(192.5,156) = " + str(dist2))
cv.imshow('test', img02)
cv.waitKey(0)
cv.destroyWindow()

insert image description here

3. Shape matching

Shape matching in OpenCV is related to a function: cv.matchShapes(), this function allows us to compare two shapes (or two contours), and returns a metric showing the similarity, the lower the value, the better the match, In essence it is calculated from moment values

It is worth noting that even image rotation does not affect the result much

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pyt

img1 = cv.imread(r'E:/image/star01.png', 0)
img2 = cv.imread(r'E:/image/star02.png', 0)
img3 = cv.imread(r'E:/image/rectangle01.png', 0)
ret, thresh = cv.threshold(img1, 127, 255, 0)
ret, thresh2 = cv.threshold(img2, 127, 255, 0)
ret, thresh3 = cv.threshold(img3, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, 2, 1)
cnt1 = contours[0]
contours, hierarchy = cv.findContours(thresh2, 2, 1)
cnt2 = contours[0]
contours, hierarchy = cv.findContours(thresh3, 2, 1)
cnt3 = contours[0]
ret = cv.matchShapes(cnt1, cnt2, 1, 0.0)
ret2 = cv.matchShapes(cnt1, cnt3, 1, 0.0)
print("星图1与星图2的匹配度量 = " + str(ret))
print("星图1与方图1的匹配度量 = " + str(ret2))
pyt.subplot(1, 3, 1), pyt.imshow(img1, cmap="gray")
pyt.title("star_img01"), pyt.xticks([]), pyt.yticks([])
pyt.subplot(1, 3, 2), pyt.imshow(img2, cmap="gray")
pyt.title("star_img02"), pyt.xticks([]), pyt.yticks([])
pyt.subplot(1, 3, 3), pyt.imshow(img3, cmap="gray")
pyt.title("rectangle_img01"), pyt.xticks([]), pyt.yticks([])
pyt.show()

insert image description here

4. Contour layering and cv.findContours()

4.1 The relationship between contour layering and cv.findcontours()

In the previous article, we talked about how to use the cv.findcontours() function to find contours, and mentioned its third parameter contour retrieval mode. For this parameter, we usually use cv.RETR_LIST or cv.RETR_TREE to get a good result. Effect, and it is necessary for us to understand the three outputs of this function. Its output includes three arrays, including image (image), contour (contours) and hierarchy, which is actually what we are going to talk about in this section. "Contour Hierarchy"

In some cases, some shapes are located inside other shapes, like nested graphics, in this case, we call the outer ones the parent class, and the inner ones as subclasses, so that the There is a certain relationship between the contours. We can specify how a contour is connected to each other, for example, is it a child of another contour, or a parent, etc. The representation of this relationship is called a hierarchy

So each contour has its own information about what level it is, who is its child, who is its parent, etc. OpenCV represents it as an array with four values: [Next, Previous, First_Child, Parent], this is the third parameter we get in the findcontours() function

4.2 Contour retrieval mode (four parameters)

RETR_LIST

This is the simplest of the four flags, it just retrieves all contours, but does not create any parent-child relationship, under this rule, parent contours and child contours are equal, they are just contours, and both belong to the same hierarchy, if we Not using any hierarchy features in development, it is our best choice

RETR_EXTERNAL

If this flag is used, it returns only the extreme outer flag, and all children's outlines are left, more figuratively, according to this rule, only the eldest son of each family gets attention, it doesn't care about other members of the family, so It can be used when we only care about the outer contour

RETR_CCOMP

This flag retrieves all contours and arranges them into a 2-level hierarchy, the outer contours of the object (i.e. the boundary of the object) are placed in hierarchy-1, the contours of holes inside the object (if any) are placed in hierarchy-2, If there is any object in it, its outline is only relocated in hierarchy 1, and its hole in hierarchy 2, etc.

RETR_TREE

It's the perfect guy, it retrieves all the profiles and creates a full family hierarchy list which we use when we need to retrieve all the profiles

Let’s take a look at the code next, practice is always the best teacher

import cv2 as cv
import numpy as np
from matplotlib import pyplot as pyt

img = cv.imread(r'E:/image/the_first.png')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
cnt = contours[0]
contours, hierarchy = cv.findContours(thresh, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE)
cnt2 = contours[0]
contours, hierarchy = cv.findContours(thresh, cv.RETR_CCOMP, cv.CHAIN_APPROX_NONE)
cnt3 = contours[0]
contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
cnt4 = contours[0]
img1 = cv.drawContours(thresh, [cnt], 0, (255, 0, 0), 2)
img2 = cv.drawContours(thresh, [cnt2], 0, (0, 255, 0), 2)
img3 = cv.drawContours(thresh, [cnt3], 0, (0, 0, 255), 2)
img4 = cv.drawContours(thresh, [cnt4], 0, (0, 0, 0), 2)
pyt.subplot(2, 2, 1), pyt.imshow(img1, cmap="gray")
pyt.title("RETR_LIST"), pyt.xticks([]), pyt.yticks([])
pyt.subplot(2, 2, 2), pyt.imshow(img2, cmap="gray")
pyt.title("RETR_EXTERNAL"), pyt.xticks([]), pyt.yticks([])
pyt.subplot(2, 2, 3), pyt.imshow(img3, cmap="gray")
pyt.title("RETR_CCOMP"), pyt.xticks([]), pyt.yticks([])
pyt.subplot(2, 2, 4), pyt.imshow(img3, cmap="gray")
pyt.title("RETR_TREE"), pyt.xticks([]), pyt.yticks([])
pyt.show()

(Note: For the content of the article, refer to the official Chinese document of OpenCV4.1)
If the article is helpful to you, remember to support it with one click and three links

Guess you like

Origin blog.csdn.net/qq_50587771/article/details/124284801