4.4. 轮廓:更多功能

4.4.1. 目标

在本章中,我们将学习
-凸性缺陷及其发现方法。-寻找从一个点到多边形的最短距离-匹配不同形状

4.4.2. 理论与规范

1. 凸缺陷

我们在关于轮廓的第二章中看到了什么是凸壳。物体与船体的任何偏差都可视为凸面缺陷。

OpenCV附带了一个现成的函数来查找这个, cv2.凸性影响() . 基本函数调用如下所示:

>>> %matplotlib inline
>>> import matplotlib.pyplot as plt
>>>
>>> import cv2
>>> import numpy as np
>>> img = cv2.imread('/cvdata/star.png', 0)
>>> ret,thresh = cv2.threshold(img,127,255,0)
>>> contours,hierarchy,aa = cv2.findContours(thresh, 1, 2)
>>> for cnt in hierarchy:
>>>     area = cv2.contourArea(cnt)
>>>     print(area)
4.0
4.0
2.0
2.0
8.5
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
76185.5
>>> hull = cv2.convexHull(cnt,returnPoints = False)
>>> defects = cv2.convexityDefects(cnt,hull)

注意

记住我们必须通过 returnPoints = False 在寻找凸壳时,为了寻找凸性缺陷。

它返回一个数组,其中每一行包含这些值- [[ start point, end point, farthest point, approximate distance to farthest point ]] . 我们可以用图像把它形象化。我们画一条连接起点和终点的线,然后在最远的点画一个圆。记住,返回的前三个值是 cnt . 所以我们必须把这些价值观 cnt .

>>> import cv2
>>> import numpy as np
>>>
>>> img = cv2.imread('/cvdata/star.png')
>>> img_gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)
>>> ret, thresh = cv2.threshold(img_gray, 127, 255,0)
>>> contours,hierarchy, aa = cv2.findContours(thresh,2,1)
>>> for cnt in hierarchy:
>>>     area = cv2.contourArea(cnt)
>>>     print(area)
76188.5
4.0
4.0
2.0
2.0
8.5
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
2.0
>>> hull = cv2.convexHull(cnt,returnPoints = False)
>>> hull
array([[2],
       [3],
       [0],
       [1]], dtype=int32)
>>> defects = cv2.convexityDefects(cnt,hull)
>>> defects
>>> 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])
>>>     cv2.line(img,start,end,[0,255,0],2)
>>>     cv2.circle(img,far,5,[0,0,255],-1)
>>>
>>> # cv2.imshow('img',img)
>>> # cv2.waitKey(0)
>>> # cv2.destroyAllWindows()
---------------------------------------------------------------------------

AttributeError                            Traceback (most recent call last)

<ipython-input-12-c616904b8ea3> in <module>()
      2 defects = cv2.convexityDefects(cnt,hull)
      3
----> 4 for i in range(defects.shape[0]):
      5     s,e,f,d = defects[i,0]
      6     start = tuple(cnt[s][0])


AttributeError: 'NoneType' object has no attribute 'shape'

看看结果:

2. 点多边形测试

此函数用于查找图像中的点与轮廓之间的最短距离。当点在轮廓外时返回负距离,当点在轮廓内时返回正距离,当点在轮廓上时返回零距离。

例如,我们可以检查点(50,50)如下:

>>> dist = cv2.pointPolygonTest(cnt,(50,50),True)

在函数中,第三个参数是 measureDist . 如果是 True ,它会找到有符号的距离。如果 False ,它将查找该点是在等高线的内部还是外部(分别返回+1、-1和0)。

注意

如果你不想找到距离,确保第三个参数是 False 因为,这是一个耗时的过程。所以,成功了 False 加速2-3倍。

3. 匹配形状

OpenCV带有一个函数 匹配形状() 它使我们能够比较两个形状或两个轮廓,并返回显示相似性的度量。结果越低,匹配越好。它是根据hu矩值计算的。文件中解释了不同的测量方法。

>>> import cv2
>>> import numpy as np
>>>
>>> img1 = cv2.imread('star.jpg',0)
>>> img2 = cv2.imread('star2.jpg',0)
>>>
>>> ret, thresh = cv2.threshold(img1, 127, 255,0)
>>> ret, thresh2 = cv2.threshold(img2, 127, 255,0)
>>> contours,hierarchy = cv2.findContours(thresh,2,1)
>>> cnt1 = contours[0]
>>> contours,hierarchy = cv2.findContours(thresh2,2,1)
>>> cnt2 = contours[0]
>>>
>>> ret = cv2.matchShapes(cnt1,cnt2,1,0.0)
>>> print ret

我试着用下面给出的不同形状来匹配形状:

我得到了以下结果:

  • 将图像A与自身匹配=0.0

  • 将图像A与图像B匹配=0.001946

  • 将图像A与图像C匹配=0.326911

看,即使图像旋转也不会对这种比较产生太大影响。

Hu-Moments 是平移、旋转和缩放不变的七个矩。第七个是斜不变。这些值可以使用 第二节休谟茨() 功能。

4.4.3. 额外资源

4.4.4. 练习

  1. 检查文档 cv2.点多边形测试() ,你可以找到一个红色和蓝色的好图像。它表示从所有像素到白色曲线的距离。曲线内的所有像素均为蓝色,具体取决于距离。同样,外部点是红色的。轮廓边缘用白色标记。所以问题很简单。编写一个代码来创建这种距离表示。

  2. 使用比较数字或字母的图像 匹配形状() . (这将是迈向OCR的一个简单步骤)