I\'m trying to match a slightly irregular shape to a database of shapes. For example, here the contour I\'m trying to match:
For more information, this is an ou
This answer is based on ZdaR's answer here https://stackoverflow.com/a/55530040/1787145. I have tried some variations in hope of using a single discerning criterion (cv2.matchShapes()
) by incorporating more in the pre-processing.
I like the idea of normalization (crop and resize). But after shrinking an image, its originally closed contour might be broken into multiple disconnected parts, due to the low resolution of pixels. The result of cv2.matchShapes()
is unreliable. By comparing whole resized images, I get following results. It says the circle is the most similar. Not good!
By filling the shape, we take area into consideration. The result looks better, but DVI still beats HDMI for having a more similar height or Height/Width ratio. We want to ignore that.
By resizing all to the same size, we eliminate some ratio in the dimensions. (300, 300) works well here.
def normalize_filled(img):
img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
im, cnt, _ = cv2.findContours(img.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
# fill shape
cv2.fillPoly(img, pts=cnt, color=(255,255,255))
bounding_rect = cv2.boundingRect(cnt[0])
img_cropped_bounding_rect = img[bounding_rect[1]:bounding_rect[1] + bounding_rect[3], bounding_rect[0]:bounding_rect[0] + bounding_rect[2]]
# resize all to same size
img_resized = cv2.resize(img_cropped_bounding_rect, (300, 300))
return img_resized
imgs = [imgQuery, imgHDMI, imgDVI, img5PinDin, imgDB25]
imgs = [normalize_filled(i) for i in imgs]
for i in range(1, 6):
plt.subplot(2, 3, i), plt.imshow(imgs[i - 1], cmap='gray')
print(cv2.matchShapes(imgs[0], imgs[i - 1], 1, 0.0))