上一教程: 轮廓属性
下一教程: 轮廓层次结构
目标
本章我们将学习:
- 凸缺陷及其查找方法。
- 查找点到多边形的最短距离
- 匹配不同的形状
理论与代码
1. 凸缺陷
我们在关于轮廓的第二章中看到了什么是凸包。物体偏离凸包的任何偏差都可以被认为是凸缺陷。
OpenCV 提供了一个现成的函数来查找凸缺陷,cv.convexityDefects()。基本的函数调用如下所示
void convexHull(InputArray points, OutputArray hull, bool clockwise=false, bool returnPoints=true)
查找点集的凸包。
void convexityDefects(InputArray contour, InputArray convexhull, OutputArray convexityDefects)
查找轮廓的凸缺陷。
- 注意
- 请记住,为了查找凸缺陷,在查找凸包时必须传递 returnPoints = False。
它返回一个数组,其中每一行包含这些值 - [起始点,结束点,最远点,到最远点的近似距离]。我们可以使用图像将其可视化。我们绘制一条连接起始点和结束点的线,然后在最远点绘制一个圆圈。请记住,返回的前三个值是 cnt 的索引。因此,我们必须从 cnt 中获取这些值。
import cv2 as cv
import numpy as np
assert img is not None, "文件无法读取,请使用 os.path.exists() 检查"
cnt = contours[0]
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])
void imshow(const String &winname, InputArray mat)
在指定的窗口中显示图像。
int waitKey(int delay=0)
等待按下键。
void destroyAllWindows()
销毁所有 HighGUI 窗口。
CV_EXPORTS_W Mat imread(const String &filename, int flags=IMREAD_COLOR_BGR)
从文件中加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0, AlgorithmHint hint=cv::ALGO_HINT_DEFAULT)
将图像从一个颜色空间转换为另一个颜色空间。
void line(InputOutputArray img, Point pt1, Point pt2, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
绘制连接两点的线段。
void circle(InputOutputArray img, Point center, int radius, const Scalar &color, int thickness=1, int lineType=LINE_8, int shift=0)
绘制一个圆。
double threshold(InputArray src, OutputArray dst, double thresh, double maxval, int type)
对每个数组元素应用固定级别的阈值。
void findContours(InputArray image, OutputArrayOfArrays contours, OutputArray hierarchy, int mode, int method, Point offset=Point())
在二值图像中查找轮廓。
查看结果
图像
2. 点多边形测试
此函数查找图像中一个点与轮廓之间的最短距离。如果点在轮廓外部,则返回负距离;如果点在轮廓内部,则返回正距离;如果点在轮廓上,则返回零。
例如,我们可以检查点 (50,50) 如下所示
double pointPolygonTest(InputArray contour, Point2f pt, bool measureDist)
执行点在轮廓内的测试。
在函数中,第三个参数是 measureDist。如果为 True,则查找带符号距离。如果为 False,则查找点在轮廓内部、外部还是轮廓上(分别返回 +1、-1、0)。
- 注意
- 如果您不想查找距离,请确保第三个参数为 False,因为这是一个耗时的过程。因此,将其设置为 False 可以提高 2-3 倍的速度。
3. 形状匹配
OpenCV 提供了一个函数 cv.matchShapes(),它使我们能够比较两种形状或两种轮廓,并返回一个表示相似度的度量值。结果越低,匹配越好。它是根据 hu 矩值计算的。文档中解释了不同的测量方法。
import cv2 as cv
import numpy as np
img1 =
cv.imread(
'star.jpg', cv.IMREAD_GRAYSCALE)
img2 =
cv.imread(
'star2.jpg', cv.IMREAD_GRAYSCALE)
assert img1 is not None, "文件无法读取,请使用 os.path.exists() 检查"
断言 img2 不是 None,"文件无法读取,请使用os.path.exists()检查"
cnt1 = contours[0]
cnt2 = contours[0]
print( ret )
double matchShapes(InputArray contour1, InputArray contour2, int method, double parameter)
比较两个形状。
我尝试使用以下不同形状的图像进行形状匹配
图像
我得到了以下结果
- 图像A与自身匹配 = 0.0
- 图像A与图像B匹配 = 0.001946
- 图像A与图像C匹配 = 0.326911
看,即使图像旋转也不会对这个比较产生太大影响。
- 注意
- Hu矩是七个对平移、旋转和缩放不变的矩。第七个是偏斜不变的。这些值可以使用cv.HuMoments()函数找到。
练习
- 查看cv.pointPolygonTest()的文档,您可以找到一张漂亮的红蓝颜色图像。它表示所有像素到其上白色曲线的距离。曲线内的所有像素根据距离显示为蓝色。同样,外部点为红色。轮廓边缘用白色标记。所以问题很简单。编写代码来创建这种距离表示。
- 使用cv.matchShapes()比较数字或字母的图像。(这将是OCR的简单步骤)