首页 > 解决方案 > 与 Python 3.9.1、opencv.python 4.5.1.48 和掩码匹配的模板(透明度)

问题描述

自 2J 以来,我遇到了与这个问题相同的问题,但没有一个答案适用于 Python 3,所以今天我花了一整天的时间来解决这个问题: python opencv cv2 matchTemplate with transparent (graphics from the question) 我终于设法写了一个 cv2.matchTemplate() 带有掩码(透明度/alpha通道)和python(3.9.1)和opencv-python(4.5.1.48)。

问题是我像在 Python 2 中一样将掩码作为 RGBA(RGB 为零)传递,并且始终找到 (0,0) 作为位置,因为结果的所有值始终为零。然后,当我尝试仅通过 alpha 通道时,它按预期工作!因为我没有找到任何关于 Python 3 的话题,所以我写了一个新问题,希望得到一些改进的建议。我在我的代码中编写了两个函数,一个是传统上只能找到一个位置 ( findImgLoc())。另一个 ( findImgTresh()) 获取值高于阈值的所有坐标。这两个函数都标准化 (0 - 1) 所有方法并反转 SQDIFF 和 SQDIFF NORMED 的结果,所以你只得到坐标,或者在第二种情况下得到坐标列表,我认为这对初学者更友好。为了测试我有一个test()函数获取cmd输出中的输出图形和信息。 仅仅因为我在旧答案中一遍又一遍地阅读这个,掩码适用于所有匹配方法的代码,不仅适用于 TM_SQDIFF 和 TM_CCORR_NORMED!

图片

源图像

模板

模板图像

没有掩码的结果 findImgTresh()带有SQDIFF_NORMEDund thres=.95-> 4 个位置

输出: [[15, 123], [15, 124], [15, 165], [15, 166]]

不带面具的结果

带有掩码的结果 findImgTresh()带有SQDIFF_NORMEDund thres=.95-> 2 个位置

输出: [[15, 123], [15, 165]]

带面具的结果

图像上没有蒙版的结果

图像上没有蒙版的结果

图像上带有蒙版的结果

图像上带有蒙版的结果

代码

import numpy as np


# Method: 0: SQDIFF | 1: SQDIFF NORMED | 2: TM CCORR | 3: TM CCORR NORMED | 4: TM COEFF | 5: TM COEFF NORMED
img_path = "/Path/to/your/file/source_image_name.png"
tem_path = "/Path/to/your/file/template_image_name.png"


def findImgLoc(image_path, template_path, mask=False, method=1):
    img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)
    tem = cv2.imread(tem_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)

    # Match template with and without mask
    if mask and img.shape[2] == 4:
        alpha_channel = np.array(cv2.split(tem)[3])
        result = cv2.matchTemplate(img, tem, method, mask=alpha_channel)

    else:
        result = cv2.matchTemplate(img, tem, method)

    # Nomrmalize result data to percent (0-1)
    result = cv2.normalize(result, None, 0, 1, cv2.NORM_MINMAX, -1)

    # Invert Image to work similar across all methods!
    if method == 0 or method == 1: result = (1 - result)
    _minVal, _maxVal, minLoc, maxLoc = cv2.minMaxLoc(result, None)

    matchLoc = maxLoc

    # Make the Result viewable
    # view_result = cv2.normalize(result, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    cv2.rectangle(result, matchLoc, (matchLoc[0] + tem.shape[0], matchLoc[1] + tem.shape[1]), (255,0,0), 2)

    return matchLoc

def findImgthres(image_path, template_path, mask=False, method=1, thres=.95):
    img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)
    tem = cv2.imread(tem_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)

    # Match template with and without mask
    if mask and img.shape[2] == 4:
        alpha_channel = np.array(cv2.split(tem)[3])
        result = cv2.matchTemplate(img, tem, method, mask=alpha_channel)

    else:
        result = cv2.matchTemplate(img, tem, method)

    # Nomrmalize result data to percent (0-1)
    result = cv2.normalize(result, None, 0, 1, cv2.NORM_MINMAX, -1)
    
    # Invert Image to work similar across all methods!
    if method == 0 or method == 1: result = (1 - result)

    result_list = np.argwhere(result > thres)

    return result_list

def test():
    global img_path, tem_path
    mT = MatchTemplate()

    def findImgthres(image_path, template_path, mask=False, method=1, thres=.95):
        img = cv2.imread(img_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)
        tem = cv2.imread(tem_path, cv2.IMREAD_UNCHANGED) # cv2.IMREAD_COLOR (cv2.IMREAD_UNCHANGED)

        # Match template with and without mask
        if mask and img.shape[2] == 4:
            alpha_channel = np.array(cv2.split(tem)[3])
            result = cv2.matchTemplate(img, tem, method, mask=alpha_channel)

        else:
            result = cv2.matchTemplate(img, tem, method)

        # Nomrmalize result data to percent (0-1)
        result = cv2.normalize(result, None, 0, 1, cv2.NORM_MINMAX, -1)
        
        # Invert Image to work similar across all methods!
        if method == 0 or method == 1: result = (1 - result)

        result_list = np.argwhere(result > thres)

        return result, result_list

    tmp_source = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
    tmp_mask_source = cv2.imread(img_path, cv2.IMREAD_UNCHANGED)
    tmp_tem = cv2.imread(tem_path, cv2.IMREAD_UNCHANGED)
    result = findImgthres(img_path, tem_path)
    mask_result = findImgthres(img_path, tem_path, mask=True)

    # Mark original Image with mask
    matchLoc = mask_result[1]
    if matchLoc is not None:
        for loc in matchLoc:
            cv2.rectangle(tmp_mask_source, tuple(loc)[::-1], (loc[1] + tmp_tem.shape[1], loc[0] + tmp_tem.shape[0]), (0,0,0), 1)

    # Mark original Image without mask
    matchLoc = result[1]
    if matchLoc is not None:
        for loc in matchLoc:
            cv2.rectangle(tmp_source, tuple(loc)[::-1], (loc[1] + tmp_tem.shape[1], loc[0] + tmp_tem.shape[0]), (0,0,0), 1)

    # Save Images
    _dir = os.path.dirname(__file__)
    cv2.imwrite(os.path.join(_dir, "source.png") , tmp_source)
    cv2.imwrite(os.path.join(_dir, "mask_source.png") , tmp_mask_source)
    cv2.imwrite(os.path.join(_dir, "result.png") , 255*result[0])
    cv2.imwrite(os.path.join(_dir, "mask_result.png") , 255*mask_result[0])

    # Output Result
    print(f"[NO MASK] Match Locs: {result[1]}")
    print(f"[MASK] Match Locs: {mask_result[1]}")


if __name__ == "__main__":
    test()

我希望我能提供进一步的帮助,并对改进建议感到高兴!

标签: python-3.xopencvtransparencymasktemplate-matching

解决方案


推荐阅读