Files
sephiria_inv_program/sephiria_inv/screenshot.py
Claude 2e23ad5d2f v0.3.0: game-window picker + NCC recognition + artifacts + ?-merged
- 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>
2026-05-14 09:36:49 +09:00

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]