class Parser: templates = { "label_level": am.template("Popup_Commission.Scene_DelegationList.Label_Level"), "label_processing": am.template("Popup_Commission.Scene_DelegationList.Label_Level.Label_Processing"), } ocr_paddle_numeric = load_recognizer() ocr_paddle = PaddleOCR(show_log=False) rel_pos = { # relative to label level "label_level": { "label_time_limit": (-75, 132, 140, 40), # "label_time_limit": (-75, 132,), }, "label_mission": { "label_mission_name": (200, 20, 290, 36) } } DELEGATIONS = sum([ [parse_delegation_dict(v) for v in values] for key, values in load_yaml(CONFIG_DELEGATION).items() if key != "__Proto__"], start=[] ) @classmethod def parse_label_level_locs(cls, image_ori): locs = match_multi_template( image_ori, cls.templates["label_level"], method=cv2.TM_CCOEFF_NORMED, thresh=.85, thresh_dedup=50 ) return locs @classmethod def parse_time_limit(cls, image_ori, locs=None): """ Args: image_ori: locs: Returns: """ locs = cls.parse_label_level_locs(image_ori) if locs is None else locs # use label level as an anchor, to locate other components x_rel, y_rel, width, height = cls.rel_pos["label_level"]["label_time_limit"] for loc in locs: if (top := loc[1] + y_rel) + 180 > image_ori.shape[0]: # excess the bolder of y-axis continue sub_image = image_ori[top: top + height, (left := loc[0] + x_rel): left + width] if len(sub_image) == 0: continue # preprocess _, sub_image_processed = cv2.threshold( cv2.cvtColor(sub_image, cv2.COLOR_RGB2GRAY), thresh=210, maxval=255, type=cv2.THRESH_BINARY_INV ) sub_image_processed = cv2.cvtColor(sub_image_processed, cv2.COLOR_GRAY2RGB) text, confidence = cls.ocr_paddle.ocr(sub_image_processed, det=False, cls=False)[0] text_rectified = f"{text[:2]}:{text[2:4]}:{text[4:6]}" if len(text := re.sub(r"\D", "", text)) == 6 else "" yield text_rectified
yield match_ratio > thresh @classmethod def find_most_similar_delegation(cls, ocr_res): val_max = 0 res = None for phrase in (x.name for x in cls.DELEGATIONS): if (val_cur := ratio(ocr_res, phrase)) >= val_max: val_max = val_cur res = phrase return res, val_max if __name__ == '__main__': from pathlib import Path from techstacks.auto_game.games.azur_lane.config import DIR_TESTCASE dir_test = Path(f"{DIR_TESTCASE}/commission/delegation_list/label_time_limit") test_values = load_yaml(dir_test / "test_values.yaml") for file_name, values in test_values.items(): img = cv2.imread(f"{dir_test}/{file_name}")[:, :, ::-1] parsed_values = Parser.parse_time_limit(img) Parser.parse_label_level_locs(img) Parser.parse_status(img) for value, parsed_value in zip(values["time_limit"], parsed_values): try: assert value == parsed_value print(f"PASS: {value, parsed_value}") except AssertionError: print(f"FAILED: {value, parsed_value}")
class AssetManager: ASSETS = load_yaml(CONFIG_SCENE) @staticmethod def recur_resolve(dict_, keys): res = None for key in keys: res = dict_ = dict_[key] return res @classmethod def resolve(cls, asset_name, asset_type=None): """ Args: asset_name: asset_type: str, optional {"Eigen", "Image", "ImageRect", "ImageRect", "RelImageRect",} Returns: """ res = cls.recur_resolve(cls.ASSETS, asset_name.split(".")) if asset_type is None: return res return res[f"__{asset_type}"] @classmethod @lru_cache(maxsize=10) def rel_image_rect(cls, asset_name: str): return cls.resolve(asset_name, "RelImageRect") @classmethod def image(cls, asset_name: str): return cls.resolve(asset_name, "Image") @classmethod def image_rect(cls, asset_name: str): return cls.resolve(asset_name, "ImageRect") @classmethod def get_image_xywh(cls, asset_name): lt, rb = (point[:2] for point in cls.image_rect(asset_name)) return lt[0], lt[1], rb[0] - lt[0], rb[1] - lt[1] @classmethod def rect(cls, asset_name: str) -> List: return cls.resolve(asset_name, "Rect")[:2] @classmethod def eigen(cls, asset_name: str) -> Tuple[int, int, int]: return cls.resolve(asset_name, "Eigen") @classmethod def eigens(cls, *objects): if isinstance(objects, str): objects = [objects] it = itertools.chain.from_iterable( (cls.eigen(xy_rgb) for xy_rgb in objects)) return np.asarray(list(it), dtype=np.int32) @classmethod @lru_cache(maxsize=10) def template(cls, asset_name: str): """ Args: asset_name: str "/a/b/c", or "a.b.c" Returns: """ file_path_relative = cls.image( asset_name) if not asset_name.startswith("/") else asset_name return cv2.imread(f"{DIR_BASE}{file_path_relative}")[:, :, ::-1]
from util.io import load_yaml from util.win32 import win32gui BASE_DIR = f"{Path.home().as_posix()}/Pictures/AutoGame/AzurLane" EVENT_NAME = "斯图尔特的硝烟" STAGE = input("Input Stage Name:\n") RESULT_DIR = f"{BASE_DIR}/{EVENT_NAME}/{STAGE}" STAGE_RECT = [(1231, 617), (1553, 675)] print(f"Result Directory: {RESULT_DIR}") if (to_continue := input("Input y to continue, other to cancel: ")).lower() != "y": raise ValueError("exit...") Path(RESULT_DIR).mkdir(parents=True, exist_ok=True) scenes = load_yaml(CONFIG_SCENE) w1 = GameWindow(window_name="BS_AzurLane") w2 = GameWindow(window_hwnd=win32gui.FindWindowEx(w1.hwnd, None, None, None)) def log(s, log_level="INFO"): text = f"{dt.datetime.now().strftime('%Y-%m-%d %H:%M:%S')}|{log_level:<4}|{s}" print(text) return text class Config: sleep_time = 1 ended = False paused = True paused_after_battle = False
from pathlib import Path from telegram import Update from telegram.ext import CallbackContext from util.io import load_yaml CONFIG = load_yaml(Path(".").absolute().parent.parent / "config.yaml") class Command: __slots__ = ("value", "cmd") def __init__(self, value: int, cmd: str): self.value = value self.cmd = cmd def __lt__(self, other): return self.value < other def __le__(self, other): return self.value <= other def __gt__(self, other): return self.value > other def __ge__(self, other): return self.value >= other def __eq__(self, other): if isinstance(other, self.__class__):