OpenCV 4.10.0
开源计算机视觉
加载中...
搜索中...
无匹配项
轮廓:更多功能

上一教程: 轮廓属性
下一教程: 轮廓层次结构

目标

在本教程中,我们将了解

  • 凸缺陷以及如何找到凸缺陷。
  • 寻找点到多边形的最短距离
  • 匹配不同的形状

理论和代码

1. 凸缺陷

我们在有关轮廓的第二章中看到了凸包是什么。对象与这个包之间的任何偏差都可以视为凸缺陷。

OpenCV 带有一个现成的函数来查找这个函数,cv.convexityDefects()。下面是基本函数调用的样子

hull = cv.convexHull(cnt,returnPoints = False)
defects = cv.convexityDefects(cnt,hull)
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
img = cv.imread('star.jpg')
assert img is not None, "file could not be read, check with os.path.exists()"
img_gray = cv.cvtColor(img,cv.COLOR_BGR2GRAY)
ret,thresh = cv2.threshold(img_gray, 127, 255,0)
contours,hierarchy = cv2.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])
cv2.line(img,start,end,[0,255,0],2)
cv2.circle(img,far,5,[0,0,255],-1)
cv2.imshow('img',img)
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):

dist = cv2.pointPolygonTest(cnt,(50,50),True)
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()"
ret, thresh = cv.threshold(img1, 127, 255,0)
ret, thresh2 = cv.threshold(img2, 127, 255,0)
contours,hierarchy = cv2.findContours(thresh,2,1)
cnt1 = contours[0]
contours,hierarchy = cv.findContours(thresh2,2,1)
cnt2 = contours[0]
ret = cv.matchShapes(cnt1,cnt2,1,0.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() 函数找到这些值。

更多资源

练习

  1. 查看文档cv.pointPolygonTest(),您可以在红色和蓝色中找到一个漂亮的图片。该图片表示图片中所有像素到白色曲线的距离。曲线内部的所有像素根据距离呈现蓝色。类似地,外部点呈现红色。轮廓边缘标记为白色。因此问题很简单。编写代码以创建这样的距离表示。
  2. 使用cv.matchShapes()比较数字或字母的图片。(这将向 OCR 迈出简单一步)