Commit Graph
25 Commits
Author SHA1 Message Date
percoandClaude Sonnet 4.6 d6f95131bc Fix NameError in test-lpr endpoint (PLATERECOGNIZER_KEY scope)
PLATERECOGNIZER_KEY is defined in watcher.py, not main.py. Reference it
via watcher.PLATERECOGNIZER_KEY inside the executor closure, and wrap
_run() in a top-level try/except so exceptions always return JSON instead
of a 500 HTML page.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 16:44:15 +02:00
percoandClaude Sonnet 4.6 c43652d187 Add LPR test button in annotation UI
New POST /event/{id}/test-lpr endpoint runs PlateRecognizer on the full
frame and local OCR on the drawn bbox region (with perspective correction
when possible). Annotation UI shows results inline with a one-click
"Utiliser" button to copy the best plate into the input field.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 15:20:14 +02:00
percoandClaude Sonnet 4.6 ea4118ffcd Fix silent watcher thread death with watchdog supervisor
Move time.sleep inside the try/except to catch BaseException-level
failures, and wrap the watcher thread in a supervisor that auto-restarts
it within 5s if it ever exits unexpectedly.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 14:59:18 +02:00
percoandClaude Sonnet 4.6 31bb5d86c6 Crop thumbnail to vehicle area instead of full frame
When a plate bbox is detected, the snapshot thumbnail is now cropped
around the vehicle (plate bbox + generous margins) and resized to
≤1280px wide. This makes the grid on the index page much more useful.

The full best frame is saved separately as best_frame.jpg and used
as the main image in the event detail view. Without a plate bbox,
fallback crops the center 80% of the frame.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 11:14:25 +02:00
percoandClaude Sonnet 4.6 00368fba0d Fix annotation canvas resolution and fullres button
Canvas now uses img.naturalWidth/Height as its coordinate space
so zooming in shows actual 4K pixels instead of upscaled 800px.
CSS width/height handle display scaling separately.

Replace window.open() fullres button (blocked by popup blockers)
with a direct <a target="_blank"> link updated on frame select.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 10:52:26 +02:00
percoandClaude Sonnet 4.6 01c5363649 Add zoom and pan to annotation canvas and event detail lightbox
Annotation canvas:
- Mouse wheel: zoom centered on cursor (1×→20×)
- Right-click drag or Space+drag: pan
- Two-finger pinch-to-zoom on touch devices
- Bbox coordinates computed in logical image space (zoom-invariant)
- "Plein écran" button opens current frame in new tab at full res
- Zoom % indicator + reset button

Event detail lightbox:
- Mouse wheel: zoom in/out (0.5×→20×)
- Drag to pan when zoomed in
- "Ouvrir en plein écran" link opens raw frame at native 4K in new tab
- Zoom resets on image change or lightbox close

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 10:42:37 +02:00
percoandClaude Sonnet 4.6 fd52942bd1 Add annotation UI for building a custom training dataset
New page /event/{id}/annotate:
- Frame selector grid (all frames from the event)
- Canvas with click-and-drag rectangle drawing to mark the plate bbox
- Touch support for tablets
- Plate text input (pre-filled with auto-detected plate)
- Saves image + YOLO label (.txt) + plates.csv to /data/annotations/
- Stores annotation metadata in DB (annotations table)

/dataset/export serves a ZIP with images/, labels/, plates.csv and
a data.yaml ready for YOLOv8/v9 fine-tuning on Google Colab.

"Annoter" button added to event detail header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 10:34:09 +02:00
percoandClaude Sonnet 4.6 9b3720c424 Normalize French plates, filter invalid lengths, reduce frame rate
- Add _normalize_plate(): strips non-alphanumeric, rejects < 6 or
  > 8 chars, formats standard new French plates as AB-123-CD
