Python 使用opencv查找包含其他图像的最相似图像

Python 使用opencv查找包含其他图像的最相似图像,python,opencv,machine-learning,image-processing,image-recognition,Python,Opencv,Machine Learning,Image Processing,Image Recognition,如果标题不清楚,让我们假设我有一个图像列表(10k+),我有一个正在搜索的目标图像 以下是目标图像的示例: 下面是一个我想要搜索的图像示例,以查找“相似”(ex1、ex2和ex3): 以下是我所做的匹配(我使用KAZE) 很好!它能够分辨出ex1是相似的,而ex2是不相似的,但是它表示ex3是相似的(甚至比ex1更相似)。我可以对我的方法做任何额外的预处理或后处理(可能是ml,假设ml实际上是有用的)或只是更改,以保持ex1与ex3相似,而不是ex3 (请注意,我创建的分数是我在网上

如果标题不清楚,让我们假设我有一个图像列表(10k+),我有一个正在搜索的目标图像

以下是目标图像的示例:

下面是一个我想要搜索的图像示例,以查找“相似”(ex1、ex2和ex3):

以下是我所做的匹配(我使用KAZE)

很好!它能够分辨出ex1是相似的,而ex2是不相似的,但是它表示ex3是相似的(甚至比ex1更相似)。我可以对我的方法做任何额外的预处理或后处理(可能是ml,假设ml实际上是有用的)或只是更改,以保持ex1与ex3相似,而不是ex3

(请注意,我创建的分数是我在网上找到的。不确定这是否是一种准确的方法)

在下面添加了更多示例

另一组例子:

这是我正在寻找的

我希望上面的图像与中间和底部图像相似(注意:我将目标图像旋转45度,并将其与下面的图像进行比较。)

特征匹配(如下面的答案所述)在发现与第二张图像的相似性时很有用,但与第三张图像(即使在正确旋转后)的相似性时却不可用


首先,数据显示在图表中,您不能从数字数据中获得重叠值吗

你有没有尝试过对颜色的变化进行一些边缘检测,从白蓝色到蓝红色,在这些边缘上拟合一些圆,然后检查它们是否重叠


由于输入数据是完全受控的(没有有机摄影或视频),也许您不必走ML路线。

我不确定给定的图像是否与您的实际任务或数据相似,但对于此类图像,您可以尝试简单的模板匹配,cf

基本上,我只是对教程进行了一些修改:

导入cv2
将matplotlib.pyplot作为plt导入
#阅读图像
示例=[ex1.png'、[ex2.png'、[ex3.png']中img的cv2.imread(img)]
target=cv2.imread('target.png')
h、 w=目标形状[:2]
#迭代示例
对于i,枚举中的img(示例):
#模板匹配
#比照。https://docs.opencv.org/4.5.2/d4/dc6/tutorial_py_template_matching.html
res=cv2.matchTemplate(img,target,cv2.TM\u CCOEFF\u NORMED)
#获取最大值的位置
_,max_val,u,top_left=cv2.minMaxLoc(res)
#设置是否找到决策目标的阈值
thr=0.7
如果最大值>thr:
#在示例中显示找到的目标
右下=(左上[0]+w,左上[1]+h)
cv2.矩形(img,左上角,右下角,(0,255,0),2)
#形象化
plt.图(i,figsize=(10,5))
plt.subplot(1,2,1),plt.imshow(img[…,[2,1,0]]),plt.title('示例')
plt.subplot(1,2,2),plt.imshow(res,vmin=0,vmax=1,cmap='gray')
plt.title('匹配结果'),plt.colorbar(),plt.tight_布局()
plt.show()
结果如下:

----------------------------------------
系统信息
----------------------------------------
平台:Windows-10-10.0.16299-SP0
Python:3.9.1
PyCharm:2021.1.1
Matplotlib:3.4.1
OpenCV:4.5.1
----------------------------------------

编辑:为了强调来自不同颜色的信息,可以使用来自的色调通道进行模板匹配:

导入cv2
将matplotlib.pyplot作为plt导入
#阅读图像
示例=[
[cv2.imread(img)用于['ex1.png','ex2.png','ex3.png']中的img,
[cv2.imread(img)用于['ex12.png'、'ex22.png'、'ex32.png']中的img]
]
目标=[
cv2.imread('target.png'),
cv2.imread('target2.png')
]
#迭代示例和目标
对于枚举(zip(示例,目标))中的i(ex,target):
对于j,枚举中的img(ex):
#从第二个数据集中旋转最后一个图像
如果(i==1)和(j==2):
img=cv2.旋转(img,cv2.顺时针旋转90°)
h、 w=目标形状[:2]
#从HSV颜色空间获取色调通道
target_h=cv2.cvt颜色(target,cv2.COLOR_BGR2HSV)[……,0]
img_h=cv2.cvt颜色(img,cv2.COLOR_BGR2HSV)[……,0]
#模板匹配
#比照。https://docs.opencv.org/4.5.2/d4/dc6/tutorial_py_template_matching.html
res=cv2.matchTemplate(img_h,target_h,cv2.TM_cceff_NORMED)
#获取最大值的位置
_,max_val,u,top_left=cv2.minMaxLoc(res)
#设置是否找到决策目标的阈值
thr=0.6
如果最大值>thr:
#在示例中显示找到的目标
右下=(左上[0]+w,左上[1]+h)
cv2.矩形(img,左上角,右下角,(0,255,0),2)
#形象化
plt.图(i*10+j,figsize=(10,5))
plt.subplot(1,2,1),plt.imshow(img[…,[2,1,0]]),plt.title('示例')
plt.subplot(1,2,2),plt.imshow(res,vmin=0,vmax=1,cmap='gray')
plt.title('匹配结果'),plt.colorbar(),plt.tight_布局()
plt.savefig(“{}.png.”格式(i*10+j))
plt.show()
新结果:

检测最相似的图像 代码 您可以使用,其中要检测是否在其他图像中的图像是模板。我把那个小图像保存在
template.png
中,另外三个图像保存在
img1.png
img2.png
img3.png

我定义了一个函数,它利用
cv2.matchTemplate
计算模板是否在图像中的置信度。在每个图像上使用该函数,可获得最高置信度的图像是包含模板的图像:

import cv2

template = cv2.imread("template.png", 0)
files = ["img1.png", "img2.png", "img3.png"]

for name in files:
    img = cv2.imread(name, 0)
    print(f"Confidence for {name}:")
    print(cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED).max())
输出: 解释如下:
  • 导入opencv模块,并以灰度b的形式读取模板图像
    ex1.png 21.052631578947366
    ex2.png 0.0
    ex3.png 42.10526315789473
    
    import cv2
    
    template = cv2.imread("template.png", 0)
    files = ["img1.png", "img2.png", "img3.png"]
    
    for name in files:
        img = cv2.imread(name, 0)
        print(f"Confidence for {name}:")
        print(cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED).max())
    
    Confidence for img1.png:
    0.8906427
    Confidence for img2.png:
    0.4427919
    Confidence for img3.png:
    0.5933967
    
    import cv2
    
    template = cv2.imread("template.png", 0)
    
    files = ["img1.png", "img2.png", "img3.png"]
    
    for name in files:
        img = cv2.imread(name, 0)
    
        print(f"Confidence for {name}:")
        print(cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED).max())
    
    import cv2
    import numpy as np
    
    def confidence(img, template):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
        res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
        conf = res.max()
        return np.where(res == conf), conf
    
    files = ["img1.png", "img2.png", "img3.png"]
    
    template = cv2.imread("template.png")
    h, w, _ = template.shape
    
    for name in files:
        img = cv2.imread(name)
        ([y], [x]), conf = confidence(img, template)
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        text = f'Confidence: {round(float(conf), 2)}'
        cv2.putText(img, text, (x, y), 1, cv2.FONT_HERSHEY_PLAIN, (0, 0, 0), 2)
        cv2.imshow(name, img)
        
    cv2.imshow('Template', template)
    cv2.waitKey(0)
    
    import cv2
    import numpy as np
    
    def confidence(img, template):
        img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
    
        res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
        conf = res.max()
        return np.where(res == conf), conf
    
    files = ["img1.png", "img2.png", "img3.png"]
    template = cv2.imread("template.png")
    
    h, w, _ = template.shape
    
    for name in files:
        img = cv2.imread(name)
        ([y], [x]), conf = confidence(img, template)
    
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        text = f'Confidence: {round(float(conf), 2)}'
        cv2.putText(img, text, (x, y), 1, cv2.FONT_HERSHEY_PLAIN, (0, 0, 0), 2)
        cv2.imshow(name, img)
    
    cv2.imshow('Template', template)
    cv2.waitKey(0)
    
    import cv2
    import numpy as np
    
    def frequent_colors(img, vals=3):
        colors, count = np.unique(np.vstack(img), return_counts=True, axis=0)
        sorted_by_freq = colors[np.argsort(count)]
        return sorted_by_freq[-vals:]
    
    def get_templates(img):
        template = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        for i in range(3):
            yield cv2.rotate(template, i)
            
    def detect(img, template, min_conf=0.45):
        colors = frequent_colors(template)
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        conf_max = min_conf
        shape = 0, 0, 0, 0
        for tmp in get_templates(template):
            h, w = tmp.shape
            res = cv2.matchTemplate(img_gray, tmp, cv2.TM_CCOEFF_NORMED)
            for y, x in zip(*np.where(res > conf_max)):
                conf = res[y, x]
                if conf > conf_max:
                    seg = img[y:y + h, x:x + w]
                    if all(np.any(np.all(seg == color, -1)) for color in colors):
                        conf_max = conf
                        shape = x, y, w, h
        return shape
    
    files = ["img1_2.png", "img2_2.png", "img3_2.png"]
    template = cv2.imread("template2.png")
    
    for name in files:
        img = cv2.imread(name)
        x, y, w, h = detect(img, template)
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.imshow(name, img)
    
    cv2.imshow('Template', template)
    cv2.waitKey(0)
    
    import cv2
    import numpy as np
    
    def frequent_colors(img, vals=3):
        colors, count = np.unique(np.vstack(img), return_counts=True, axis=0)
        sorted_by_freq = colors[np.argsort(count)]
        return sorted_by_freq[-vals:]
    
    def get_templates(img):
        template = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
        for i in range(3):
            yield cv2.rotate(template, i)
    
    def detect(img, template, min_conf=0.45):
    
        colors = frequent_colors(template)
        img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
        conf_max = min_conf
        shape = 0, 0, 0, 0
    
        for tmp in get_templates(template):
            h, w = tmp.shape
            res = cv2.matchTemplate(img_gray, tmp, cv2.TM_CCOEFF_NORMED)
    
            for y, x in zip(*np.where(res > conf_max)):
                conf = res[y, x]
                if conf > conf_max:
                    seg = img[y:y + h, x:x + w]
                    if all(np.any(np.all(seg == color, -1)) for color in colors):
                        conf_max = conf
                        shape = x, y, w, h
    
        return shape
    
    files = ["img1_2.png", "img2_2.png", "img3_2.png"]
    template = cv2.imread("template2.png")
    
    for name in files:
        img = cv2.imread(name)
        x, y, w, h = detect(img, template)
        cv2.rectangle(img, (x, y), (x + w, y + h), (0, 0, 255), 2)
        cv2.imshow(name, img)
    
    cv2.imshow('Template', template)
    cv2.waitKey(0)