【转载】OpenCV-Python系列之轮廓的高级功能(三十二)

截至到本次教程,我们已经基本掌握了OpenCV常用的一些功能,实际上已经可以处理很多问题了,故从本教程开始,示例代码将编写为一个固定函数,以便调用,另外将不再给出完整代码,比如导入库将不再另行贴出,一些基本的代码也不再贴出,只贴出核心部分,我会将核心部分整理为一个方便调用的函数。

我们在前面讨论了轮廓的特征以及属性,今天我们将综合之前学的内容讨论轮廓的高级功能。

凸缺陷

对象上的任何凹陷都被称为凸缺陷,OpenCV 中有一个函数cv.convexityDefect()可以帮助我们找到凸缺陷,函数调用如下:

hull = cv2.convexHull(cnt,returnPoints = False)

defects = cv2.convexityDefects(cnt,hull)

注意:如果要查找凸缺陷,在使用函数 cv2.convexHull 找凸包时,
参数 returnPoints 一定要是 False。

它会返回一个数组,其中每一行包含的值是 [起点,终点,最远的点,到最远点的近似距离],们可以在一张图上显示它。我们将起点和终点用一条绿线 连接,在最远点画一个圆圈,要记住的是返回结果的前三个值是轮廓点的索引,我们仍然使用之前的多边形的图片:
在这里插入图片描述

来看代码核心部分:

view plaincopy to clipboardprint?
def convexity(img):  
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
    ret, thresh = cv2.threshold(img_gray, 127, 255, 0)  
    contours, hierarchy = cv2.findContours(thresh, 2, 1)  
    cnt = contours[0]  
    hull = cv2.convexHull(cnt, returnPoints=False)  
    defects = cv2.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)  

在这里插入图片描述

可以看到,凹陷处被检测出来。

点多边形测试

点多边形测试求解图像中的一个点到一个对象轮廓的最短距离。如果点在轮廓的外部,返回值为负。如果在轮廓上,返回值为0。如果在轮廓内部,返回值为正。

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

dist = cv.pointPolygonTest(cnt,(50,50),True)

在函数中,第三个参数是measureDist。如果为True,则找到带符号的距离。如果为False,它将查找该点是在轮廓内部还是外部或轮廓上(分别返回+ 1,-1、0)。

这个按照我们的需要设置为False即可,当measureDist设置为false时,若返回值为+1,表示点在轮廓内部,返回值为-1,表示在轮廓外部,返回值为0,表示在轮廓上。

注意:如果不想查找距离,确保第三个参数为False,因为这是一个耗时的过程。因此,将其设置为False可使速度提高2-3倍。

我们来看代码,看看(50,50)位于哪儿:

view plaincopy to clipboardprint?
def PointPolygon(img):  
    img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)  
    ret, thresh = cv2.threshold(img_gray, 127, 255, 0)  
    contours, hierarchy = cv2.findContours(thresh, 2, 1)  
    cnt = contours[0]  
    dist = cv2.pointPolygonTest(cnt,(50,50),False)  
    print(dist)  

结果:
在这里插入图片描述
-1代表该点位于轮廓内部。

匹配形状

函数 cv2.matchShape() 可以帮我们比较两个形状或轮廓的相似度。如果返回值越小,匹配越好。它是根据 Hu 矩来计算的。Hu 矩是归一化中心矩的线性组合,之所以这样做是为了能够获取代表图像的某个特征的矩函数,这些矩函数对某些变化如缩放,旋转,镜像映射具有不变形。

我们来看函数原型以及相应参数解释:
在这里插入图片描述

第一个参数是待匹配的物体1,第二个是待匹配的物体2

第三个参数method有三种输入:

CV_CONTOURS_MATCH_I1

CV_CONTOURS_MATCH_I2

CV_CONTOURS_MATCH_I3

即三种不同的判定物体相似的方法
在这里插入图片描述

注意:

前两个参数输入“灰度图像”时,并不是想当然的那样,其内容包含待匹配轮廓图案的灰度图;而是使用一行或一列双通道灰度图或者两列灰度图,该图中的每个像素不是什么图片,而是代表多边形轮廓上各节点的X,Y坐标。

输入轮廓时每个参数只能是一个轮廓

MatchShapes是OpenCV提供的一个根据计算比较两张图像Hu不变距的函数,函数返回值代表相似度大小,完全相同的图像返回值是0,返回值最大是1。这可以用在在一堆照片中搜索出两张相同或相同程度最大的图像。

我们现在可以做个试验,类似于模板匹配。

待识别图像:
在这里插入图片描述
模板图像:
在这里插入图片描述

现在我们看看识别的步骤:

  1. 将待识别图像 -> 灰度图像 -> 二值图像

  2. 通过轮廓检索函数 cv.findContours 找到待识别图像所有轮廓

  3. 模板图像 -> 灰度图像 -> 二值图像

  4. 通过轮廓检索函数 cv.findContours 找到模板图像中字母 A 的外轮廓

  5. 将第2步得到的轮廓逐一和第4步得到的轮廓 通过 cv.matchShapes 函数进行形状匹配。找到其中最小值,最小值对应的待识别图像中的轮廓即为匹配到的模板图像

  6. 标出在待识别图像中找到的模板图像

来看核心代码:

view plaincopy to clipboardprint?
def MatchShapes():  
    # 载入原图  
    img = cv2.imread('OCR.jpg', 0)  
    # 在下面这张图像上作画  
    image1 = cv2.cvtColor(img, cv2.COLOR_GRAY2BGR)  
  
    # 二值化图像  
    _, thresh = cv2.threshold(img, 0, 255, cv2.THRESH_BINARY|  
                             cv2.THRESH_OTSU)  
    # 搜索轮廓  
    contours, hierarchy = cv2.findContours(thresh, 3, 2)  
    hierarchy = np.squeeze(hierarchy)  
  
    # 载入标准模板图  
    img_a = cv2.imread('temp.jpg', 0)  
    _, th = cv2.threshold(img_a, 0, 255, cv2.THRESH_BINARY|  
                          cv2.THRESH_OTSU)  
    contours1, hierarchy1 = cv2.findContours(th, 3, 2)  
    # 字母A的轮廓  
    template_a = contours1[0]  
  
    # 记录最匹配的值的大小和位置  
    min_pos = -1  
    min_value = 2  
    for i in range(len(contours)):  
        # 参数3:匹配方法;参数4:opencv预留参数  
        value = cv2.matchShapes(template_a, contours[i], 1, 0.0)  
        if value < min_value:  
            min_value = value  
            min_pos = i  
  
    # 参数3为0表示绘制本条轮廓contours[min_pos]  
    cv2.drawContours(image1, [contours[min_pos]], 0, [255, 0, 0], 3)  
  
    cv2.imshow('result', image1)  

在这里插入图片描述
可以看到已经正确的匹配到了,实际上这就相当于是OCR文字识别的雏形。

当然,关于OpenCV中轮廓的讨论还没有结束,仍然有其他的功能,我们将在下次介绍。

查看文章汇总页https://blog.csdn.net/weixin_44237705/article/details/107864965
更多openvino技术信息可以入群交流~
在这里插入图片描述

猜你喜欢

转载自blog.csdn.net/weixin_44237705/article/details/108703205