From 09416347761273012d37505153b3dd7274c90717 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Lukas=20W=C3=B6lfer?= Date: Thu, 2 May 2019 01:54:11 +0200 Subject: [PATCH] Worked on configuration --- shenzhen_solitaire/cv/card_finder.py | 2 +- shenzhen_solitaire/cv/configuration.py | 91 ++++++++++++++++++++++++++ test/cv_helper.py | 64 ++---------------- 3 files changed, 96 insertions(+), 61 deletions(-) create mode 100644 shenzhen_solitaire/cv/configuration.py diff --git a/shenzhen_solitaire/cv/card_finder.py b/shenzhen_solitaire/cv/card_finder.py index 79c709a..f7ba254 100644 --- a/shenzhen_solitaire/cv/card_finder.py +++ b/shenzhen_solitaire/cv/card_finder.py @@ -107,7 +107,7 @@ def find_square(search_square: np.ndarray, return (best_square, best_count) -def catalague_cards(squares: List[np.ndarray]) -> List[Tuple[np.ndarray, Card]]: +def catalogue_cards(squares: List[np.ndarray]) -> List[Tuple[np.ndarray, Card]]: cv2.namedWindow("Catalogue", cv2.WINDOW_NORMAL) cv2.waitKey(1) result: List[Tuple[np.ndarray, Card]] = [] diff --git a/shenzhen_solitaire/cv/configuration.py b/shenzhen_solitaire/cv/configuration.py new file mode 100644 index 0000000..4daffee --- /dev/null +++ b/shenzhen_solitaire/cv/configuration.py @@ -0,0 +1,91 @@ +"""Contains configuration class""" +import zipfile +import json +from typing import List, Tuple, Dict +import io +import dataclasses + +import numpy as np +from . import adjustment +from . import card_finder +from .. import board + + +class Configuration: + """Configuration for solitaire cv""" + ADJUSTMENT_FILE_NAME = 'adjustment.json' + TEMPLATES_DIRECTORY = 'templates' + + def __init__(self, + adj: adjustment.Adjustment, + catalogue: List[Tuple[np.ndarray, + board.Card]], + meta: Dict[str, + str]) -> None: + self.adjustment = adj + self.catalogue = catalogue + self.meta = meta + + def save(self, filename: str) -> None: + """Save configuration to zip archive""" + zip_stream = io.BytesIO() + with zipfile.ZipFile(zip_stream, "w") as zip_file: + zip_file.writestr( + self.ADJUSTMENT_FILE_NAME, json.dumps( + dataclasses.asdict( + self.adjustment))) + counter = 0 + for square, card in self.catalogue: + counter += 1 + file_stream = io.BytesIO() + np.save(file_stream, square, allow_pickle=False) + file_name = "" + if isinstance(card, board.SpecialCard): + file_name = f's{card.value}-{card.name}-{counter}.npy' + elif isinstance(card, board.NumberCard): + file_name = f'n{card.suit.value}{card.number}-{card.suit.name}-{counter}.npy' + else: + raise AssertionError() + zip_file.writestr( + self.TEMPLATES_DIRECTORY + f"/{file_name}", + file_stream.getvalue()) + + with open(filename, 'wb') as zip_archive: + zip_archive.write(zip_stream.getvalue()) + + @staticmethod + def load(filename: str) -> 'Configuration': + """Load configuration from zip archive""" + def _parse_file_name(card_filename: str) -> board.Card: + assert card_filename.startswith( + Configuration.TEMPLATES_DIRECTORY + '/') + pure_name = card_filename[ + len(Configuration.TEMPLATES_DIRECTORY + '/'):] + if pure_name[0] == 's': + return board.SpecialCard(int(pure_name[1])) + if pure_name[0] == 'n': + return board.NumberCard( + suit=board.NumberCard.Suit( + int(pure_name[1])), number=int(pure_name[2])) + raise AssertionError() + + catalogue: List[Tuple[np.ndarray, board.Card]] = [] + with zipfile.ZipFile(filename, 'r') as zip_file: + adj = adjustment.Adjustment( + **json.loads(zip_file.read(Configuration.ADJUSTMENT_FILE_NAME))) + for template_filename in ( + x for x in zip_file.namelist() if + x.startswith(Configuration.TEMPLATES_DIRECTORY + '/')): + catalogue.append( + (np.load(io.BytesIO(zip_file.read(template_filename))), + _parse_file_name(template_filename))) + assert catalogue[-1][0] is not None + return Configuration(adj=adj, catalogue=catalogue, meta={}) + + @staticmethod + def generate(image: np.ndarray) -> 'Configuration': + """Generate a configuration with user input""" + adj = adjustment.adjust_field(image) + squares = card_finder.get_field_squares(image, adj) + catalogue = card_finder.catalogue_cards(squares[:2]) + return Configuration(adj=adj, catalogue=catalogue, meta={}) diff --git a/test/cv_helper.py b/test/cv_helper.py index ae01823..af73c31 100644 --- a/test/cv_helper.py +++ b/test/cv_helper.py @@ -5,60 +5,14 @@ import io import json import dataclasses -import numpy as np # type: ignore -import cv2 # type: ignore +import numpy as np +import cv2 from .context import shenzhen_solitaire from shenzhen_solitaire.cv import adjustment from shenzhen_solitaire.cv import card_finder from shenzhen_solitaire import board - - -def pixelcount(image: np.ndarray) -> List[Tuple[Tuple[int, int, int], int]]: - p: Dict[Tuple[int, int, int], int] = {(0, 0, 0): 0} - for pixel in itertools.chain.from_iterable(image): - x = tuple(pixel) - if x in p: - p[x] += 1 - else: - p[x] = 1 - B = sorted(p.items(), key=lambda x: x[1]) - return B - - -def simplify(image: np.ndarray) -> None: - cv2.imshow("Window", image) - cv2.waitKey(0) - cv2.destroyWindow("Window") - print(*card_finder.simplify(image)[1].items(), sep='\n') - cv2.imshow("Window", image) - cv2.waitKey(0) - cv2.destroyWindow("Window") - -def calibrate(image: np.ndarray) -> None: - adj = adjustment.adjust_field(image) - squares = card_finder.get_field_squares(image, adj) - catalogue = card_finder.catalague_cards(squares[:2]) - - zip_stream = io.BytesIO() - with zipfile.ZipFile(zip_stream, "w") as zip_file: - zip_file.writestr('adjustment.json', json.dumps(dataclasses.asdict(adj))) - counter = 0 - for square, card in catalogue: - counter += 1 - file_stream = io.BytesIO() - np.save(file_stream, square, allow_pickle=False) - file_name = "" - if isinstance(card, board.SpecialCard): - file_name = f's{card.value}-{card.name}-{counter}.npy' - elif isinstance(card, board.NumberCard): - file_name = f'n{card.suit.value}{card.number}-{card.suit.name}-{card.number}-{counter}.npy' - else: - raise AssertionError() - zip_file.writestr(f"templates/{file_name}", file_stream.getvalue()) - - with open('myzip.zip', 'wb') as fd: - fd.write(zip_stream.getvalue()) +from shenzhen_solitaire.cv.configuration import Configuration def main() -> None: @@ -67,17 +21,7 @@ def main() -> None: nparr = np.frombuffer(img_str, np.uint8) image = cv2.imdecode(nparr, cv2.IMREAD_COLOR) - calibrate(image) - - - -def main2() -> None: - file_stream = None - with zipfile.ZipFile('myzip.zip', "r") as zip_file: - file_stream = io.BytesIO(zip_file.read('0.dat')) - - A = np.load(file_stream) - print(A) + Configuration.generate(image) if __name__ == "__main__":