From fc2e3aca4cdb88bc7aeed321fe2d97dbe55f7efe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6lfer?= Date: Tue, 16 Jun 2020 14:37:00 +0200 Subject: [PATCH] Tested with more advanced methods of card detection --- tools/feature_extraction.py | 99 +++++++++++++++++++++++++++++++++++++ 1 file changed, 99 insertions(+) create mode 100644 tools/feature_extraction.py diff --git a/tools/feature_extraction.py b/tools/feature_extraction.py new file mode 100644 index 0000000..3728191 --- /dev/null +++ b/tools/feature_extraction.py @@ -0,0 +1,99 @@ +import shenzhen_solitaire.card_detection.configuration as configuration +from shenzhen_solitaire.board import NumberCard, SpecialCard + +import cv2 + +import numpy as np +from typing import Any, Tuple + + +def prepare_image(image): + gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) + # edge_image = cv2.Canny(gray_image, 120, 160) + ret, edge_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY_INV) + contours2, hierarchy = cv2.findContours( + edge_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE + ) + cnt2 = max(contours2, key=cv2.contourArea) + + mask = np.zeros(edge_image.shape, dtype=edge_image.dtype) + contim = cv2.drawContours(mask, [cnt2], 0, 1, cv2.FILLED) + crop = np.multiply(edge_image, contim) + return crop + + +def match_template(image, template): + image_cont, hierarchy = cv2.findContours( + image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE + ) + imcont = max(image_cont, key=cv2.contourArea) + template_cont, hierarchy = cv2.findContours( + template, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE + ) + temcont = max(template_cont, key=cv2.contourArea) + return [ + cv2.matchShapes(imcont, temcont, mode, 0.0) + for mode in ( + cv2.CONTOURS_MATCH_I1, + cv2.CONTOURS_MATCH_I2, + cv2.CONTOURS_MATCH_I3, + ) + ] + + +def type_fine(one, other) -> bool: + if isinstance(one, SpecialCard): + return one == other + assert isinstance(one, NumberCard) + if not isinstance(other, NumberCard): + return False + return one.number == other.number + + +def debug_match(image, image_type, catalogue): + img1 = prepare_image(image) + i1_matches = [] + for index, (template_image, template_type) in enumerate(catalogue): + img2 = prepare_image(template_image) + i1_matches.append((template_type, match_template(img1, img2)[0], index)) + i1_matches = sorted(i1_matches, key=lambda x: x[1]) + if not type_fine(i1_matches[0][0], image_type): + correct_index = 0 + for list_type, list_value, _ in i1_matches: + if type_fine(list_type, image_type): + correct_value = list_value + break + correct_index += 1 + print( + f"{str(image_type):>20} matched as {str(i1_matches[0][0]):>20} {i1_matches[0][1]:.05f}, " + f"correct in pos {correct_index:02d} val {correct_value:.05f}" + ) + cv2.imshow("one", prepare_image(catalogue[i1_matches[0][2]][0])) + cv2.imshow("two", img1) + cv2.imshow("three", prepare_image(catalogue[i1_matches[correct_index][2]][0])) + cv2.waitKey(0) + return + for list_type, list_value, list_index in i1_matches: + if not type_fine(list_type, i1_matches[0][0]): + if list_value * 0.6 < i1_matches[0][1]: + print( + f"{str(image_type):>20} {i1_matches[0][1]:.05f} very close" + f" match with {str(list_type):>20} {list_value:.05f}" + ) + return + + if i1_matches[0][1] > 1: + print(f"{image_type} with value {i1_matches[0][1]}") + + +def main() -> None: + pc = configuration.load("test_config.zip") + laptop = configuration.load("laptop_conf.zip") + bla = [(i, t) for i, t in pc.catalogue if t == SpecialCard.Hua] + bla = pc.catalogue + for pc_image, pc_card_type in bla: + debug_match(pc_image, pc_card_type, laptop.catalogue) + + +if __name__ == "__main__": + main()