|
5 | 5 | from dataclasses import dataclass
|
6 | 6 | from typing import Optional
|
7 | 7 |
|
| 8 | +import time |
| 9 | +import math |
| 10 | + |
8 | 11 | import cv2
|
9 | 12 | import numpy as np
|
10 | 13 | import numpy.typing
|
| 14 | +from numpy.typing import NDArray |
11 | 15 | from winrt.windows.media.ocr import OcrEngine
|
12 | 16 | from winrt.windows.globalization import Language
|
13 | 17 | from winrt.windows.graphics.imaging import *
|
14 | 18 | from winrt.windows.security.cryptography import CryptographicBuffer
|
15 | 19 |
|
16 |
| -from enum import Enum, auto |
| 20 | +from logging import getLogger |
17 | 21 |
|
| 22 | +root = getLogger() |
18 | 23 |
|
19 |
| -class OCRMode(Enum): |
20 |
| - SUMMON = auto() |
21 |
| - UNKNOWN = auto() |
22 |
| - INSPECT = auto() |
23 |
| - CREATURES_DISPLAY = auto() |
24 |
| - SELECT_GODFORGE_AVATAR = auto() |
25 |
| - CREATURE_REORDER_SELECT = auto() |
26 |
| - CREATURE_REORDER_WITH = auto() |
27 | 24 |
|
28 | 25 | # Modified from https://gist.github.com/dantmnf/23f060278585d6243ffd9b0c538beab2
|
29 | 26 |
|
@@ -192,7 +189,7 @@ def english_installed() -> bool:
|
192 | 189 |
|
193 | 190 |
|
194 | 191 | def detect_green_text(image: np.typing.ArrayLike, x_start: float = 0.0, x_end: float = 1.0, y_start: float = 0.0,
|
195 |
| - y_end: float = 1.0) -> np.typing.ArrayLike: |
| 192 | + y_end: float = 1.0) -> NDArray: |
196 | 193 | """Using a source image of RGB color, extract highlighted menu items which are a green color"""
|
197 | 194 | lower_green = np.array([60, 50, 100])
|
198 | 195 | upper_green = np.array([60, 255, 255])
|
@@ -243,16 +240,66 @@ def detect_title(frame: np.typing.ArrayLike) -> np.typing.ArrayLike:
|
243 | 240 | return mask
|
244 | 241 |
|
245 | 242 |
|
246 |
| -def detect_dialog_text(frame: np.typing.ArrayLike) -> np.typing.ArrayLike: |
247 |
| - y_start = int(frame.shape[0] * 0.70) |
248 |
| - y_end = int(frame.shape[0] * 0.95) |
249 |
| - x_start = int(frame.shape[1] * 0.01) |
250 |
| - x_end = int(frame.shape[1] * 0.995) |
| 243 | +def timeit(func): |
| 244 | + def wrap_timer(*args, **kwargs): |
| 245 | + t1 = time.time() |
| 246 | + value = func(*args, **kwargs) |
| 247 | + t2 = time.time() |
| 248 | + took = t2 - t1 |
| 249 | + print(f"{func.__name__!r} took {math.ceil(took * 1000)}ms") |
| 250 | + return value |
| 251 | + |
| 252 | + return wrap_timer |
| 253 | + |
| 254 | + |
| 255 | +def detect_dialog_text(frame: NDArray, gray_frame: NDArray, ocr_engine: OCR) -> Optional[str]: |
| 256 | + """detect dialog text from frame |
| 257 | +
|
| 258 | + :param gray_frame BGR whole window frame |
| 259 | + :param ocr_engine: engine that can perform OCR on image |
| 260 | + """ |
| 261 | + y_start = int(gray_frame.shape[0] * 0.70) |
| 262 | + y_end = int(gray_frame.shape[0] * 0.95) |
| 263 | + x_start = int(gray_frame.shape[1] * 0.01) |
| 264 | + x_end = int(gray_frame.shape[1] * 0.995) |
251 | 265 | dialog_area = frame[y_start:y_end, x_start:x_end]
|
| 266 | + # output = np.ones(dialog_area.shape, dtype='uint8') |
| 267 | + # output[dialog_area > 180] = 255 |
| 268 | + # mask = output |
252 | 269 |
|
253 | 270 | img = cv2.cvtColor(dialog_area, cv2.COLOR_BGR2HLS)
|
254 | 271 | sensitivity = 30
|
255 | 272 | lower_white = np.array([0, 255 - sensitivity, 0])
|
256 | 273 | upper_white = np.array([0, 255, 0])
|
257 | 274 | mask = cv2.inRange(img, lower_white, upper_white)
|
258 |
| - return mask |
| 275 | + |
| 276 | + # resize_factor = 2 |
| 277 | + # mask = cv2.resize(mask, (mask.shape[1] * resize_factor, mask.shape[0] * resize_factor), |
| 278 | + # interpolation=cv2.INTER_LINEAR) |
| 279 | + ocr_result = ocr_engine.recognize_cv2_image(mask) |
| 280 | + try: |
| 281 | + first_line = ocr_result.lines[0] |
| 282 | + first_word = first_line.words[0] |
| 283 | + bbox = first_word.bounding_rect |
| 284 | + root.debug(f"dialog box: {ocr_result.text}") |
| 285 | + |
| 286 | + # health bar text - rect(69, 87, 73, 16), rect(282, 87, 71, 16) |
| 287 | + # dialog box text - rect(14, 23, 75, 16) |
| 288 | + |
| 289 | + offset_x = mask.shape[0] * 0.40 |
| 290 | + root.debug(f"{offset_x=}") |
| 291 | + is_not_dialog_box = bbox.x > offset_x |
| 292 | + root.debug(f"{is_not_dialog_box=}") |
| 293 | + if is_not_dialog_box: |
| 294 | + return None |
| 295 | + return ocr_result.merged_text |
| 296 | + # if is_not_dialog_box and not self.has_menu_entry_text: |
| 297 | + # return |
| 298 | + except IndexError: |
| 299 | + root.debug("no dialog text") |
| 300 | + return None |
| 301 | + # no text was found |
| 302 | + if not self.has_menu_entry_text and not self.has_dialog_text and not self.quest_text: |
| 303 | + root.info("Pause, menu system. both not present") |
| 304 | + self.audio_system.silence() |
| 305 | + return |
0 commit comments