pythonopencvcomputer-vision

Why does cv.matchShapes() detect a big difference between shapes if they are the same?


I have a code that compares two geometric figures. I set the threshold for comparison to 0.1 (you will see it below in the code), and in principle the results are more or less good.

But there are times when you come across quite similar figures (but with different x and y coordinates). For example

enter image description here enter image description here

That is, in principle, the figures are similar, but as far as the coordinates on the sheet are concerned, the figures are located slightly differently.

 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'))

From the example above, differences =7.842170693643041

As you understand, I would like the result in such cases to be that the figures are identical (or almost identical). Tell me, how can this be implemented?


Solution

  • see documentation https://docs.opencv.org/4.x/d5/d45/tutorial_py_contours_more_functions.html

    The findContours and matchShapes expects white (255) inside and black (0) outside.

    I converted your images using this code:

    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')
    

    and with your function, I get differences ~= 0.45

    (I think the two shapes you have are not the same, I mean you didn't just move the first to get the second)

    enter image description here

    enter image description here