- Applied after PlateRecognizer and local LPR results
- CAPTURE_DURATION 15→20s, CAPTURE_FPS 5→2fps (40 frames vs 75)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-03 09:18:56 +02:00
percoandClaude Sonnet 4.6 30561c44de Improve whitelist UX: inline label edit and label prompt from stats
Whitelist page: each entry now shows an editable label field inline
(uses INSERT OR REPLACE so it acts as update). Stats page: the
whitelist button expands a small dropdown with a label input before
confirming.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:41:34 +02:00
percoandClaude Sonnet 4.6 ea58a860b8 Add vehicle whitelist and per-plate passage statistics
Whitelist: plates added to /whitelist are silently ignored on
detection — no clip, no frames, no DB entry. Manageable via
/whitelist page or from the event detail page per-event.

Stats: /stats shows all known plates ranked by passage count,
with first/last seen dates and one-click whitelist toggle.

Navigation links added to the index header.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 22:33:53 +02:00
percoandClaude Sonnet 4.6 bd890f111e Fix ValueError: use 'is not None' for numpy array truthiness check
'if quad else None' raises ValueError on a numpy array with more
than one element. Replace with 'if quad is not None else None'.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 21:55:38 +02:00
percoandClaude Sonnet 4.6 76913d7b52 Fix frame selection: use motion score to find vehicle-present frames
Pure sharpness ranking fails when a moving car causes motion blur —
blurry car frames score lower than the sharp static background, so
YOLO never sees the vehicle. Now compute inter-frame motion diff
(downscaled to 320px, fast) alongside sharpness, then combine
(65% motion + 35% sharpness) to select the top 15 frames for YOLO.
This ensures the vehicle-present frames reach YOLO and PlateRecognizer
even when they are slightly blurred.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 20:34:22 +02:00
percoandClaude Sonnet 4.6 6aac633862 Integrate PlateRecognizer API as primary ANPR engine
Adds call_platerecognizer() to lpr.py which sends frames to the
PlateRecognizer cloud API (regions=fr) with a 1920px cap to stay
within API limits. In watcher.py, switches to a two-pass frame
scoring strategy: Laplacian sharpness on all frames first, then
YOLO only on the top-10 sharpest frames, then PlateRecognizer on
the top-3 by score. Falls back to local YOLO+Tesseract/PaddleOCR
if the API returns no result.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 19:05:34 +02:00
percoandClaude Sonnet 4.6 accbae41ce Add delete event, perspective correction OCR, and OCR crop display
- Delete event: POST /event/{id}/delete removes DB row + files
- Perspective correction: minAreaRect on white plate region → getPerspectiveTransform
  gives a flat frontal view of the plate (e.g. 'GR B38 WR' instead of trapezoid)
