Worked on feature extraction

This commit is contained in:
Lukas Wölfer
2020-06-18 05:10:31 +02:00
parent 11919bb13c
commit 7efa290295
2 changed files with 53 additions and 32 deletions

View File

@@ -9,5 +9,12 @@
"python.testing.pytestEnabled": false, "python.testing.pytestEnabled": false,
"python.testing.nosetestsEnabled": false, "python.testing.nosetestsEnabled": false,
"python.testing.unittestEnabled": true, "python.testing.unittestEnabled": true,
"python.pythonPath": "/home/lukas/.local/share/virtualenvs/shenzhen-solitaire-nsu5dgrx/bin/python" "python.linting.mypyArgs": [
"--ignore-missing-imports",
"--follow-imports=silent",
"--show-column-numbers",
"--strict"
],
"python.linting.mypyEnabled": true,
"python.formatting.provider": "black"
} }

View File

@@ -4,10 +4,10 @@ from shenzhen_solitaire.board import NumberCard, SpecialCard
import cv2 import cv2
import numpy as np import numpy as np
from typing import Any, Tuple from typing import Any, Tuple, List, Union, Dict, Optional
def border_image(image, size=1, color=0): def border_image(image: np.array, size: int = 1, color: int = 0) -> None:
for ring in range(size): for ring in range(size):
for x in range(ring, image.shape[0] - ring): for x in range(ring, image.shape[0] - ring):
image[x][ring] = color image[x][ring] = color
@@ -17,47 +17,39 @@ def border_image(image, size=1, color=0):
image[image.shape[0] - 1 - ring][y] = color image[image.shape[0] - 1 - ring][y] = color
def prepare_image(image): def prepare_image(image: np.array) -> np.array:
cnt = get_contour(image) cnt = get_contour(image)
mask = np.zeros(image.shape[:2], dtype=image.dtype) mask = np.zeros(image.shape[:2], dtype=image.dtype)
contim = cv2.drawContours(mask, [cnt], 0, 255, cv2.FILLED) contim = cv2.drawContours(mask, [cnt], 0, 255, cv2.FILLED)
# crop = np.multiply(edge_image, contim)
return contim return contim
def get_contour(image): def get_contour(image: np.array) -> np.array:
gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) gray_image = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
ret, edge_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY_INV) ret, edge_image = cv2.threshold(gray_image, 127, 255, cv2.THRESH_BINARY_INV)
border_image(edge_image, size=0) kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))
edge_image = cv2.morphologyEx(edge_image, cv2.MORPH_CLOSE, kernel)
border_image(edge_image, size=1)
contours, hierarchy = cv2.findContours( contours, hierarchy = cv2.findContours(
edge_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE edge_image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE
) )
cnt = max(contours, key=cv2.contourArea) cnt = max(contours, key=cv2.contourArea)
assert isinstance(cnt, np.ndarray)
return cnt return cnt
def matchScaleInvShape(cont1, cont2): def matchScaleInvShape(cont1: np.array, cont2: np.array) -> float:
m1 = cv2.moments(cont1) m1 = cv2.moments(cont1)
m2 = cv2.moments(cont2) m2 = cv2.moments(cont2)
moments = [ moments = [
(m1[moment], m2[moment]) for moment in m1 if str(moment).startswith("nu") (m1[moment], m2[moment]) for moment in m1 if str(moment).startswith("nu")
] ]
return sum([abs((nu1) - (nu2)) for nu1, nu2 in moments]) return sum([abs((nu1) - (nu2)) * 1000 for nu1, nu2 in moments])
def match_template(image, template): def type_fine(
image_cont, hierarchy = cv2.findContours( one: Union[SpecialCard, NumberCard], other: Union[SpecialCard, NumberCard]
image, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE ) -> bool:
)
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 [matchScaleInvShape(imcont, temcont)]
def type_fine(one, other) -> bool:
if isinstance(one, SpecialCard): if isinstance(one, SpecialCard):
return one == other return one == other
assert isinstance(one, NumberCard) assert isinstance(one, NumberCard)
@@ -65,7 +57,10 @@ def type_fine(one, other) -> bool:
return False return False
return one.number == other.number return one.number == other.number
def check_type(matches, should_type):
def check_type(
matches: List[Any], should_type: Union[SpecialCard, NumberCard]
) -> Optional[int]:
if not type_fine(matches[0][0], should_type): if not type_fine(matches[0][0], should_type):
correct_index = 0 correct_index = 0
for list_type, list_value, _ in matches: for list_type, list_value, _ in matches:
@@ -77,24 +72,43 @@ def check_type(matches, should_type):
f"{str(should_type):>20} matched as {str(matches[0][0]):>20} {matches[0][1]:.05f}, " f"{str(should_type):>20} matched as {str(matches[0][0]):>20} {matches[0][1]:.05f}, "
f"correct in pos {correct_index:02d} val {correct_value:.05f}" f"correct in pos {correct_index:02d} val {correct_value:.05f}"
) )
cv2.imshow("one", prepare_image(catalogue[matches[0][2]][0])) catalogue_index = matches[correct_index][2]
cv2.imshow("two", img1) assert isinstance(catalogue_index, int)
cv2.imshow("three", prepare_image(catalogue[matches[correct_index][2]][0])) return catalogue_index
cv2.waitKey(0) return None
return True
return False
def debug_match(image, image_type, catalogue):
def show_wrong_images(
current: np.ndarray, correct: np.ndarray, wrong: np.ndarray
) -> None:
cv2.imshow("Current", current)
cv2.imshow("Correct", correct)
cv2.imshow("Wrong", wrong)
cv2.waitKey(0)
def debug_match(
image: np.array,
image_type: Union[NumberCard, SpecialCard],
catalogue: List[Tuple[Any, Union[SpecialCard, NumberCard]]],
) -> None:
cnt1 = prepare_image(image) cnt1 = prepare_image(image)
i1_matches = [] i1_matches = []
for index, (template_image, template_type) in enumerate(catalogue): for index, (template_image, template_type) in enumerate(catalogue):
cnt2 = prepare_image(template_image) cnt2 = prepare_image(template_image)
i1_matches.append((template_type, matchScaleInvShape(cnt1, cnt2), index)) i1_matches.append((template_type, matchScaleInvShape(cnt1, cnt2), index))
i1_matches = sorted(i1_matches, key=lambda x: x[1]) i1_matches = sorted(i1_matches, key=lambda x: x[1])
correct_type_index = check_type(i1_matches, image_type)
if correct_type_index is not None:
show_wrong_images(
cnt1,
prepare_image(catalogue[correct_type_index][0]),
prepare_image(catalogue[i1_matches[0][2]][0]),
)
return
for list_type, list_value, list_index in i1_matches: for list_type, list_value, list_index in i1_matches:
if not type_fine(list_type, i1_matches[0][0]): if not type_fine(list_type, i1_matches[0][0]):
if list_value * 0.4 < i1_matches[0][1]: if list_value * 0.8 < i1_matches[0][1]:
print( print(
f"{str(image_type):>20} {i1_matches[0][1]:.05f} very close" f"{str(image_type):>20} {i1_matches[0][1]:.05f} very close"
f" match with {str(list_type):>20} {list_value:.05f}" f" match with {str(list_type):>20} {list_value:.05f}"