Python 使用opencv查找包含其他图像的最相似图像
如果标题不清楚,让我们假设我有一个图像列表(10k+),我有一个正在搜索的目标图像 以下是目标图像的示例: 下面是一个我想要搜索的图像示例,以查找“相似”(ex1、ex2和ex3): 以下是我所做的匹配(我使用KAZE) 很好!它能够分辨出ex1是相似的,而ex2是不相似的,但是它表示ex3是相似的(甚至比ex1更相似)。我可以对我的方法做任何额外的预处理或后处理(可能是ml,假设ml实际上是有用的)或只是更改,以保持ex1与ex3相似,而不是ex3 (请注意,我创建的分数是我在网上找到的。不确定这是否是一种准确的方法) 在下面添加了更多示例 另一组例子: 这是我正在寻找的 我希望上面的图像与中间和底部图像相似(注意:我将目标图像旋转45度,并将其与下面的图像进行比较。) 特征匹配(如下面的答案所述)在发现与第二张图像的相似性时很有用,但与第三张图像(即使在正确旋转后)的相似性时却不可用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 (请注意,我创建的分数是我在网上
首先,数据显示在图表中,您不能从数字数据中获得重叠值吗 你有没有尝试过对颜色的变化进行一些边缘检测,从白蓝色到蓝红色,在这些边缘上拟合一些圆,然后检查它们是否重叠
由于输入数据是完全受控的(没有有机摄影或视频),也许您不必走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())
输出:
解释如下:
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)