AkCoooo commited on
Commit
7f77870
·
verified ·
1 Parent(s): b55a401

Upload 2 files

Browse files
Files changed (2) hide show
  1. app.py +126 -0
  2. requirements.txt +0 -0
app.py ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # app_yolo11_blur_nomargin.py
2
+ from pathlib import Path
3
+ import cv2
4
+ import numpy as np
5
+ import gradio as gr
6
+ from ultralytics import YOLO
7
+ from huggingface_hub import hf_hub_download
8
+
9
+
10
+ # ===== CONFIG =====
11
+ DEVICE = "cpu" # "cpu" ou "cuda:0"
12
+ CONF_DEFAULT = 0.30
13
+ IOU_DEFAULT = 0.50
14
+
15
+ weights_path = hf_hub_download(
16
+ repo_id="morsetechlab/yolov11-license-plate-detection",
17
+ filename="license-plate-finetune-v1l.pt"
18
+ )
19
+ model = YOLO(weights_path)
20
+
21
+ # ===== BLUR SANS MARGE =====
22
+ def blur_bbox_nomargin(img, x1, y1, x2, y2, blur_strength=0.24, feather=8):
23
+ """
24
+ Floute exactement la bbox YOLO (aucune marge).
25
+ - feather (px) : adoucit seulement À L'INTÉRIEUR du rectangle (pas de débordement).
26
+ Mets 0 pour un bord net.
27
+ """
28
+ H, W = img.shape[:2]
29
+ x1, y1 = max(0, x1), max(0, y1)
30
+ x2, y2 = min(W, x2), min(H, y2)
31
+ w, h = x2 - x1, y2 - y1
32
+ if w <= 0 or h <= 0:
33
+ return img
34
+
35
+ # flou global (on compositera avec un masque)
36
+ k = int(max(w, h) * blur_strength)
37
+ k = max(31, (k // 2) * 2 + 1) # impair, min 31 pour un rendu smooth
38
+ blurred_full = cv2.GaussianBlur(img, (k, k), 0)
39
+
40
+ # masque rectangulaire strict (aucune marge)
41
+ mask = np.zeros((H, W), dtype=np.uint8)
42
+ cv2.rectangle(mask, (x1, y1), (x2, y2), 255, thickness=-1)
43
+
44
+ if feather > 0:
45
+ # Feather interne (ne dépasse pas le rectangle) via distance transform
46
+ # alpha = 1 au cœur, 0 au bord du rectangle, transition sur 'feather' px
47
+ # (évite l'élargissement qu'on aurait avec un simple Gaussian sur le masque)
48
+ obj = (mask > 0).astype(np.uint8) # 0/1
49
+ dist = cv2.distanceTransform(obj, distanceType=cv2.DIST_L2, maskSize=3)
50
+ # clips: 0..feather -> 0..1
51
+ alpha = np.clip(dist / float(feather), 0.0, 1.0)
52
+ else:
53
+ alpha = (mask.astype(np.float32) / 255.0)
54
+
55
+ alpha = alpha[..., None] # HxWx1
56
+ out = (alpha * blurred_full + (1.0 - alpha) * img).astype(np.uint8)
57
+ return out
58
+
59
+ # ===== PIPELINE =====
60
+ def anonymize(image, conf=CONF_DEFAULT, iou=IOU_DEFAULT, blur_strength=0.24, feather=8):
61
+ if image is None:
62
+ return None, "Aucune image."
63
+ bgr = cv2.cvtColor(image, cv2.COLOR_RGB2BGR)
64
+
65
+ results = model.predict(source=bgr, conf=conf, iou=iou, device=DEVICE, verbose=False)
66
+
67
+ out = bgr.copy()
68
+ total = 0
69
+ for r in results:
70
+ if r.boxes is None:
71
+ continue
72
+ for (x1, y1, x2, y2) in r.boxes.xyxy.cpu().numpy().astype(int):
73
+ # Ajuste feather si la bbox est trop petite
74
+ w, h = x2 - x1, y2 - y1
75
+ f_eff = min(feather, max(w // 2 - 1, 0), max(h // 2 - 1, 0))
76
+ out = blur_bbox_nomargin(out, x1, y1, x2, y2,
77
+ blur_strength=blur_strength,
78
+ feather=f_eff)
79
+ total += 1
80
+
81
+ out_rgb = cv2.cvtColor(out, cv2.COLOR_BGR2RGB)
82
+
83
+ if total == 0:
84
+ log = "🔍 Aucune plaque d'immatriculation détectée dans cette image"
85
+ elif total == 1:
86
+ log = f"✅ 1 plaque anonymisée avec succès (Confiance: {conf:.0%}, Flou: {blur_strength:.0%})"
87
+ else:
88
+ log = f"✅ {total} plaques anonymisées avec succès (Confiance: {conf:.0%}, Flou: {blur_strength:.0%})"
89
+
90
+ return out_rgb, log
91
+
92
+ # ===== UI =====
93
+ with gr.Blocks(title="Anonymisation Automatique de Plaques d'Immatriculation") as demo:
94
+ gr.Markdown("""
95
+ # 🚗 Anonymisation Automatique de Plaques d'Immatriculation
96
+
97
+ **Détection et floutage intelligent des plaques avec IA**
98
+
99
+ 📋 **Instructions :**
100
+ 1. Téléchargez ou glissez-déposez votre image
101
+ 2. L'anonymisation se fait automatiquement
102
+
103
+ """)
104
+
105
+ with gr.Row():
106
+ with gr.Column():
107
+ gr.Markdown("### 📤 **Image à traiter**")
108
+ inp = gr.Image(type="numpy", label="Sélectionnez votre image", height=400)
109
+
110
+ btn = gr.Button("🔒 Anonymiser l'image", variant="primary", size="lg")
111
+
112
+ with gr.Column():
113
+ gr.Markdown("### 📥 **Résultat**")
114
+ out_img = gr.Image(type="numpy", label="Image anonymisée", height=400)
115
+ out_log = gr.Textbox(
116
+ label="📊 Rapport de traitement",
117
+ interactive=False,
118
+ info="Détails sur le nombre de plaques détectées et les paramètres utilisés"
119
+ )
120
+
121
+ btn.click(anonymize, [inp], [out_img, out_log])
122
+ inp.change(anonymize, [inp], [out_img, out_log])
123
+
124
+ if __name__ == "__main__":
125
+ import os
126
+ demo.launch(server_name="0.0.0.0", server_port=int(os.getenv("PORT", "7860")))
requirements.txt ADDED
Binary file (370 Bytes). View file