plaque_immat / app.py
AkCoooo
Masquer le pied de page lors du lancement de l'interface utilisateur
48cc13b
# app_yolo11_blur_nomargin.py
from pathlib import Path
import cv2
import numpy as np
import os, time, tempfile
import gradio as gr
from ultralytics import YOLO
from huggingface_hub import hf_hub_download
from PIL import Image
# ========= CONFIG =========
DEVICE = "cpu" # "cpu" ou "cuda:0" si GPU visible
CONF_DEFAULT = 0.30
IOU_DEFAULT = 0.50
BLUR_DEFAULT = 0.28
FEATHER_DEFAULT = 8
weights_path = hf_hub_download(
repo_id="morsetechlab/yolov11-license-plate-detection",
filename="license-plate-finetune-v1l.pt"
)
model = YOLO(weights_path)
# ========= BLUR SANS MARGE (bord doux interne) =========
def blur_bbox_nomargin(img, x1, y1, x2, y2, blur_strength=BLUR_DEFAULT, feather=FEATHER_DEFAULT):
H, W = img.shape[:2]
x1, y1 = max(0, x1), max(0, y1)
x2, y2 = min(W, x2), min(H, y2)
w, h = x2 - x1, y2 - y1
if w <= 0 or h <= 0:
return img
# flou global puis composition dans la bbox via masque (aucune marge)
k = int(max(w, h) * blur_strength)
k = max(31, (k // 2) * 2 + 1) # noyau impair, min 31 => flou smooth
blurred_full = cv2.GaussianBlur(img, (k, k), 0)
mask = np.zeros((H, W), dtype=np.uint8)
cv2.rectangle(mask, (x1, y1), (x2, y2), 255, thickness=-1)
if feather > 0:
# feather vers l'intérieur du rectangle (ne déborde pas)
obj = (mask > 0).astype(np.uint8)
dist = cv2.distanceTransform(obj, distanceType=cv2.DIST_L2, maskSize=3)
alpha = np.clip(dist / float(feather), 0.0, 1.0)
else:
alpha = (mask.astype(np.float32) / 255.0)
alpha = alpha[..., None]
out = (alpha * blurred_full + (1.0 - alpha) * img).astype(np.uint8)
return out
# ========= PIPELINE (avec étapes UI) =========
def process_and_toggle(image):
"""
Générateur pour:
1) cacher l'étape 1, montrer l'étape 2 (message 'Traitement...')
2) faire le traitement, produire l'image + fichier .jpg + log
"""
# 1) toggle immédiat
yield (None, None, gr.update(visible=False), gr.update(visible=True))
# 2) traitement
if image is None:
yield (None, None, gr.update(visible=True), gr.update(visible=False))
return
bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
results = model.predict(source=bgr, conf=CONF_DEFAULT, iou=IOU_DEFAULT, device=DEVICE, verbose=False)
out = bgr.copy()
total = 0
for r in results:
if r.boxes is None:
continue
for (x1, y1, x2, y2) in r.boxes.xyxy.cpu().numpy().astype(int):
# feather effectif borné à la moitié de la bbox (évite artefacts)
w, h = x2 - x1, y2 - y1
f_eff = min(int(FEATHER_DEFAULT), max(w // 2 - 1, 0), max(h // 2 - 1, 0))
out = blur_bbox_nomargin(out, x1, y1, x2, y2,
blur_strength=float(BLUR_DEFAULT),
feather=f_eff)
total += 1
out_rgb = cv2.cvtColor(out, cv2.COLOR_BGR2RGB)
# Fichier .JPG
ts = time.strftime("%Y%m%d_%H%M%S")
fname = f"plaque_floutee_{ts}.jpg"
fpath = os.path.join(tempfile.gettempdir(), fname)
Image.fromarray(out_rgb).save(fpath, format="JPEG", quality=92)
yield (out_rgb, fpath, gr.update(visible=False), gr.update(visible=True))
def reset_ui():
# réinitialise l'affichage (retour à l'étape 1)
return None, None, gr.update(visible=True), gr.update(visible=False)
# ========= UI =========
with gr.Blocks(title="🚗 Floutage de plaques d'immatriculation") as demo:
gr.Markdown("### 📸 Dépose une image 🟦 Clique sur **Flouter** 💾 Télécharge ta voiture avec plaque d'immatriculation flouté")
step1 = gr.Column(visible=True)
with step1:
with gr.Row():
with gr.Column():
inp = gr.Image(type="numpy", label="Image")
btn = gr.Button("Flouter 🔒")
step2 = gr.Column(visible=False)
with step2:
out_img = gr.Image(type="numpy", label="Aperçu flouté 👀")
out_file = gr.File(label="Télécharger en JPG 💾")
back_btn = gr.Button("Recommencer 🔄")
# clic: on stream d'abord le toggle, puis l'image/fichier
btn.click(
fn=process_and_toggle,
inputs=[inp],
outputs=[out_img, out_file, step1, step2],
queue=True # permet le 'yield'
)
# bouton retour
back_btn.click(
fn=reset_ui,
inputs=[],
outputs=[out_img, out_file, step1, step2],
)
if __name__ == "__main__":
demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")), show_footer=False)