【问题标题】:How to improve accuracy of OpenCV matching results in Python如何在 Python 中提高 OpenCV 匹配结果的准确性
【发布时间】:2020-07-25 18:02:34
【问题描述】:

我正在尝试在 Python 3.6 中配置 OpenCV,以将字符图标(模式)1 与字符框 2 匹配。尽管如此,匹配度还是很低,尤其是对于像1 这样的阴影字符。

我尝试通过不仅使用 matchTemplate,还比较直方图来解决它,但是 - 结果仍然很差。

我确实尝试过使用灰度、颜色、仅匹配图片中心(裁剪的脸)、匹配整个图片...调整图案大小以使其具有精确的尺寸,就像它在盒子中一样...所有组合.. . 但这仍然是非常随机的(参见相关结果的附图)

提前感谢您的帮助!

代码如下:

import numpy as np
import cv2 as cv
from PIL import Image
import os

box = Image.open("/Users/user/Desktop/dbz/my_box.jpeg")
box.thumbnail((592,1053))

#conditions for each match step
character_threshold = 0.6 #checks in box
hist_threshold = 0.3

import numpy as np
import cv2 as cv
from PIL import Image
import os

box = Image.open("/Users/user/Desktop/dbz/my_box.jpeg")
box.thumbnail((592,1053))

#conditions for each match step
character_threshold = 0.6
hist_threshold = 0.3

for root, dirs, files in os.walk("/Users/user/Desktop/dbz/img/Super/TEQ/"):
    for file in files:
        if not file.startswith("."):
            print("now "  + file)
            char = os.path.join(root, file)

            #Opens and generate character's icon
            character = Image.open(char)
            character.thumbnail((153,139))
            
            #Crops face from the character's icon and converts to grayscale CV object
            face = character.crop((22,22,94,94)) #size 72x72 with centered face (should be 22,22,94,94)
            face_array = np.array(face).astype(np.uint8)
            face_array_gray = cv.cvtColor(face_array, cv.COLOR_RGB2GRAY)
            
            #Converts the character's icon to grayscale CV object
            character_array = np.array(character).astype(np.uint8)
            character_array_gray = cv.cvtColor(character_array, cv.COLOR_RGB2GRAY)

            #Converts box screen to grayscale CV object
            box_array = np.array(box).astype(np.uint8)
            box_array_gray = cv.cvtColor(box_array, cv.COLOR_RGB2GRAY)
        
            #Check whether the face is in the box
            character_score = cv.matchTemplate(box_array[:,:,2],face_array[:,:,2],cv.TM_CCOEFF_NORMED)
            if character_score.max() > character_threshold:
                ij = np.unravel_index(np.argmax(character_score),character_score.shape)
                x, y = ij[::-1] #np returns lower-left coordinates, whilst PIL accepts upper, left,lower, right !!!
                w, h = face_array_gray.shape
                face.show()           

                found = box.crop((x,y,x+w,y+h)) #expand border to 25 pixels in each size (Best is  (x-20,y-5,x+w,y+h+20))
                #found.show() 

                #found_character = np.array(found_character).astype(np.uint8)
                #found_character = cv.cvtColor(found_character, cv.COLOR_RGB2GRAY)
                    
                found_array = np.array(found).astype(np.uint8)
                found_array_gray = cv.cvtColor(found_array, cv.COLOR_RGB2GRAY)
                    
                found_hist = cv.calcHist([found_array],[0,1,2],None,[8,8,8],[0,256,0,256,0,256])
                found_hist = cv.normalize(found_hist,found_hist).flatten()

                found_hist_gray = cv.calcHist([found_array_gray],[0],None,[8],[0,256])
                found_hist_gray = cv.normalize(found_hist_gray,found_hist_gray).flatten()

                face_hist = cv.calcHist([face_array],[0,1,2],None,[8,8,8],[0,256,0,256,0,256])
                face_hist = cv.normalize(face_hist,face_hist).flatten()

                face_hist_gray = cv.calcHist([face_array_gray],[0],None,[8],[0,256])
                face_hist_gray = cv.normalize(face_hist_gray,face_hist_gray).flatten()

                character_hist = cv.calcHist([character_array],[0,1,2],None,[8,8,8],[0,256,0,256,0,256])
                character_hist = cv.normalize(character_hist,character_hist).flatten()

                character_hist_gray = cv.calcHist([character_array_gray],[0],None,[8],[0,256])
                character_hist_gray = cv.normalize(character_hist_gray,character_hist_gray).flatten()

                hist_compare_result_CORREL = cv.compareHist(found_hist_gray, character_hist_gray,cv.HISTCMP_CORREL)
                #hist_compare_result_CHISQR = cv.compareHist(found_hist_gray, character_hist_gray,cv.HISTCMP_CHISQR)
                #hist_compare_result_INTERSECT = cv.compareHist(found_hist_gray, character_hist_gray,cv.HISTCMP_INTERSECT)
                #hist_compare_result_BHATTACHARYYA = cv.compareHist(found_hist_gray, character_hist_gray,cv.HISTCMP_BHATTACHARYYA)

                if (hist_compare_result_CORREL+character_score.max()) > 1:
                    print(f"Found {file} with a score:\n match:{character_score.max()}\n hist_correl: {hist_compare_result_CORREL}\n SUM:{hist_compare_result_CORREL+character_score.max()}", file=open("/Users/user/Desktop/dbz/out.log","a+"))

