Почему cv.matchShapes() обнаруживает большую разницу между фигурами, если они одинаковы?

У меня есть код, который сравнивает две геометрические фигуры. Я установил порог сравнения 0,1 (вы увидите его ниже в коде), и в принципе результаты более-менее хорошие.

Но бывают случаи, когда встречаются вполне похожие фигуры (но с разными координатами x и y). Например

То есть в принципе фигуры похожи, но что касается координат на листе, то фигуры расположены немного по-другому.

 def compare_two_figure(template, figure_for_compare):
    template = cv.imread(template, cv.IMREAD_GRAYSCALE)
    figure_for_compare = cv.imread(figure_for_compare, cv.IMREAD_GRAYSCALE)

    _, thresh_template = cv.threshold(template, 127, 255, 0)
    _, thresh_figure_for_compare = cv.threshold(figure_for_compare, 127, 255, 0)

    contours_template, _ = cv.findContours(thresh_template, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    particular_contour_template = contours_template[1]

    contours_figure_for_compare, _ = cv.findContours(thresh_figure_for_compare, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    particular_contour_figure_for_compare = contours_figure_for_compare[1]

    differences = cv.matchShapes(particular_contour_template, particular_contour_figure_for_compare, 1, 0.0)
    print(differences)
    if differences < 0.1:
        return "same"
    else:
        return "different"


print(compare_two_figure('files/template_14_v2.jpg', 'searching_figure_14.jpg'))

В приведенном выше примере различия = 7,842170693643041.

Как вы понимаете, хотелось бы, чтобы в таких случаях результат был таким, чтобы цифры были идентичными (или почти идентичными). Подскажите, как это можно реализовать?

вы определяете функцию с именем compare_two_figure, но вместо этого вызываете compare_two_documents. Должны ли эти функции быть одинаковыми?

Aemyl 04.07.2024 12:56

@Aemyl да, это то же самое. Спасибо

Paul 04.07.2024 13:03

контекст: stackoverflow.com/questions/78705469/…

Christoph Rackwitz 04.07.2024 13:35

Формы могут выглядеть одинаково, но одна короче по вертикали. Это тоже не будет соответствовать.

fmw42 08.07.2024 18:05
Почему в Python есть оператор "pass"?
Почему в Python есть оператор "pass"?
Оператор pass в Python - это простая концепция, которую могут быстро освоить даже новички без опыта программирования.
Некоторые методы, о которых вы не знали, что они существуют в Python
Некоторые методы, о которых вы не знали, что они существуют в Python
Python - самый известный и самый простой в изучении язык в наши дни. Имея широкий спектр применения в области машинного обучения, Data Science,...
Основы Python Часть I
Основы Python Часть I
Вы когда-нибудь задумывались, почему в программах на Python вы видите приведенный ниже код?
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
LeetCode - 1579. Удаление максимального числа ребер для сохранения полной проходимости графа
Алиса и Боб имеют неориентированный граф из n узлов и трех типов ребер:
Оптимизация кода с помощью тернарного оператора Python
Оптимизация кода с помощью тернарного оператора Python
И последнее, что мы хотели бы показать вам, прежде чем двигаться дальше, это
Советы по эффективной веб-разработке с помощью Python
Советы по эффективной веб-разработке с помощью Python
Как веб-разработчик, Python может стать мощным инструментом для создания эффективных и масштабируемых веб-приложений.
1
4
67
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Ответ принят как подходящий

см. документацию https://docs.opencv.org/4.x/d5/d45/tutorial_py_contours_more_functions.html

findContours и matchShapes ожидают белый (255) внутри и черный (0) снаружи.

Я преобразовал ваши изображения, используя этот код:

def fill_polygons(template, figure_for_compare):
    template = cv.imread(template, cv.IMREAD_GRAYSCALE)
    template = 255 - template
    figure_for_compare = cv.imread(figure_for_compare, cv.IMREAD_GRAYSCALE)
    figure_for_compare = 255 - figure_for_compare

    _, thresh_template = cv.threshold(template, 127, 255, 0)
    _, thresh_figure_for_compare = cv.threshold(figure_for_compare, 127, 255, 0)

    contours_template, _ = cv.findContours(thresh_template, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    particular_contour_template = contours_template[1]

    cv.fillPoly(thresh_template, pts=[particular_contour_template], color=(255, 255, 255))
    cv.imwrite("/tmp/1a.png", thresh_template)

    contours_figure_for_compare, _ = cv.findContours(thresh_figure_for_compare, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    particular_contour_figure_for_compare = contours_figure_for_compare[1]

    cv.fillPoly(thresh_figure_for_compare, pts=[particular_contour_figure_for_compare], color=(255, 255, 255))
    cv.imwrite("/tmp/2a.png", thresh_figure_for_compare)


fill_polygons('files/template_14_v2.jpg', 'searching_figure_14.jpg')

и с вашей функцией я получаю разницу ~ = 0,45

(Я думаю, что две фигуры, которые у вас есть, не одинаковы, я имею в виду, что вы не просто переместили первую, чтобы получить вторую)

Большое спасибо за внимание к моему вопросу и за решение. Да, я видел эту ссылку, но видимо не внимательно прочитал. Я хотел бы уточнить один момент: ваша функция fill_polygons работает и возвращает два файла 1a.png и 2a.png, а затем я должен передать эти два файла в качестве аргументов в мою функцию Compare_two_figure? Я прав?

Paul 08.07.2024 09:15

Да, ты прав

Ophir Carmi 08.07.2024 09:40

Не могли бы вы провести рефакторинг своего кода, так как вы дважды определяете переменные contexts_template и unique_contour_template, а после второго определения переменная unique_contour_template нигде не используется. Это немного сбивает с толку.

Paul 08.07.2024 09:52

Готово, удалены лишние строки

Ophir Carmi 08.07.2024 10:09

Спасибо за помощь. В этом случае ваше решение идеально, но мне кажется, что мне следует поискать другой подход для определения сходства.

Paul 09.07.2024 08:43

Более простой ответ:

изменения в рассматриваемом коде:

  1. Инвертируйте изображения im = 255 - im

  2. Используйте cv.RETR_LIST вместо cv.RETR_TREE

     def compare_two_figure(template, figure_for_compare):
         template = cv.imread(template, cv.IMREAD_GRAYSCALE)
         template = 255 - template
         figure_for_compare = cv.imread(figure_for_compare, cv.IMREAD_GRAYSCALE)
         figure_for_compare = 255 - figure_for_compare
    
         _, thresh_template = cv.threshold(template, 127, 255, 0)
         _, thresh_figure_for_compare = cv.threshold(figure_for_compare, 127, 255, 0)
    
         contours_template, _ = cv.findContours(thresh_template, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
         particular_contour_template = contours_template[1]
    
         contours_figure_for_compare, _ = cv.findContours(thresh_figure_for_compare, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
         particular_contour_figure_for_compare = contours_figure_for_compare[1]
    
         differences = cv.matchShapes(particular_contour_template, particular_contour_figure_for_compare, 1, 0.0)
         print(differences)
         if differences < 0.1:
             return "same"
         else:
             return "different"
    

Я получаю разницу ~= 0,45

Другие вопросы по теме