上一教程: 轮廓属性
下一教程: 轮廓层次结构
目标
在本教程中,我们将了解
- 凸缺陷以及如何找到凸缺陷。
- 寻找点到多边形的最短距离
- 匹配不同的形状
理论和代码
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, "file could not be read, check with 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)
从文件中加载图像。
void cvtColor(InputArray src, OutputArray dst, int code, int dstCn=0)
将图像从一种颜色空间转换到另一种。
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, "file could not be read, check with os.path.exists()"
assert img2 is not None, "file could not be read, check with 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 迈出简单一步)