(1)

(2)

【问题讨论】:

  • 您是否尝试过在颜色和模板的 Alpha 通道中使用蒙版进行多尺度模板匹配?我注意到您的模板图像比例大于大图中的图标。
  • 嘿,正如您在代码中看到的那样,我确实调整了模板 (character.thumbnail((153,139))) 的大小,因此它的尺寸几乎与图像中的尺寸完全相同。此外,我还尝试仅裁剪“人脸”(character.crop((22,22,94,94)),以防右下角的星号干扰正确答案。多尺度模板匹配?没听到关于它 - 我会搜索它并检查它是否可以在这里使用
  • 在模板匹配中尝试使用来自模板alpha通道的掩码?
  • 啊...所以要按形状匹配。好吧,虽然 alpha 通道不会只返回每个模板的帧吗?
  • 来自 alpha 通道的掩码告诉 matchTemplate 在哪里不包括匹配中的像素。否则,您将匹配 alpha 通道下的任何内容,这可能会降低您的匹配分数,以便所有匹配项都相似。因此,您必须阅读模板以保留 Alpha 通道。然后将alpha通道提取为mask图像,将没有alpha通道的颜色层提取为要匹配的图像。

标签: python python-3.x opencv computer-vision


【解决方案1】:

以下是 Python/OpenCV 中掩码模板匹配的简单示例。

图片:

透明模板:

去除了 alpha 的模板:

模板 alpha 通道提取为蒙版图像:

mport cv2
import numpy as np

# read image
img = cv2.imread('logo.png')

# read template with alpha
tmplt = cv2.imread('hat_alpha.png', cv2.IMREAD_UNCHANGED)
hh, ww = tmplt.shape[:2]

# extract template mask as grayscale from alpha channel and make 3 channels
tmplt_mask = tmplt[:,:,3]
tmplt_mask = cv2.merge([tmplt_mask,tmplt_mask,tmplt_mask])

# extract templt2 without alpha channel from tmplt
tmplt2 = tmplt[:,:,0:3]

# do template matching
corrimg = cv2.matchTemplate(img,tmplt2,cv2.TM_CCORR_NORMED, mask=tmplt_mask)
min_val, max_val, min_loc, max_loc = cv2.minMaxLoc(corrimg)
max_val_ncc = '{:.3f}'.format(max_val)
print("correlation match score: " + max_val_ncc)
xx = max_loc[0]
yy = max_loc[1]
print('xmatch =',xx,'ymatch =',yy)

# draw red bounding box to define match location
result = img.copy()
pt1 = (xx,yy)
pt2 = (xx+ww, yy+hh)
cv2.rectangle(result, pt1, pt2, (0,0,255), 1)

cv2.imshow('image', img)
cv2.imshow('template2', tmplt2)
cv2.imshow('template_mask', tmplt_mask)
cv2.imshow('result', result)
cv2.waitKey(0)
cv2.destroyAllWindows()

# save results
cv2.imwrite('logo_hat_match2.png', result)

输入匹配位置:

比赛信息:

correlation match score: 1.000
xmatch = 417 ymatch = 44

如果没有掩码,模板中的大绿色区域将在输入中不匹配并显着降低匹配分数。

【讨论】:

  • 谢谢!如您所见,我的图片仅在方框中的一个字符上有所不同。我应该裁剪边框并只对面部使用 alpha 匹配吗?
  • 带上口罩,外面无所谓。您最大的问题是将透明模板缩放到与图像中的图标相同的大小。由于每个图标中的黄色星标不在模板中,您将无法获得完美匹配。但是口罩应该会有所帮助。或者您可以使您的模板更加透明以避免与星区匹配。
  • 我对它进行了缩放,尽管如此,这是从我的模板Mask 获得的掩码。不可能在图像中找到它,因为这样的边界无处不在
  • 蒙版形状对匹配没有贡献。它所做的只是告诉 matchTemplate 仅匹配蒙版为白色的模板,并忽略模板中蒙版为黑色的所有像素。更仔细地看我的例子。模板的绿色部分会在图像中的任何地方不匹配。但在使用掩码时会被忽略。
  • 好吧,我明白了。尽管如此,我的示例的匹配非常差 - 0.66,而图像中没有出现的模板达到了 0.85 以上。
猜你喜欢
  • 1970-01-01
  • 2019-04-07
  • 2016-04-02
  • 2019-10-07
  • 2023-04-05
  • 2015-10-22
  • 2013-06-23
  • 2022-01-15
  • 1970-01-01
相关资源
最近更新 更多