基于图像金字塔的模板匹配检测螺母

实验任务与要求:

图像01~05.jpg中是几个螺母的照片,请设计并实现一个方法,正确地检测出其中的螺母,注意:有一个是圆形的不要检测,只检测六边形螺母。可以从其中一幅图像中截取模板。

问题分析

本实验采用计算机视觉中模板匹配的相关技术,通过分析本实验中需要检测的场景与螺母的分布与位置,可以发现图片中螺母的形状是平躺,但存在不同大小和颜色的螺母,而且螺母之间间距也有稀疏不同,而且存在与螺母相似度较高的圆形物体,对多目标检测带来较大的影响。最后一张检测图像的检测场景更为复杂,由于存在许多干扰的元素。给螺母的检测带来较大的困难。为此考虑到一些解决方法,其中通过建立螺母的模板进行检测,分别利用到了彩色模板和边缘模板,以及轮廓模板。对于采用的方法有图像金字塔和距离变换。同时由于需要检测的螺母是多个,因此采用进行多目标匹配的方法。

方法流程的设计

通过分析检测螺母的场景,首先尝试采用最直接的截图获取螺母模板的方式,来进行模板的匹配,因此采用opencv中的模板匹配函数,函数返回模板与图片的响应图,根据响应图中的最大值来设置响应的阈值,进而通过调节阈值达到多目标检测的结果。通过实验结果分析,发现采用截取多个螺母模板取平均,所得到的模板的检测结果较好,因此需要加入求模板平均的步骤。其次,考虑到检测场景中存在大小不同的螺母,因此考虑到构建螺母模板的金字塔,通过与不同大小的模板的匹配,来检测出不同大小的螺母。另外考虑到螺母为正六边形,为此构造不同旋转角度的螺母,由于螺母的对称性,其中旋转角度为[0,60]。

实验配置与结果

实验配置主要是通过Sobel算子进行边缘检测,其中 , 和canny边缘检测中设置两个阈值,通过实验发现,低阈值为60,高阈值为150,实验效果较好。在利用轮廓匹配中的距离变换中,采用最小距离作为度量,通过调整多目标检测的参数,发现参数取1.29效果较好。即认为距离小于1.29倍的最小距离的响应点,认为是螺母。在构建模板金字塔时,考虑到检测图片中出现的螺母大小,采用4层的图像金字塔。同时采用截取两个螺母取平均作为模板(截取模板时注意选择框尽量大小一致)。首先,采用距离变换进行模板的匹配,通过调节参数得到较好的检测结果如下所示

图片一的检测结果:
在这里插入图片描述

图片二的检测结果:
在这里插入图片描述

图片三的检测结果:
在这里插入图片描述
采用图像金字塔构建模板金字塔如下所示:

通过用不同大小的模板对图片中的螺母进行匹配,希望能够检测出不同大小的螺母,以图片1的检测结果如下所示:
在这里插入图片描述

实验结果分析

通过上述实验结果,可以看出采用距离变换选取合适的参数,可以得到较好的检测结果,由于检测场景中存在干扰元素,即存在与螺母相似的物体,因此在进行多目标检测时存在一个困境,就是如果为了检测更多的螺母,进行降低阈值的操作,会导致检测出圆形的非螺母物体,因此就给检测带来较大的困难,而且图片4中的螺母分布较密集,导致检测结果不理想,图片5中将检测场景变得更加复杂,由于图片中存在蝴蝶,而且蝴蝶的翅膀上的斑点与螺母相似,造成很大的检测困难。
实验通过建立模板金字塔,通过不同的模板分别进行检测,可以缓解多目标检测与检测准确度之间的矛盾。通过调节阈值参数,获得一个还可以接受的检测结果。

源代码

#截取螺母模板
Template = cv.imread(filename='01.jpg',flags=cv.IMREAD_UNCHANGED)
Template = cv.resize(Template,(int(Template.shape[1]/2),int(Template.shape[0]/2)))
if Template is None:
    print('opening image failed.')
