如果标题不清楚,让我们假设我有一个图像列表(10k+),我有一个正在搜索的目标图像
以下是目标图像的示例:
下面是一个我想要搜索的图像示例,以查找“相似”(ex1、ex2和ex3):
以下是我所做的匹配(我使用KAZE)
from matplotlib import pyplot as plt
import numpy as np
import cv2
from typing import List
import os
import imutils
def calculate_matches(des1: List[cv2.KeyPoint], des2: List[cv2.KeyPoint]):
"""
does a matching algorithm to match if keypoints 1 and 2 are similar
@param des1: a numpy array of floats that are the descriptors of the keypoints
@param des2: a numpy array of floats that are the descriptors of the keypoints
@return:
"""
# bf matcher with default params
bf = cv2.BFMatcher(cv2.NORM_L2)
matches = bf.knnMatch(des1, des2, k=2)
topResults = []
for m, n in matches:
if m.distance < 0.7 * n.distance:
topResults.append([m])
return topResults
def compare_images_kaze():
cwd = os.getcwd()
target = os.path.join(cwd, 'opencv_target', 'target.png')
images_list = os.listdir('opencv_images')
for image in images_list:
# get my 2 images
img2 = cv2.imread(target)
img1 = cv2.imread(os.path.join(cwd, 'opencv_images', image))
for i in range(0, 360, int(360 / 8)):
# rotate my image by i
img_target_rotation = imutils.rotate_bound(img2, i)
# Initiate KAZE object with default values
kaze = cv2.KAZE_create()
kp1, des1 = kaze.detectAndCompute(img1, None)
kp2, des2 = kaze.detectAndCompute(img2, None)
matches = calculate_matches(des1, des2)
try:
score = 100 * (len(matches) / min(len(kp1), len(kp2)))
except ZeroDivisionError:
score = 0
print(image, score)
img3 = cv2.drawMatchesKnn(img1, kp1, img_target_rotation, kp2, matches,
None, flags=2)
img3 = cv2.cvtColor(img3, cv2.COLOR_BGR2RGB)
plt.imshow(img3)
plt.show()
plt.clf()
if __name__ == '__main__':
compare_images_kaze()
下面是我的代码的结果:
ex1.png 21.052631578947366
ex2.png 0.0
ex3.png 42.10526315789473
很好!它能够分辨出ex1是相似的,而ex2是不相似的,但是它表示ex3是相似的(甚至比ex1更相似)。我可以对我的方法做任何额外的预处理或后处理(可能是ml,假设ml实际上是有用的)或只是更改,以保持ex1与ex3相似,而不是ex3
(请注意,我创建的分数是我在网上找到的。不确定这是否是一种准确的方法)
在下面添加了更多示例
另一组例子:
这是我正在寻找的
我希望上面的图像与中间和底部图像相似(注意:我将目标图像旋转45度,并将其与下面的图像进行比较。)
特征匹配(如下面的答案所述)在发现与第二张图像的相似性时很有用,但与第三张图像(即使在正确旋转后)的相似性时却不可用
我不确定,如果给定的图像与您的实际任务或数据相似,但是对于这种图像,您可以尝试简单的模板匹配,参见this OpenCV tutorial
基本上,我只是对教程进行了一些修改:
结果如下:
编辑:为了强调来自不同颜色的信息,可以使用来自HSV color space的色调通道进行模板匹配:
新结果:
检测最相似的图像
代码
您可以使用template matching,其中要检测是否在其他图像中的图像是模板。我在{}中保存了那个小图像,在{}、{}和{}中保存了其他三个图像
我定义了一个函数,它利用
cv2.matchTemplate
来计算模板是否在图像中的置信度。在每个图像上使用该函数,可获得最高置信度的图像是包含模板的图像:输出:
解释:
cv2.imread
方法的第二个参数设置为0
,以灰度形式读取模板图像:cv2.matchTemplate
来检测每个图像中的模板。有many detection methods可以使用,但为此,我决定使用cv2.TM_CCOEFF_NORMED
方法:函数的输出范围介于
0
和1
之间,如您所见,它成功地检测到第一个图像最有可能包含模板图像(其置信度最高)可视化
代码
如果仅检测包含模板的图像是不够的,并且需要可视化,可以尝试以下代码:
输出:
解释:
cv2.matchTemplate
方法需要灰度图像,请将这两幅图像转换为灰度:cv2.matchTemplate
方法检测图像中的模板,并返回具有最高置信度的点的位置,然后返回最高置信度:confidence
函数,获取检测到的模板左上角的x-y位置和检测的置信度:概念
我们可以使用
cv2.matchTemplate
方法来检测图像在另一个图像中的位置,但是对于第二组图像,您可以进行旋转。此外,我们还需要考虑颜色cv2.matchTemplate
将接收图像、模板(另一个图像)和模板检测方法,并将返回灰度数组,其中灰度数组中最亮的点将是模板在该点处最有把握的点我们可以在4个不同的角度使用模板,并使用产生最高置信度的模板。当我们检测到与模板匹配的可能点时,我们使用函数(我们将自己定义)来检查模板中最常见的颜色是否出现在我们检测到的图像中。如果不是,则忽略补丁,不管返回的可信度如何
代码
输出
解释
frequent_colors
,它将接收图像并返回图像中最常见的颜色。可选参数val
是返回多少颜色;如果val
是3
,则将返回3种最常见的颜色:get_templates
,该函数将接收图像,并以4个不同角度(原始、顺时针90、180和逆时针90)生成图像(灰度):detect
,它将接收图像和模板图像,并返回图像上检测到的模板的边界框的x、y、w、h,对于这个函数,我们将使用前面定义的frequent_colors
和get_templates
函数。min_conf
参数将是将检测分类为实际检测所需的最小置信度:colors
中。另外,定义主图像的灰度版本:cv2.matchTemplate
方法获得图像上检测到的模板的灰度数组:conf_min
的检测模板的x,y坐标中循环,并将置信度存储在变量conf
中。如果conf
大于初始最大置信变量(conf_max
),则继续检测模板中所有三种最常见的颜色是否都存在于图像的补丁中:0, 0, 0, 0
:detect
函数获取边界框的x、y、w、h。使用cv2.rectangle
方法在图像上绘制边界框:相关问题 更多 >
编程相关推荐