如何从OpenCV Python中的matchShapes函数获得可靠的结果?

问题描述

对于超长问题很抱歉...我必须添加足够的图像来解释我的观点并演示不同的边缘情况

我正在尝试使用Python中的OpenCV检测减速带迹象。这些标志看起来像这样:

(这些只是我从互联网上下载的示例,以下分割轮廓不是这些图像的一部分)

我设法提取了这些标志的内部轮廓,它们看起来像这样:

一些不需要的三角形符号也通过我的三角形检测器:

这些已提取出轮廓如下:

所以我的目的是将提取的轮廓与一些标准图像(我已经保存过)进行比较。为此,我正在OpenCV中使用matchContours函数

我正在使用的标准图像,将与所有可能的图像进行比较(左侧有多个凸起,右侧有多个凸起):

我面临的问题是matchContours输出是非常可变的,我无法理解。与上面显示的标准之一(右)相比,以下水平堆叠图像描述了目标轮廓(左),左下角的值描述了以下代码输出

def compare_rois(standard,image):
    cnt1,_ = cv2.findContours(standard,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_NONE) 
    cnt2,_ = cv2.findContours(image,cv2.CHAIN_APPROX_NONE) 

    biggest1 = sorted(cnt1,key=cv2.contourArea,reverse=True)[0]
    biggest2 = sorted(cnt2,reverse=True)[0]

    return cv2.matchShapes(biggest1,biggest2,cv2.CONTOURS_MATCH_I1,0.0)

compare_rois(single_bump_template_inverted,image) 
compare_rois(multiple_bumps_template_inverted,image)

# not displaying the stacking and adding text 

以下是上述代码输出的一些示例:

从以上图像中,我可以说这些值(两次比较中的最小值)应该在0 and 1.6之间,以便分类为“检测到减速带” ...

但是以下图像与该观察结果相矛盾。有时,错误检测到的斑点的值落在该范围内,而其他时候实际的“真实”检测值不在此范围内,更糟糕的是所有被认为与颠簸差异很大的形状也进入了范围(以“箭头”表示)或“ e”):

为什么会这样?请注意,ROI图像具有所有不同的形状...有些很小,有些很大... matchShapes应该与物体的形状无关,并且应该能够检测到该形状尽管如此,atleast that is this site says

如前所述,所有7个Hu矩在平移(沿x或y方向移动),缩放和旋转下都是不变的。

所以我的问题是:如何确保我从matchShapes获得的返回值在正确的范围内?我可以对输入图像进行任何转换,以更好地“帮助” matchShapes“看到”差异吗?


SO question与我的相似,下面的两个注释似乎表明可能需要进行一些转换...

alkasm's comment

matchShapes()使用Hu不变量;旋转/平移/比例不变的形状的描述。即使您的结果看起来很怪异,现实情况是硬币的形状非常椭圆形,比衬衫还大,这意味着如果将它们炸成相同的大小,硬币的椭圆形会具有更大的“质量”(面积)比衬衫离中心更远。嗯,这件衬衫的matchShapes()更相似

OP's reply

解决了这个问题,只是做了一个扩展轮廓以具有正方形边界框的功能,以便以一定角度观看的硬币会面朝上出现。这可能适用于更复杂的形状...

我不确定OP在这种情况下做了什么,天气是否对我的情况有帮助,所以我问了这个问题。


我应该尝试使用其他两种已实现的方法吗? CONTOURS_MATCH_I2CONTOURS_MATCH_I3?它们到底有什么不同? official documentation只能说这么多:

enter image description here


您可以从here下载整个数据集。并在与解压缩后的“数据集”文件夹相同的工作目录中运行以下代码

import os
import cv2

dataset = "dataset"

folders = os.listdir(dataset)
folders.remove("standard")

single = cv2.imread(os.path.join(dataset,"standard","single.jpg"),0)
multiple = cv2.imread(os.path.join(dataset,"multiple.jpg"),0)


def compare_rois(roi,standard):
    cnt1,_ = cv2.findContours(roi,0.0)


for folder in folders:
    path_to_folder = os.path.join(dataset,folder)
    roi = cv2.imread(os.path.join(path_to_folder,"image.jpg"),0)

    ret1 = compare_rois(roi,single)
    ret2 = compare_rois(roi,multiple)
    
    single_resized   = cv2.resize(single,roi.shape[::-1],interpolation = cv2.INTER_NEAREST)
    multiple_resized = cv2.resize(multiple,interpolation = cv2.INTER_NEAREST)
    
    stacked1 = np.hstack((roi,single_resized))
    stacked2 = np.hstack((roi,multiple_resized))    
    
    h,w = stacked1.shape[:2]
    cv2.putText(stacked1,"{:3f}".format(ret1),(10,h - h//w - 10),0.5,(255,255,255),1)
    
    h,w = stacked2.shape[:2]
    cv2.putText(stacked2,"{:3f}".format(ret2),1)
    
    cv2.imshow("roi",roi)
    cv2.imshow("compared with single",stacked1)
    cv2.imshow("compared with multiple",stacked2)
    
    if cv2.waitKey(0) == ord('q'):
        cv2.destroyAllWindows()     

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...