- Tesseract now scales image 3x before OCR and skips EU blue strip (left 11%)
- Saves plate_ocr.jpg (perspective-corrected + enhanced crop actually fed to OCR)
- Event detail shows both raw detection crop and OCR crop side by side
- Manual plate edit form in event detail

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 18:05:10 +02:00
percoandClaude Sonnet 4.6 13e6038069 Improve LPR accuracy and add manual plate edit
- Tiled YOLO (3x2, 20% overlap): plate confidence 0.307 -> 0.838 on test frame
- Aspect ratio filter (2.0-6.5:1): rejects non-plate shapes
- Confidence threshold 0.03 -> 0.04: removes fence/noise false positives
- Exclude top 15% (sky) and bottom 8% (timestamp overlay) from detection zone
- Add Tesseract as primary OCR (better for Latin plates), PaddleOCR as fallback
- Enhance plate crop before OCR: CLAHE + sharpening + min 80px upscale
- Save plate_crop.jpg (4x upscaled) to event dir for manual review
- Show plate crop in event detail page
- Add manual plate edit form in event detail (POST /event/{id}/plate)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 17:45:50 +02:00
percoandClaude Sonnet 4.6 92f435935e Extract frames at full resolution before transcoding clip for browser
Previously frames were extracted after the 720p transcode, resulting in 1280x720
images even when the source was 4K. Now frames are extracted from the original
clip first, then the clip is transcoded to 720p for web playback.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 17:19:53 +02:00
percoandClaude Sonnet 4.6 ec214ed7b2 Add MP4 upload endpoint for testing pipeline without live camera
POST /upload saves the file, runs full processing (transcode, frame extraction,
LPR, color detection) and redirects to the resulting event page.
UI: "Tester un clip" button in header reveals a file picker form.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 17:15:49 +02:00
percoandClaude Sonnet 4.6 5594010d78 Fix NameError: replace undefined 'kept' with 'frame_files' in log line
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:45:42 +02:00
percoandClaude Sonnet 4.6 d333a29c4c Fix encodage clip : H.264 baseline 720p CRF28 pour compatibilité navigateur
- Transcode clip en H.264 baseline level 3.1 (compatible tous navigateurs)
- Downsample à 720p pour réduire la taille (17MB raw → ~2.5MB encodé)
- CRF 28 + preset fast = bon compromis qualité/vitesse
- Sans audio (inutile pour surveillance)
- -movflags +faststart pour lecture streaming sans téléchargement complet

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:42:52 +02:00
percoandClaude Sonnet 4.6 6aae4ef40c Toutes les frames, clip web-compatible, lightbox plein écran
- Garde toutes les frames (plus de limite TOP_FRAMES), triées score LPR desc
- Clip remuxé avec -movflags +faststart pour lecture directe navigateur + lien téléchargement
- Lightbox : double-clic sur frame → plein écran, navigation ←/→, Échap pour fermer
- Grille 8 colonnes pour voir toutes les frames

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:37:44 +02:00
percoandClaude Sonnet 4.6 8c2af7dfab Fix couleur véhicule, supprime filtre caméra, améliore debug
- Couleur : crop autour de la plaque (zone carrosserie au-dessus) au lieu du frame entier ; fallback center 50% si pas de plaque
- lpr.read_plate() retourne maintenant (text, conf, bbox) pour exposer la position de la plaque
- Index : supprime filtre caméra et badge caméra (une seule caméra)
- Carte index : badge ▶ clip si clip disponible
- Page détail : section debug (nb frames, taille clip, id), gestion propre des anciens événements sans clip/frames

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 16:19:29 +02:00
percoandClaude Sonnet 4.6 528a158c42 Ajoute vue détail par passage (clip + galerie frames)
- Sauvegarde le clip MP4 et les top 10 frames par événement dans /data/events/{id}/
- Nouvelle route GET /event/{id} avec page détail : info, vignette interactive, lecteur vidéo, galerie frames
- Les cartes de l'index sont maintenant cliquables
- Migration DB : ajout colonne clip_path sur les BDD existantes

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 15:52:12 +02:00
percoandClaude Sonnet 4.6 8507987ea9 Capture ffmpeg 5fps/15s au lieu de OpenCV 1fps/20s
- Remplace OpenCV VideoCapture par ffmpeg pour la capture RTSP (plus fiable)
- Capture 15s → extrait ~75 frames à 5fps via ffmpeg
- Le LPR analyse toutes les frames et garde la meilleure (plaque la plus grande/confiante)
- Ajoute CAPTURE_FPS env var

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 15:48:12 +02:00
percoandClaude Sonnet 4.6 65b74ce46d Passe de Frigate polling à GetAiState Reolink + LPR ONNX local
- Remplace la source Frigate par l'API GetAiState de la caméra Reolink
- Capture RTSP en temps réel (~20s) quand véhicule détecté, garde la meilleure frame
- LPR avec YOLOv9 (détection plaque) + PaddleOCR v4 (lecture texte) via ONNX
- Modèles partagés avec Frigate (volume local ./models/)
- Cooldown 60s entre événements pour éviter les doublons

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:49:49 +02:00
percoandClaude Sonnet 4.6 f6422b0e7e feat: initial CamWatch service
Polls Frigate events API, extracts dominant vehicle color (KMeans),
reads LPR plate from Frigate sub_label. Responsive dark UI with
filter by plate/camera/date and auto-refresh. FastAPI + SQLite.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-02 14:10:05 +02:00