I have two contours to match (think of them as any arbitrary 2D closed curves). opencv
claims to have matchShapes
function that is invariant under translation, rotation and scale. But it seems to me that this is not the case, when I add shift (10, 5)
to one of the curves, the function returns a different result, let alone if I did something whackier. Why is that?
Reproducible example:
t = np.arange(0, np.pi, 0.001)
x, y = np.cos(t), np.sin(t)
xy = np.stack([x, y], -1)
print(cv.matchShapes(xy, xy, 1, 0))
print(cv.matchShapes(xy, xy + (2, 10), 1, 0))
The objects you send to cv.matchShapes()
need to be contour
objects which are different to a straight up 2D numpy
array. The following code converts your curves to a plot,
then to an image & the contours of the 2 curves are found.
Finally cv.matchShapes()
is run.
The output: 0
for the self match & 6.637412841570267e-12
for the match with the translated curve, a pretty accurate match under translation.
import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
fig = plt.figure()
ax = fig.add_subplot(111)
t = np.arange(0, np.pi, 0.001)
x, y = np.cos(t), np.sin(t)
ax.plot(x, y)
x_new = x + 2
y_new = y + 10
ax.plot(x_new, y_new, 'b')
[s.set_visible(False) for s in ax.spines.values()]
[t.set_visible(False) for t in ax.get_xticklines()]
[t.set_visible(False) for t in ax.get_yticklines()]
ax.axis('off')
plt.savefig('xy.jpg')
xy_img = cv.imread('xy.jpg', cv.IMREAD_COLOR)
xy_cpy = cv.cvtColor(xy_img, cv.COLOR_BGR2GRAY)
(threshold, bw) = cv.threshold(xy_cpy, 127, 255, cv.THRESH_BINARY)
contours, hier = cv.findContours(bw, cv.RETR_LIST, cv.CHAIN_APPROX_NONE)
contours = contours[0:-1] # remove box surounding whole image
print(cv.matchShapes(contours[0], contours[0], method=cv.CONTOURS_MATCH_I1, parameter=0))
print(cv.matchShapes(contours[0], contours[1], method=cv.CONTOURS_MATCH_I1, parameter=0))
cv.namedWindow("xy")
cv.drawContours(xy_img, contours, -1, (0, 255, 0), 3)
cv.imshow("xy", xy_img)
cv.waitKey()