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>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
92f435935e
commit
13e6038069
+14
-1
@@ -5,7 +5,7 @@ import threading
|
||||
import tempfile
|
||||
import asyncio
|
||||
from contextlib import asynccontextmanager
|
||||
from fastapi import FastAPI, Request, Query, HTTPException, UploadFile, File
|
||||
from fastapi import FastAPI, Request, Query, HTTPException, UploadFile, File, Form
|
||||
from fastapi.responses import HTMLResponse, RedirectResponse
|
||||
from fastapi.staticfiles import StaticFiles
|
||||
from fastapi.templating import Jinja2Templates
|
||||
@@ -103,12 +103,16 @@ async def event_detail(request: Request, event_id: str):
|
||||
size = os.path.getsize(clip_abs)
|
||||
clip_size = f"{size // 1024 // 1024}MB" if size > 1024 * 1024 else f"{size // 1024}KB"
|
||||
|
||||
plate_crop_abs = os.path.join(event_dir, "plate_crop.jpg")
|
||||
plate_crop = f"events/{event_id}/plate_crop.jpg" if os.path.exists(plate_crop_abs) else None
|
||||
|
||||
return templates.TemplateResponse("event_detail.html", {
|
||||
"request": request,
|
||||
"ev": ev,
|
||||
"frames": frames,
|
||||
"has_clip": has_clip,
|
||||
"clip_size": clip_size,
|
||||
"plate_crop": plate_crop,
|
||||
"capture_duration": CAPTURE_DURATION,
|
||||
"capture_fps": CAPTURE_FPS,
|
||||
"capture_total": CAPTURE_DURATION * CAPTURE_FPS,
|
||||
@@ -136,6 +140,15 @@ async def api_events(
|
||||
return {"events": events, "total": total}
|
||||
|
||||
|
||||
@app.post("/event/{event_id}/plate")
|
||||
async def update_plate(event_id: str, plate: str = Form("")):
|
||||
ev = database.get_event(event_id)
|
||||
if not ev:
|
||||
raise HTTPException(status_code=404, detail="Événement introuvable")
|
||||
database.update_plate(event_id, plate)
|
||||
return RedirectResponse(f"/event/{event_id}", status_code=303)
|
||||
|
||||
|
||||
@app.post("/upload")
|
||||
async def upload_clip(file: UploadFile = File(...)):
|
||||
if not file.filename.lower().endswith(".mp4"):
|
||||
|
||||
Reference in New Issue
Block a user