Spaces:
Sleeping
Sleeping
| """Standalone CLI runner for the LSF interpreter (no web server). | |
| Opens a window showing the live camera feed with the holistic skeleton drawn on | |
| top and the running transcription printed in the console and on-screen. | |
| Keys | |
| ---- | |
| q / Esc : quit | |
| r : start recording a sign sample; you'll be asked for its gloss in the | |
| console, then perform the sign. Press s to save it as a template. | |
| s : stop + save the current recording | |
| c : clear the on-screen transcript | |
| For the Django web UI instead, run: python web/manage.py runserver | |
| """ | |
| from __future__ import annotations | |
| import argparse | |
| import sys | |
| import time | |
| from collections import deque | |
| import cv2 | |
| from lsf.camera import InterpreterPipeline | |
| def parse_args() -> argparse.Namespace: | |
| p = argparse.ArgumentParser(description="French Sign Language interpreter (CLI).") | |
| p.add_argument("--camera", type=int, default=0, help="Camera index (default 0).") | |
| p.add_argument( | |
| "--templates", | |
| default="signs/lsf_signs.json", | |
| help="Path to the learned-sign templates file.", | |
| ) | |
| p.add_argument("--model", default=None, help="Optional Keras model.h5 path.") | |
| p.add_argument( | |
| "--monocular-depth", | |
| action="store_true", | |
| help="Enable MiDaS monocular depth fallback (needs torch installed).", | |
| ) | |
| return p.parse_args() | |
| def main() -> int: | |
| args = parse_args() | |
| cap = cv2.VideoCapture(args.camera) | |
| if not cap.isOpened(): | |
| print(f"Error: could not open camera index {args.camera}.", file=sys.stderr) | |
| return 1 | |
| pipeline = InterpreterPipeline( | |
| templates_path=args.templates, | |
| model_path=args.model, | |
| enable_monocular_depth=args.monocular_depth, | |
| ) | |
| pipeline.probe_depth(cap) | |
| print(f"Depth source: {pipeline.depth.status} ({pipeline.depth.reason})") | |
| print("Press 'r' to record a sign, 's' to save, 'c' to clear, 'q' to quit.") | |
| transcript: deque[str] = deque(maxlen=8) | |
| recording = False | |
| fps = 0.0 | |
| last = time.time() | |
| try: | |
| while True: | |
| ok, frame = cap.read() | |
| if not ok: | |
| break | |
| frame = cv2.flip(frame, 1) | |
| result = pipeline.process(frame) | |
| if result.recognition is not None: | |
| line = f"{result.recognition.gloss} ({result.recognition.confidence:.2f})" | |
| transcript.append(line) | |
| print("→", line) | |
| now = time.time() | |
| fps = 0.9 * fps + 0.1 * (1.0 / max(now - last, 1e-3)) | |
| last = now | |
| _draw_overlay(result.annotated, transcript, result.depth_source, fps, recording) | |
| cv2.imshow("LSF interpreter", result.annotated) | |
| key = cv2.waitKey(1) & 0xFF | |
| if key in (ord("q"), 27): | |
| break | |
| elif key == ord("r") and not recording: | |
| label = input("Gloss for this sign (then perform it): ").strip() | |
| if label: | |
| pipeline.recognizer.start_recording(label) | |
| recording = True | |
| print(f"Recording '{label}'… press 's' to save.") | |
| elif key == ord("s") and recording: | |
| saved = pipeline.recognizer.stop_recording() | |
| recording = False | |
| print(f"Saved template: {saved}" if saved else "Recording too short, discarded.") | |
| elif key == ord("c"): | |
| transcript.clear() | |
| finally: | |
| cap.release() | |
| cv2.destroyAllWindows() | |
| pipeline.close() | |
| return 0 | |
| def _draw_overlay(frame, transcript, depth_source, fps, recording) -> None: | |
| h = frame.shape[0] | |
| status = "REC" if recording else "" | |
| hud = f"depth:{depth_source} fps:{fps:0.0f} {status}" | |
| cv2.putText(frame, hud, (10, 24), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 4) | |
| cv2.putText(frame, hud, (10, 24), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 128), 1) | |
| for i, line in enumerate(list(transcript)[-6:]): | |
| y = h - 20 - (5 - i) * 26 | |
| cv2.putText(frame, line, (10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 0), 4) | |
| cv2.putText(frame, line, (10, y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 1) | |
| if __name__ == "__main__": | |
| raise SystemExit(main()) | |