Как фильтровать совпадения ключевых точек в OpenCV?

#python #opencv #computer-vision #cv2

#python #opencv #компьютерное зрение #cv2

Вопрос:

Недавно я начал разбираться с OpenCV, и теперь я пытаюсь реализовать проверку изображения шаблона в другом изображении.
Проблема сейчас в том, что программа сопоставления находит хорошие совпадения для ключевых точек, но не учитывает их расположение относительно друг друга.

Например: шаблон был найден правильно
шаблона нет на картинке, но он все равно найденВ обоих случаях программа сопоставления обнаружила совпадения ключевых точек и сделала это правильно, но во втором случае совпадения были найдены в разных местах на картинке. Я хотел бы обработать эту ситуацию как «шаблон не найден», предпочтительно с помощью встроенных функций OpenCV.

Функция для сравнения ключевых точек:

 def keypoint_match(pic, pattern, pic_desc, pattern_desc, drawDebug=False):
    bf = cv2.BFMatcher()
    matches = bf.knnMatch(pattern_desc[1], pic_desc[1], k=2)

    good = []
    for m, n in matches:
        if (m.distance < 0.75 * n.distance):
            good.append(m)

    print('Good matches:', len(good))
    find = True if len(good) > 10 else False

    if drawDebug or find:
        image = cv2.drawMatches(np.uint8(pattern), pattern_desc[0], np.uint8(pic), pic_desc[0], good, 0,
                                flags=0, matchColor=(0, 255, 0), singlePointColor=(255, 0, 0))
        plt.figure(figsize=(20, 20))
        plt.axis('off')
        plt.imshow(image.astype(np.uint8))
        plt.show()
    return good, find
  

Результат:

 test1.png
Good matches: 32
Pattern found: 'smile.png'
Result: pattern found

test2.png
Good matches: 25
Pattern found: 'smile.png'
Result: pattern found
  

Тестовые картинки и полный исходный код я загрузил здесь.

UPD:
Насколько я знаю, существует 3 метода поиска объекта на изображении:

  • Сопоставление шаблонов
  • Обнаружение ключевых точек
  • Обнаружение контура

Моя задача — выяснить, есть ли определенная эмблема на картинке или нет. Эмблема на картинке может быть слегка наклонена или иметь другой масштаб. Цвет фона изображения также может отличаться, например, если это фотография. Как правило, эмблемы имеют сложную структуру, но они имеют примерно одинаковые контуры.
Вот почему я выбрал метод «Обнаружения ключевых точек».
Я добавил 2 фотографии для теста.
Проблема в том, что есть частичные совпадения, и я хотел бы их исключить, но я не знаю как. Изображения представлены только для демонстрации проблемы частичных совпадений.

шаблон был найден правильно на фотографии
шаблона нет на фотографии, но он все равно найден

Ответ №1:

Отказ от ответственности:

Если я правильно понимаю, что это ситуация с печально известной XY-проблемой и что вы действительно хотите найти изображение улыбки на последующих двух тестовых изображениях, независимо от того, какая именно техника используется, тогда я хотел бы представить следующее:

Решение: template_matching.py

 import cv2
import numpy as np
from matplotlib import pyplot as plt
import sys

img_rgb = cv2.imread(sys.argv[1])
img_gray = cv2.cvtColor(img_rgb, cv2.COLOR_BGR2GRAY)
template = cv2.imread('smile.png',0)
w, h = template.shape[::-1]

res = cv2.matchTemplate(img_gray,template,cv2.TM_CCOEFF_NORMED)
threshold = 0.8
loc = np.where( res >= threshold)
for pt in zip(*loc[::-1]):
    cv2.rectangle(img_rgb, pt, (pt[0]   w, pt[1]   h), (0,0,255), 2)

cv2.imwrite('res.png',img_rgb)
  

что вы можете запустить так:

Результат:

 python3 template_matching.py test1.png
  

и это дало бы вам такой результат:

обнаружен смайлик

в то время как другое тестовое изображение,

 python3 template_matching.py test2.png
  

выдает результат, подобный этому:

Ничего не найдено

Объяснение:

Возможно, я не совсем знаком с SIFT (так называемый алгоритм наилучшего обнаружения объектов), но обычно он используется для обнаружения углов, извлечения объектов и так далее. Одного этого недостаточно для сопоставления (по крайней мере, на мой взгляд). Вам нужно объединить эти функции для определения объекта. И этот объект вы могли бы затем попытаться найти в тестовом наборе изображений.

Альтернативный подход, о котором я мог бы подумать, который может быть более сложным и не будет использовать какую-либо встроенную функцию blackbox opencv, использует преобразование Хафа для получения двух вертикальных линий. А затем преобразуйте круг Хафа, чтобы получить полукруг, образованный смайлом. Вместе они определили бы ваш «смайлик». но в любом случае, вы говорите в своем вопросе:

предпочтительно с помощью встроенных функций OpenCV.

тогда, я думаю, приведенное выше решение является самым быстрым и кратким для вашей проблемы.

Комментарии:

1. Спасибо вам за ответ. Возможно, мой вопрос действительно является проблемой XY, но у меня было несколько причин выбрать «Обнаружение ключевых точек». Я обновил свой вопрос. Я добавил 2 фотографии. «Сопоставление с шаблоном» для них не работает. При пороговом значении = 0,5 шаблон не найден на фотографии test3.png, а на картинке test2.png найден. Я думаю, что «обнаружение ключевых точек» для меня лучше, чем «Сопоставление с шаблоном».

2. @AlexanderGoryushkin, я понимаю вашу точку зрения. Я думаю, что надежность сопоставления с шаблоном можно было бы улучшить, сделав код многомасштабным. Хотя сначала мне пришлось бы попробовать это самому. Но я просто высказал вам свое мнение. Возможно, KNN amp; SIFT действительно правильный путь. Мне пришлось бы ознакомиться с этими двумя, прежде чем я смогу прокомментировать дальнейшие действия.