feat(cli): atm debug — one-shot capture + detect + annotated PNG
Quick sanity check after calibration. Prints window/dot detection state, classified colour + confidence, saves full/cropped/annotated frames to logs/. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -62,6 +62,9 @@ def main(argv=None) -> None:
|
|||||||
metavar="PATH", help="Journal JSONL file (default: trades.jsonl)",
|
metavar="PATH", help="Journal JSONL file (default: trades.jsonl)",
|
||||||
)
|
)
|
||||||
|
|
||||||
|
# debug
|
||||||
|
sub.add_parser("debug", help="Capture one frame, run detector, annotate + print result")
|
||||||
|
|
||||||
# report
|
# report
|
||||||
p_report = sub.add_parser("report", help="Print weekly performance report")
|
p_report = sub.add_parser("report", help="Print weekly performance report")
|
||||||
p_report.add_argument(
|
p_report.add_argument(
|
||||||
@@ -80,6 +83,7 @@ def main(argv=None) -> None:
|
|||||||
"label": _cmd_label,
|
"label": _cmd_label,
|
||||||
"dryrun": _cmd_dryrun,
|
"dryrun": _cmd_dryrun,
|
||||||
"run": _cmd_run,
|
"run": _cmd_run,
|
||||||
|
"debug": _cmd_debug,
|
||||||
"journal": _cmd_journal,
|
"journal": _cmd_journal,
|
||||||
"report": _cmd_report,
|
"report": _cmd_report,
|
||||||
}
|
}
|
||||||
@@ -140,6 +144,72 @@ def _cmd_journal(args) -> None:
|
|||||||
j.add(entry)
|
j.add(entry)
|
||||||
|
|
||||||
|
|
||||||
|
def _cmd_debug(args) -> None:
|
||||||
|
"""One-shot capture + detect. Saves annotated PNG. Prints classification."""
|
||||||
|
from datetime import datetime
|
||||||
|
try:
|
||||||
|
from atm.detector import Detector
|
||||||
|
from atm.vision import crop_roi
|
||||||
|
except ImportError as exc:
|
||||||
|
sys.exit(f"debug module deps missing: {exc}")
|
||||||
|
|
||||||
|
cfg = Config.load_current(Path("configs"))
|
||||||
|
capture = _build_capture(cfg)
|
||||||
|
frame = capture()
|
||||||
|
if frame is None:
|
||||||
|
sys.exit("capture returned None (window not found or region invalid)")
|
||||||
|
|
||||||
|
out_dir = Path("logs")
|
||||||
|
out_dir.mkdir(exist_ok=True)
|
||||||
|
ts = datetime.now().strftime("%Y%m%d_%H%M%S")
|
||||||
|
|
||||||
|
import cv2 # type: ignore[import-untyped]
|
||||||
|
full_path = out_dir / f"debug_full_{ts}.png"
|
||||||
|
cv2.imwrite(str(full_path), frame)
|
||||||
|
print(f"captured frame: {frame.shape} → {full_path}")
|
||||||
|
|
||||||
|
# crop dot_roi + run detector
|
||||||
|
try:
|
||||||
|
dot_crop = crop_roi(frame, cfg.dot_roi)
|
||||||
|
dot_path = out_dir / f"debug_dot_roi_{ts}.png"
|
||||||
|
cv2.imwrite(str(dot_path), dot_crop)
|
||||||
|
print(f"dot_roi crop: {dot_crop.shape} → {dot_path}")
|
||||||
|
except Exception as exc:
|
||||||
|
sys.exit(f"dot_roi crop failed: {exc}")
|
||||||
|
|
||||||
|
det = Detector(cfg, capture)
|
||||||
|
res = det.step(0.0)
|
||||||
|
print("---")
|
||||||
|
print(f"window_found: {res.window_found}")
|
||||||
|
print(f"dot_found: {res.dot_found}")
|
||||||
|
if res.match is not None:
|
||||||
|
print(f"rgb: {res.rgb}")
|
||||||
|
print(f"classified: {res.match.name} distance={res.match.distance:.1f} confidence={res.match.confidence:.2f}")
|
||||||
|
else:
|
||||||
|
print("no match (dot not found or UNKNOWN classification)")
|
||||||
|
print(f"accepted: {res.accepted} color={res.color}")
|
||||||
|
|
||||||
|
# Annotate: draw dot_roi rect + mark detected dot
|
||||||
|
annotated = frame.copy()
|
||||||
|
x, y, w, h = cfg.dot_roi.x, cfg.dot_roi.y, cfg.dot_roi.w, cfg.dot_roi.h
|
||||||
|
cv2.rectangle(annotated, (x, y), (x + w, y + h), (0, 255, 255), 2)
|
||||||
|
if res.dot_found and res.match is not None:
|
||||||
|
# re-find dot to know exact x,y for annotation
|
||||||
|
from atm.vision import find_rightmost_dot
|
||||||
|
bg_rgb = (18, 18, 18)
|
||||||
|
if "background" in cfg.colors:
|
||||||
|
bg_rgb = cfg.colors["background"].rgb
|
||||||
|
dot_crop = crop_roi(frame, cfg.dot_roi)
|
||||||
|
pos = find_rightmost_dot(dot_crop, bg_rgb)
|
||||||
|
if pos is not None:
|
||||||
|
dx, dy = pos
|
||||||
|
cx, cy = x + dx, y + dy
|
||||||
|
cv2.circle(annotated, (cx, cy), 12, (0, 0, 255), 3)
|
||||||
|
annotated_path = out_dir / f"debug_annotated_{ts}.png"
|
||||||
|
cv2.imwrite(str(annotated_path), annotated)
|
||||||
|
print(f"annotated: {annotated_path}")
|
||||||
|
|
||||||
|
|
||||||
def _cmd_report(args) -> None:
|
def _cmd_report(args) -> None:
|
||||||
try:
|
try:
|
||||||
from atm.journal import Journal
|
from atm.journal import Journal
|
||||||
|
|||||||
Reference in New Issue
Block a user