Цель
В этой главе,
- Мы увидим, как сопоставить функции одного изображения с другими изображениями.
- Мы будем использовать сопоставитель грубой силы и сопоставитель FLANN в OpenCV.
Основы сопоставления грубой силы
Сопоставители грубой силы просты. Он берет дескриптор одной из функций в первом наборе и сопоставляет его со всеми другими функциями во втором наборе, используя некоторые вычисления расстояния. и возвращает ближайший.
Для сопоставления BF сначала мы должны использоватьcv.BFMatcher() для создания объекта BFMatcher. Он принимает два необязательных параметра. Первый — normType, который определяет используемое измерение расстояния. По умолчанию этоcv.NORM_L2
. Для SIFT, SURF и т. д. (такжеcv.NORM_L1
)Очень полезно. Для дескрипторов на основе двоичных строк, таких как ORB, BRIEF, BRISK и т. д., вы должны использоватьcv.NORM_HAMMING
, который использует расстояние Хэмминга в качестве метрики. Если используется ОРБWTA_K == 3
или4
, вы должны использоватьcv.NORM_HAMMING2.
Второй параметр — это логическая переменная crossCheck, которая по умолчанию имеет значение false. Если true, Matcher возвращает только те совпадения со значениями (i, j), что i-й дескриптор в наборе A имеет j-й дескриптор в наборе B как наилучшее совпадение, и наоборот. т. е. две функции в двух наборах должны совпадать друг с другом. Он обеспечивает стабильные результаты и является хорошей альтернативой тесту отношений, предложенному Д. Лоу в статье SIFT.
После создания два важных методаBFMatcher.match()иBFMatcher.knnMatch( ). Первый возвращает лучшее совпадение. Второй метод возвращает k лучших совпадений, где k задается пользователем. Это может быть полезно, когда нам нужно выполнить другую работу над этим.
как мы используемcv.drawKeypoints() рисует ключевые моменты, такие как,cv.drawMatches() может помочь нам провести спички. Он укладывает два изображения по горизонтали и рисует линию от первого изображения ко второму, чтобы показать наилучшее совпадение. иcv.drawMatchesKnnНарисуйте все k лучших совпадений. еслиk=2
, который нарисует две совпадающие линии для каждой ключевой точки. Поэтому, если вы хотите рисовать выборочно, вам нужно передать маску.
Давайте рассмотрим пример SIFT и ORB (оба используют разные меры расстояния).
Сопоставление методом грубой силы с использованием дескрипторов ORB
Здесь мы увидим простой пример того, как сопоставить функции между двумя изображениями. В этом случае у меня есть queryImage и trainImage. Мы попытаемся найти queryImage в trainImage, используя сопоставление признаков. (изображения /samples/data/box.png и /samples/data/boxinсцена.png)
Мы используем дескрипторы ORB для сопоставления функций. Итак, давайте начнем с загрузки изображений, поиска дескрипторов и т.д.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE) # 索引图像
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # 训练图像
# 初始化ORB检测器
orb = cv.ORB_create()
# 基于ORB找到关键点和检测器
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
Затем мы создаем меру расстоянияcv.NORM_HAMMINGОбъект BFMatcher (поскольку мы используем ORB) с включенным CrossCheck для лучших результатов. Затем мы используем метод Matcher.match(), чтобы получить наилучшее соответствие между двумя изображениями. Мы сортируем их в порядке возрастания расстояния, чтобы лучшие совпадения (малые расстояния) шли первыми. Потом вытаскиваем только топ 10 совпадений (просто для наглядности. При желании можно увеличить)
# 创建BF匹配器的对象
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True) # 匹配描述符.
matches = bf.match(des1,des2) # 根据距离排序
matches = sorted(matches, key = lambda x:x.distance) # 绘制前10的匹配项
img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) plt.imshow(img3),plt.show()
Будут получены следующие результаты:
Что такое объект Matcher?
matchs = bf.match(des1,des2)
Результатом строки является список объектов DMatch. Объект DMatch имеет следующие свойства:
- DMatch.distance - расстояние между дескрипторами. Чем ниже, тем лучше.
- DMatch.trainIdx — индекс дескриптора в дескрипторе поезда
- DMatch.queryIdx — индекс дескриптора в дескрипторе запроса
- DMatch.imgIdx - индекс изображения поезда.
Сопоставление методом грубой силы с дескриптором SIFT и тестом масштабирования
На этот раз мы будем использовать BFMatcher.knnMatch(), чтобы получить k лучших совпадений. В этом примере мы положим k = 2, чтобы можно было применить критерий пропорциональности, разработанный Д. Лоу в его статье.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE) # 索引图像
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # 训练图像
# 初始化SIFT描述符
sift = cv.xfeatures2d.SIFT_create()
# 基于SIFT找到关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# 默认参数初始化BF匹配器
bf = cv.BFMatcher()
matches = bf.knnMatch(des1,des2,k=2)
# 应用比例测试
good = []
for m,n in matches:
if m.distance < 0.75*n.distance:
good.append([m])
# cv.drawMatchesKnn将列表作为匹配项。
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3),plt.show()
Проверьте результаты ниже:
FLANN на основе сопоставления
FLANN — это быстрая библиотека для приближенных ближайших соседей. Он содержит набор алгоритмов, оптимизированных для быстрого поиска ближайших соседей и многомерных признаков в больших наборах данных. Он работает быстрее, чем BFMatcher для больших наборов данных. Мы увидим второй пример сопоставления на основе FLANN.
Для сопоставителей на основе FLANN нам нужно передать два словаря, которые определяют используемый алгоритм, связанные с ним параметры и т. д. Первый — это IndexParams. Для различных алгоритмов передаваемая информация объясняется в документации FLANN. Напомним, что для таких алгоритмов, как SIFT, SURF и т. д., вы можете сделать следующее:
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
При использовании ORB вы можете ссылаться на следующее. Аннотированные значения предлагаются в соответствии с документацией, но в некоторых случаях обязательные параметры не указываются. Другие значения также работают нормально.
FLANN_INDEX_LSH = 6
index_params= dict(algorithm = FLANN_INDEX_LSH,
table_number = 6, # 12
key_size = 12, # 20
multi_probe_level = 1) #2
Второй словарь — SearchParams. Он указывает, сколько раз дерево в индексе должно быть рекурсивно пройдено. Более высокие значения обеспечивают лучшую точность, но также занимают больше времени. Если вы хотите изменить значение, передайтеsearch_params = dict(checks = 100)
С этой информацией нам легко.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE) # 索引图像
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # 训练图像
# 初始化SIFT描述符
sift = cv.xfeatures2d.SIFT_create()
# 基于SIFT找到关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# FLANN的参数
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50) # 或传递一个空字典
flann = cv.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# 只需要绘制好匹配项,因此创建一个掩码
matchesMask = [[0,0] for i in range(len(matches))]
# 根据Lowe的论文进行比例测试
for i,(m,n) in enumerate(matches):
if m.distance < 0.7*n.distance:
matchesMask[i]=[1,0]
draw_params = dict(matchColor = (0,255,0),
singlePointColor = (255,0,0),
matchesMask = matchesMask,
flags = cv.DrawMatchesFlags_DEFAULT)
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)
plt.imshow(img3,),plt.show()
Проверьте результаты ниже:
Сводная станция блога о технологиях искусственного интеллекта Panchuang: http://docs.panchuang.net/PyTorch, официальная китайская учебная станция: http://pytorch.panchuang.net/OpenCV, официальный китайский документ: http://woshicver.com/