OpenCV Python中的图像匹配

3 投票
2 回答
6604 浏览
提问于 2025-04-17 22:48

我正在做一个项目,目的是用opencv python识别摄像头拍到的旗帜。

我已经尝试过使用surf、颜色直方图匹配和模板匹配这三种方法。但是这三种方法并不总是能给出正确的结果。现在我想知道,针对我的这个问题,最好的解决方案是什么。

下面是一些模板图像的例子:

image![][1]

enter image description here

这里是摄像头拍到的旗帜的例子。

enter image description here

如果我想识别这种类型的图像,我应该使用什么方法呢?

更新matchTemplate的代码

    flags=["Cambodia.jpg","Laos.jpg","Malaysia.jpg","Myanmar.jpg","Philippines.jpg","Singapore.jpg","Thailand.jpg","Vietnam.jpg","Indonesia.jpg","Brunei.jpg"]   

    while True:
           methods = 'cv2.TM_CCOEFF_NORMED'
           list_of_pics=[]
           for flag in flags:
                   template= cv2.imread(flag,0)
                   img = cv2.imread('philippines2.jpg',0)

    # generate Gaussian pyramid for A
                    G = template.copy()
                    gpA = [G]
                    for i in xrange(6):
                            G = cv2.pyrDown(G)
                            gpA.append(G)


                    n=0
                    for x in gpA:       

                           w, h = x.shape[::-1]


                           method = eval(methods)#

            # Apply template Match
                          res = cv2.matchTemplate(img,x,method)
                          matchVal=res[0][0]
                          picDict={"matchVal":matchVal,"name":flag}
                          list_of_pics.append(picDict)

                           n=n+1
        newlist = sorted(list_of_pics, key=operator.itemgetter('matchVal'),reverse=True) 
#print newlist
        matched_image=newlist[0]['name']
print matched_image
k=cv2.waitKey(10)
if (k==27):
    break
cv2.destroyAllWindows()

2 个回答

2

SURF算法不能用在那些没有角落的图像上,比如说像条纹旗帜那样,图像的颜色变化主要是单一方向的。对于整个物体的颜色直方图可能不太有效,因为你给出的两个例子颜色很相似。不过,如果你能把图像的不同部分分别做直方图,那效果会更好。

你需要做的是把你的训练图像分成四个部分,然后为这四个部分各自创建一个颜色直方图。在测试阶段,你会把这四个直方图结合起来,检查它们的空间顺序是否正确。颜色直方图对旋转、缩放和透视变化都比较耐受,但它会随着光照的变化而改变,所以你需要设置比较宽松的匹配标准。将图像分成四个部分可以帮助改善这种情况。

未来我建议你更详细地研究这些方法,以便理解它们的适用性,而不是随便尝试。

4

我觉得用SURF/SIFT来获取好结果可能不太行,因为:

  • SURF/SIFT需要关键点来检测物体,但在你的情况下,你需要检测的是旗帜,而大多数旗帜的图案比较单一,关键点不多。

  • 在你的摄像头画面中,不只有旗帜,还有其他东西。这些东西也会影响关键点的获取。

解决方案:我还是觉得你应该使用matchTemplate(),这是你已经尝试过的。不过你在使用时没有考虑到matchTemplate()不具备缩放和方向不变性。所以,解决办法是使用Gaussian pyramid,制作不同大小(比如一半、四分之一、两倍等)的样本旗帜。在获得同一面旗帜的2到5种不同大小后,你应该在每种旗帜大小和摄像头画面之间执行matchTemplate()

策略:

  • 获取摄像头画面。

  • 加载一张旗帜的图片。

  • 使用高斯金字塔,创建该旗帜的更小和更大的图片(你不需要保存这些图片)。

  • 在摄像头画面和每种大小的旗帜之间执行matchTemplate()

  • 结果是:与哪个图像的相关值最大,哪个就是你摄像头中出现的旗帜。

记住:matchTemplate不具备缩放和方向不变性。所以,如果你在摄像头画面中旋转图像或改变它的大小,你可能得不到好的结果。

撰写回答