- window_capture.py: enumerate top-level windows (pygetwindow) and capture a specific one via PrintWindow PW_RENDERFULLCONTENT (works on non-focused windows). Linux falls back to mss region grab. - recognizer.py: replace MAE matcher with NCC over numpy vectors. Each rotatable slab generates 4 templates (0/90/180/270). Adds 248 artifact templates and an empty-cell heuristic (low mean/std-dev). Cells below confidence floor are tagged "unknown" — likely merged "?" boxes. - gui.py: new ScreenshotFrame with [게임 창 선택] button → window picker dialog → bbox crop → recognize → editable preview grid with per-cell CellEditor that handles slab / artifact / merged(?) / empty. Merged cells let user pick which two slabs got combined + a level. - artifacts.py + bundled _artifacts.json (248 entries from WhiteDog1004/sephiria) for matching and rendering. - renderer.py: factored CDN fetch into _fetch_image; added fetch_artifact_image(). - requirements.txt: + numpy, pygetwindow (Win), pywin32 (Win). - docker-build-cmd.sh: upgrade PyInstaller to 5.x inside cdrx container so numpy DLL manifest reads work. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
43 lines
1.4 KiB
Python
43 lines
1.4 KiB
Python
"""Backward-compatible thin wrapper over the new recognizer.
|
|
|
|
The old API exposed `Recognition` (slot_id, value, score) and `recognize()`
|
|
returning slabs only. Existing CLI code (`__main__.py`) and tests use that
|
|
surface, so we keep it working by delegating to recognizer.py.
|
|
|
|
New code should call `recognizer.recognize_image()` / `recognize_file()`
|
|
directly for richer (kind, rotation, artifact) results.
|
|
"""
|
|
|
|
from __future__ import annotations
|
|
|
|
from dataclasses import dataclass
|
|
from typing import List, Optional, Tuple
|
|
|
|
from .recognizer import recognize_file
|
|
|
|
|
|
@dataclass
|
|
class Recognition:
|
|
slot_id: str
|
|
value: Optional[str] # slab value, or None if empty/unknown/artifact
|
|
score: float # NCC score in [-1, 1]; higher = better
|
|
|
|
|
|
def recognize(
|
|
screenshot_path: str,
|
|
bbox: Tuple[int, int, int, int],
|
|
slot_num: int = 34,
|
|
empty_threshold: float = 35.0, # ignored; kept for arg-compat
|
|
) -> List[Recognition]:
|
|
"""Recognize slabs in the inventory area of a screenshot (slabs only)."""
|
|
cells = recognize_file(screenshot_path, bbox, slot_num=slot_num)
|
|
out: List[Recognition] = []
|
|
for c in cells:
|
|
v = c.value if c.kind == "slab" else None
|
|
out.append(Recognition(c.slot_id, v, c.score))
|
|
return out
|
|
|
|
|
|
def recognized_values(recognitions: List[Recognition]) -> List[str]:
|
|
return [r.value for r in recognitions if r.value is not None]
|