求则得之,舍则失之

求则得之,舍则失之

在本章中,我们将学习

  • 一些常用的属性,如Solidity,等效直径,掩模图像,平均强度等。
  • 质心(Centroid)、面积(Area)、周长(Perimeter)等也属于这一类,但我们在上一篇已经学习过
  • 凸度缺陷及如何找到它们。
  • 最短距离:从一个点到一个多边形的最短距离
  • 匹配不同的形状
import cv2 as cv
import numpy as np

img = cv.imread('star.jpg', 0)
ret2, thresh = cv.threshold(img, 127, 255, cv.THRESH_BINARY_INV)
contours, hierarchy2 = cv.findContours(thresh, 1, 2)
# contours, hierarchy = cv.findContours(thresh, cv.RETR_TREE, cv.CHAIN_APPROX_SIMPLE)
cnt = contours[1]

1. 横纵比

基于OpenCV的轮廓检测(2)-LMLPHP

# 它是物体的边界矩形的宽度与高度之比。
x, y, w, h = cv.boundingRect(cnt)
aspect_ratio = float(w) / h

2.Extent

基于OpenCV的轮廓检测(2)-LMLPHP

# Extent是等轮廓面积与边界矩形面积的比值。
area = cv.contourArea(cnt)
x, y, w, h = cv.boundingRect(cnt)
rect_area = w * h
extent = float(area) / rect_area

3.Solidity

基于OpenCV的轮廓检测(2)-LMLPHP

# Solidity是轮廓面积与其凸包面积之比。
area = cv.contourArea(cnt)
hull = cv.convexHull(cnt)
hull_area = cv.contourArea(hull)
solidity = float(area) / hull_area

4.等效直径

基于OpenCV的轮廓检测(2)-LMLPHP

# 等效直径是指面积与轮廓面积相等的圆的直径。
area = cv.contourArea(cnt)
equi_diameter = np.sqrt(4 * area / np.pi)

5.方向

# 方向是物体所指向的角度。下面的方法也给出了长轴和短轴的长度。
(x, y), (MA, ma), angle = cv.fitEllipse(cnt)

6. 掩模和像素点

# 在某些情况下,我们可能需要包含该对象的所有点。可以这样做:
mask = np.zeros(img.shape, np.uint8)
cv.drawContours(mask, [cnt], 0, 255, -1)
pixelpoints = np.transpose(np.nonzero(mask))  # 转置
# pixelpoints = cv.findNonZero(mask)
# 这里给出了两个方法,一个使用Numpy函数,另一个使用OpenCV函数(最后一个注释行)来完成相同的操作。结果也是相同的,但略有不同。
# Numpy给出了**(row, column)**格式的坐标,而OpenCV给出了**(x,y)**格式的坐标。所以基本上答案会互换。注意,row = y, column = x。

7.最大值最小值以及对应的位置

# 我们可以通过掩膜图像找到这些参数。
min_val, max_val, min_loc, max_loc = cv.minMaxLoc(img, mask=mask)

8.平均颜色或平均强度

# 在这里,我们可以找到一个物体的平均颜色。也可以是灰度模式下物体的平均强度。我们再次使用相同的掩膜来完成。
mean_val = cv.mean(img, mask=mask)

9.极值点

# 极值点是指物体的最上方、最下方、最右边和最左边的点。
leftmost = tuple(cnt[cnt[:, :, 0].argmin()][0])
rightmost = tuple(cnt[cnt[:, :, 0].argmax()][0])
topmost = tuple(cnt[cnt[:, :, 1].argmin()][0])
bottommost = tuple(cnt[cnt[:, :, 1].argmax()][0])

基于OpenCV的轮廓检测(2)-LMLPHP

10.凸缺陷

# 物体与凸包的任何偏差都可以被认为是凸缺陷。
# OpenCV提供了一个现成的函数,cv.convexitydefects()。基本的函数调用如下所示:
hull = cv.convexHull(cnt, returnPoints=False)
defects = cv.convexityDefects(cnt, hull)
# 记住,为了找到凸缺陷,我们必须传递returnPoints = False。
# 它返回一个数组,其中每一行包含这些值—[起始点、结束点、最远点、到最远点的近似距离]。我们可以使用一个可视化图像。
# 我们从开始点到结束点画一条线,然后在最远的点上画一个圆。记住,返回的前三个值是cnt的索引。所以我们必须从cnt中引入这些值。
img = cv.imread('star.jpg')
img_gray = cv.cvtColor(img, cv.COLOR_BGR2GRAY)
ret, thresh = cv.threshold(img_gray, 127, 255, cv.THRESH_BINARY_INV)
contours, hierarchy = cv.findContours(thresh, 2, 1)
cnt = contours[0]
hull = cv.convexHull(cnt, returnPoints=False)
defects2 = cv.convexityDefects(cnt, hull)
for i in range(defects2.shape[0]):
    s, e, f, d = defects2[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()

基于OpenCV的轮廓检测(2)-LMLPHP

11.点多边形测试

这个函数查找图像中一个点和轮廓线之间的最短距离。它返回距离,当点在轮廓外时为负,当点在轮廓内时为正,如果点在轮廓上则为零。

# 例如,我们可以这样检查点(50,50):
dist = cv.pointPolygonTest(cnt, (50, 50), True)

在函数中,第三个参数是measureDist。如果它为真,它会找到带符号的距离。如果为False,它会查找点是在轮廓线内还是在轮廓线外(分别返回+1,-1,0)。
如果你不想求距离,请确保第三个参数为False,因为这是一个耗时的过程。因此,将其设置为False将提供2-3倍的加速。

12.形状匹配

OpenCV附带了一个函数cv.matchShapes(),它使我们能够比较两个形状或两个轮廓,并返回一个显示相似性的指标。结果越低,说明匹配得越好。它是根据Hu矩计算的。文档中解释了不同的测量方法。

img1 = cv.imread('star.jpg', 0)
img2 = cv.imread('star2.jpg', 0)
ret2, thresh = cv.threshold(img1, 127, 255, cv.THRESH_BINARY_INV)
ret3, thresh2 = cv.threshold(img2, 127, 255, 0)
contours, hierarchy = cv.findContours(thresh, 2, 1)
cnt1 = contours[0]
contours, hierarchy2 = cv.findContours(thresh2, 2, 1)
cnt2 = contours[0]
ret = cv.matchShapes(cnt1, cnt2, 1, 0.0)
print(ret)
# 我尝试匹配不同的形状,如下所示:
# 我得到了以下结果:
# 匹配图像A与自身= 0.0
# 匹配图像A与图像B = 0.001946
# 匹配图像A与图像C = 0.326911
# 甚至图像旋转不影响结果

参考目录

https://docs.opencv.org/4.x/d5/d45/tutorial_py_contours_more_functions.html

07-27 12:58