mik*_*123 5 python opencv machine-learning image-processing image-recognition
如果标题不清楚,假设我有一个图像列表(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()
Run Code Online (Sandbox Code Playgroud)
这是我的代码的结果:
ex1.png 21.052631578947366
ex2.png 0.0
ex3.png 42.10526315789473
Run Code Online (Sandbox Code Playgroud)
没毛病!它能够分辨出 ex1 相似而 ex2 不相似,但是它指出 ex3 相似(甚至比 ex1 更相似)。任何额外的预处理或后处理(可能是 ml,假设 ml 实际上有用)或只是我可以对我的方法做的更改,以便仅保持 ex1 相似而不是 ex3?
(注意我创建的这个分数是我在网上找到的。不确定这是否是一种准确的方法)
在下面添加了更多示例
另一组例子:
这是我正在寻找的
我希望上面的图像与中间和底部的图像相似(注意:我将目标图像旋转 45 度并将其与下面的图像进行比较。)
特征匹配(如下面的答案所述)在发现与第二张图像的相似性方面很有用,但不是第三张图像(即使在正确旋转之后)
您可以使用模板匹配,其中您要检测是否在其他图像中的图像就是模板。我将那个小图像保存在、 中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())
Run Code Online (Sandbox Code Playgroud)
Confidence for img1.png:
0.8906427
Confidence for img2.png:
0.4427919
Confidence for img3.png:
0.5933967
Run Code Online (Sandbox Code Playgroud)
cv2.imread
导入opencv模块,并通过将方法的第二个参数设置为灰度来读入模板图像0
:import cv2
template = cv2.imread("template.png", 0)
Run Code Online (Sandbox Code Playgroud)
files = ["img1.png", "img2.png", "img3.png"]
Run Code Online (Sandbox Code Playgroud)
for name in files:
img = cv2.imread(name, 0)
Run Code Online (Sandbox Code Playgroud)
cv2.matchTemplate
来检测每个图像中的模板。有很多检测方法可以使用,但为此我决定使用以下cv2.TM_CCOEFF_NORMED
方法: print(f"Confidence for {name}:")
print(cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED).max())
Run Code Online (Sandbox Code Playgroud)
该函数的输出范围在0
和之间1
,正如您所看到的,它成功检测到第一张图像最有可能包含模板图像(它具有最高的置信度)。
如果检测哪个图像包含模板还不够,并且您想要可视化,可以尝试以下代码:
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)
Run Code Online (Sandbox Code Playgroud)
import cv2
import numpy as np
Run Code Online (Sandbox Code Playgroud)
cv2.matchTemplate
方法需要灰度图像,因此将2张图像转换为灰度图像:def confidence(img, template):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
template = cv2.cvtColor(template, cv2.COLOR_BGR2GRAY)
Run Code Online (Sandbox Code Playgroud)
cv2.matchTemplate
方法检测图像中的模板,并返回置信度最高的点的位置,返回置信度最高的点: res = cv2.matchTemplate(img, template, cv2.TM_CCOEFF_NORMED)
conf = res.max()
return np.where(res == conf), conf
Run Code Online (Sandbox Code Playgroud)
files = ["img1.png", "img2.png", "img3.png"]
template = cv2.imread("template.png")
Run Code Online (Sandbox Code Playgroud)
h, w, _ = template.shape
Run Code Online (Sandbox Code Playgroud)
confidence
我们之前定义的函数,获取检测到的模板左上角的 xy 位置以及检测的置信度:for name in files:
img = cv2.imread(name)
([y], [x]), conf = confidence(img, template)
Run Code Online (Sandbox Code Playgroud)
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)
Run Code Online (Sandbox Code Playgroud)
cv2.imshow('Template', template)
cv2.waitKey(0)
Run Code Online (Sandbox Code Playgroud)
小智 -2
首先,数据出现在图表中,你不能从它们的数值数据中得到重叠的值吗?
您是否尝试过对从白蓝色到蓝红色的颜色变化进行一些边缘检测,将一些圆圈拟合到这些边缘,然后检查它们是否重叠?
由于输入数据受到严格控制(没有有机摄影或视频),也许您不必走 ML 路线。