From 3720e25a5a47198efc9d532bdae1cb7ba2e86861 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6lfer?= Date: Sun, 21 Apr 2019 22:32:31 +0200 Subject: [PATCH] Worked on card detection --- colors.txt | 6 ++ shenzhen_solitaire/board_cv.py | 97 ---------------------------- shenzhen_solitaire/cv/__init__.py | 0 shenzhen_solitaire/cv/adjustment.py | 96 +++++++++++++++++++++++++++ shenzhen_solitaire/cv/card_finder.py | 22 +++++++ test/cv_helper.py | 42 ++++++++++++ 6 files changed, 166 insertions(+), 97 deletions(-) create mode 100644 colors.txt delete mode 100644 shenzhen_solitaire/board_cv.py create mode 100644 shenzhen_solitaire/cv/__init__.py create mode 100644 shenzhen_solitaire/cv/adjustment.py create mode 100644 shenzhen_solitaire/cv/card_finder.py create mode 100644 test/cv_helper.py diff --git a/colors.txt b/colors.txt new file mode 100644 index 0000000..696b0d8 --- /dev/null +++ b/colors.txt @@ -0,0 +1,6 @@ +65, 65, 65 bai +0, 0, 0 black +22, 48, 178 red +76, 111, 19 green + + diff --git a/shenzhen_solitaire/board_cv.py b/shenzhen_solitaire/board_cv.py deleted file mode 100644 index 2045c5c..0000000 --- a/shenzhen_solitaire/board_cv.py +++ /dev/null @@ -1,97 +0,0 @@ -import cv2 -import numpy -from typing import Optional -from dataclasses import dataclass - -A = cv2.imread("Solitaire.png") - - -@dataclass -class Adjustment: - x: int - y: int - w: int - h: int - dx: int - dy: int - - -def adjust_squares( - image: numpy.ndarray, - count_x: int, - count_y: int, - preset: Optional[Adjustment] = None) -> Adjustment: - result = preset - if not result: - result = Adjustment(0, 0, 0, 0, 0, 0) - while True: - B = image.copy() - for ix in range(count_x): - for iy in range(count_y): - cv2.rectangle(B, (result.x + - result.dx * - ix, result.y + - result.dy * - iy), (result.x + - result.w + - result.dx * - ix, result.y + - result.h + - result.dy * - iy), (0, 0, 0)) - cv2.imshow('Window', B) - k = cv2.waitKey(0) - print(k) - if k == 27: - break - elif k == 81: - result.x -= 1 - elif k == 83: - result.x += 1 - elif k == 82: - result.y -= 1 - elif k == 84: - result.y += 1 - elif k == 104: - result.x -= 10 - elif k == 115: - result.x += 10 - elif k == 116: - result.y -= 10 - elif k == 110: - result.y += 10 - elif k == 97: - result.w -= 1 - elif k == 111: - result.h -= 1 - elif k == 101: - result.h += 1 - elif k == 117: - result.w += 1 - elif k == 59: - result.dx -= 1 - elif k == 44: - result.dy -= 1 - elif k == 46: - result.dy += 1 - elif k == 112: - result.dx += 1 - - cv2.destroyWindow('Window') - return result - - -def adjust_field(image) -> Adjustment: - return adjust_squares(image, 8, 5, Adjustment(42, 226, 15, 15, 119, 24)) - -def adjust_bunker(image) -> Adjustment: - return adjust_squares(image, 3, 1) - -def adjust_hua(image) -> Adjustment: - return adjust_squares(image, 1, 1) - -def adjust_goal(image) -> Adjustment: - return adjust_squares(image, 3, 1) - - -print(adjust_field(A)) diff --git a/shenzhen_solitaire/cv/__init__.py b/shenzhen_solitaire/cv/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/shenzhen_solitaire/cv/adjustment.py b/shenzhen_solitaire/cv/adjustment.py new file mode 100644 index 0000000..3fbf30b --- /dev/null +++ b/shenzhen_solitaire/cv/adjustment.py @@ -0,0 +1,96 @@ +from typing import Optional, Tuple +from dataclasses import dataclass +import cv2 +import numpy + + +@dataclass +class Adjustment: + x: int + y: int + w: int + h: int + dx: int + dy: int + + +def get_square(adjustment: Adjustment, ix: int = 0, + iy: int = 0) -> Tuple[int, int, int, int]: + return (adjustment.x + adjustment.dx * ix, + adjustment.y + adjustment.dy * iy, + adjustment.x + adjustment.w + adjustment.dx * ix, + adjustment.y + adjustment.h + adjustment.dy * iy) + + +def _adjust_squares( + image: numpy.ndarray, + count_x: int, + count_y: int, + adjustment: Optional[Adjustment] = None) -> Adjustment: + if not adjustment: + adjustment = Adjustment(0, 0, 0, 0, 0, 0) + while True: + B = image.copy() + for ix in range(count_x): + for iy in range(count_y): + square = get_square(adjustment, ix, iy) + cv2.rectangle(B, + (square[0], square[1]), + (square[2], square[3]), + (0, 0, 0)) + cv2.imshow('Window', B) + k = cv2.waitKey(0) + print(k) + if k == 27: + break + elif k == 81: + adjustment.x -= 1 + elif k == 83: + adjustment.x += 1 + elif k == 82: + adjustment.y -= 1 + elif k == 84: + adjustment.y += 1 + elif k == 104: + adjustment.x -= 10 + elif k == 115: + adjustment.x += 10 + elif k == 116: + adjustment.y -= 10 + elif k == 110: + adjustment.y += 10 + elif k == 97: + adjustment.w -= 1 + elif k == 111: + adjustment.h -= 1 + elif k == 101: + adjustment.h += 1 + elif k == 117: + adjustment.w += 1 + elif k == 59: + adjustment.dx -= 1 + elif k == 44: + adjustment.dy -= 1 + elif k == 46: + adjustment.dy += 1 + elif k == 112: + adjustment.dx += 1 + + cv2.destroyWindow('Window') + return adjustment + + +def adjust_field(image) -> Adjustment: + return _adjust_squares(image, 8, 5, Adjustment(42, 226, 15, 15, 119, 24)) + + +def adjust_bunker(image) -> Adjustment: + return _adjust_squares(image, 3, 1) + + +def adjust_hua(image) -> Adjustment: + return _adjust_squares(image, 1, 1) + + +def adjust_goal(image) -> Adjustment: + return _adjust_squares(image, 3, 1) diff --git a/shenzhen_solitaire/cv/card_finder.py b/shenzhen_solitaire/cv/card_finder.py new file mode 100644 index 0000000..cfc884e --- /dev/null +++ b/shenzhen_solitaire/cv/card_finder.py @@ -0,0 +1,22 @@ +from typing import List, Tuple +import numpy +from .adjustment import Adjustment, get_square +from .. import board + + +def _extract_squares(image: numpy.ndarray, + squares: List[Tuple[int, + int, + int, + int]]) -> List[numpy.ndarray]: + return [image[square[1]:square[3], square[0]:square[2]].copy() + for square in squares] + + +def get_field_squares(image: numpy.ndarray, + adjustment: Adjustment) -> List[numpy.ndarray]: + squares = [] + for ix in range(8): + for iy in range(5): + squares.append(get_square(adjustment, ix, iy)) + return _extract_squares(image, squares) diff --git a/test/cv_helper.py b/test/cv_helper.py new file mode 100644 index 0000000..3210044 --- /dev/null +++ b/test/cv_helper.py @@ -0,0 +1,42 @@ +from .context import shenzhen_solitaire +from shenzhen_solitaire.cv import adjustment +from shenzhen_solitaire.cv import card_finder +import cv2 + +A = cv2.imread("Solitaire.png") + +adj = adjustment.adjust_field(A) +X = card_finder.get_field_squares(A, adj) +for h in range(20): + p = {None: 0} + for x in X[h]: + for x2 in ((x1[0], x1[1], x1[2]) for x1 in x): + if x2 in p: + p[x2] += 1 + else: + p[x2] = 1 + B = sorted(p.items(), key=lambda x: x[1]) + print(*B, sep='\n') + + T = X[h].copy() + cv2.imshow("Window", T) + while cv2.waitKey(0) != 27: + pass + cv2.destroyWindow("Window") +assert 0 + +for ix, vx in enumerate(T): + for iy, vy in enumerate(vx): + if (vy[0] > 100) and (vy[1] > 100) and (vy[2] > 100): + T[ix, iy] = [255, 255, 255] + else: + T[ix, iy] = [0, 0, 0] + +cv2.imshow("Window", T) +cv2.waitKey(0) +cv2.destroyWindow("Window") + + +# for j in X: +# cv2.imshow("Window", j) +# cv2.waitKey(0)