x,y,w,h = cv.selectROI(Template)
T1 = cv.cvtColor(Template[y:y+h,x:x+w,:],cv.COLOR_BGR2GRAY).astype(np.float32)/255

Sobelx = np.array([[-1,0,1],[-2,0,2],[-1,0,1]],np.float32)
Sobely = Sobelx.T
Gx = cv.filter2D(T1,-1,Sobelx)
Gy = cv.filter2D(T1,-1,Sobely)
M1 = np.sqrt(Gx**2 + Gy**2)


cv.imshow('template',M1)
cv.waitKey(0)
cv.destroyAllWindows()


x,y,w,h = cv.selectROI(Template)
T2 = cv.cvtColor(Template[y:y+h,x:x+w,:],cv.COLOR_BGR2GRAY).astype(np.float32)/255
Gx = cv.filter2D(T2,-1,Sobelx)
Gy = cv.filter2D(T2,-1,Sobely)
M2 = np.sqrt(Gx**2 + Gy**2)
M2 = cv.resize(M2,(M1.shape[1],M1.shape[0]))

cv.imshow('template',M2)
cv.waitKey(0)
cv.destroyAllWindows()

M = M1
cv.addWeighted(M1,0.5,M2,0.5,0.0,M)


plt.figure()
plt.imshow(M,cmap = 'gray')
plt.show()


#对图片进行模板匹配,对每个模板进行匹配,结果放在列表中
frame = cv.imread(filename='01.jpg',flags=cv.IMREAD_UNCHANGED)
frame = cv.resize(frame,(int(frame.shape[1]/2),int(frame.shape[0]/2)))

I = cv.cvtColor(frame,cv.COLOR_BGR2GRAY).astype(np.float32)/255

Sobelx = np.array([[-1,0,1],[-2,0,2],[-1,0,1]],np.float32)
Sobely = Sobelx.T

Gx = cv.filter2D(I,-1,Sobelx)
Gy = cv.filter2D(I,-1,Sobely)
im = np.sqrt(Gx**2 + Gy**2)

cv.imshow('im',cv.resize(im,(700,700)))
cv.waitKey(0)
cv.destroyAllWindows()

im1 = frame.copy()
for line in all_T:
    template = line[0]
    if template.shape[0]>=im.shape[0] or template.shape[1]>=im.shape[1]:
        print("NO detect")
        pass
    else:
        res = matchTemplateOfvarious(im,line)
        cv.imshow('res',cv.resize(res,(700,700)))
        cv.waitKey(0)
        cv.destroyAllWindows()
        #获取最大响应值
        _,max_val,_,_ = cv.minMaxLoc(res)
        print("此大小模板的匹配不同角度的螺母的最大值")
        print(max_val)
        
        if max_val>0.42:
            #对res二值化,二值化阈值选取最大响应的某个比例
            thresh = 0.355
            _,detects = cv.threshold(res,thresh,255,cv.THRESH_BINARY)
            #计算二值化之后的响应图的连通分量
            _,_,_,centroids = cv.connectedComponentsWithStats(detects.astype(np.uint8))

            #获取每个连通分量的质心位置,并根据此获得每个目标的包围盒坐标
            centroids = centroids + [T.shape[1]/2, T.shape[0]/2]
            centroids = np.round(centroids).astype(np.int32)
            top_left = np.round(centroids - [T.shape[1]/2, T.shape[0]/2]).astype(np.int32)
            bot_right = np.round(centroids + [T.shape[1]/2, T.shape[0]/2]).astype(np.int32)

            #在图像上绘制检测到的每一个目标的包围盒
            for l in range(1,centroids.shape[0]):
                cv.rectangle(im1,(top_left[l,0], top_left[l,1]),
                             (bot_right[l,0], bot_right[l,1]),[1,0,0],2)

plt.imshow(im1)
plt.show()
  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值