Marcel0123 commited on
Commit
4f8044a
·
verified ·
1 Parent(s): a432ed6

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +18 -158
app.py CHANGED
@@ -18,17 +18,32 @@ target_id = cv.dnn.DNN_TARGET_CPU
18
  fer_model = FacialExpressionRecog(modelPath=FER_MODEL_PATH, backendId=backend_id, targetId=target_id)
19
  detect_model = YuNet(modelPath=FD_MODEL_PATH)
20
 
21
- # EN -> NL mapping (lowercase)
22
  EN_TO_NL = {
23
  "neutral": "neutraal",
 
24
  "happy": "blij",
 
 
25
  "sad": "verdrietig",
 
 
26
  "surprise": "verrast",
 
 
 
 
27
  "angry": "boos",
28
  "anger": "boos",
 
29
  "disgust": "walging",
30
- "fear": "bang",
 
 
 
 
31
  "contempt": "minachting",
 
32
  "unknown": "onbekend",
33
  }
34
 
@@ -51,159 +66,4 @@ def visualize(image, det_res, fer_res):
51
  fer_type_str_nl = to_dutch_lower(FacialExpressionRecog.getDesc(fer_type))
52
 
53
  cv.rectangle(output, (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3]), (0, 255, 0), 2)
54
- cv.putText(output, fer_type_str_nl, (bbox[0], max(0, bbox[1] - 10)),
55
- cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2, cv.LINE_AA)
56
-
57
- landmarks = det[4:14].astype(np.int32).reshape((5, 2))
58
- for idx, landmark in enumerate(landmarks):
59
- cv.circle(output, landmark, 2, landmark_color[idx], 2)
60
- return output
61
-
62
- def summarize_emotions(fer_res):
63
- """Maakt de grote groene NL-lowercase samenvatting."""
64
- if not fer_res:
65
- return "## **geen gezicht gedetecteerd**"
66
- names_nl = [to_dutch_lower(FacialExpressionRecog.getDesc(x)) for x in fer_res]
67
- counts = Counter(names_nl).most_common()
68
- top = counts[0][0]
69
- details = ", ".join([f"{name} ({n})" for name, n in counts])
70
- return f"# **{top}**\n\n_Gedetecteerde emoties: {details}_"
71
-
72
- # --- Staafdiagram tekenen met OpenCV (geen matplotlib nodig) ---
73
- def draw_bar_chart_cv(stats: dict, width=640, height=320):
74
- img = np.full((height, width, 3), 255, dtype=np.uint8)
75
- cv.putText(img, "Live emotie-statistieken", (12, 28), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 2, cv.LINE_AA)
76
- if not stats:
77
- cv.putText(img, "Nog geen statistieken", (12, height//2), cv.FONT_HERSHEY_SIMPLEX, 0.9, (128, 128, 128), 2, cv.LINE_AA)
78
- return cv.cvtColor(img, cv.COLOR_BGR2RGB)
79
-
80
- left, right, top, bottom = 60, 20, 50, 40
81
- plot_w = width - left - right
82
- plot_h = height - top - bottom
83
- origin = (left, height - bottom)
84
-
85
- cv.line(img, origin, (left + plot_w, height - bottom), (0, 0, 0), 2) # x-as
86
- cv.line(img, origin, (left, height - bottom - plot_h), (0, 0, 0), 2) # y-as
87
-
88
- labels = list(stats.keys())
89
- values = [stats[k] for k in labels]
90
- max_val = max(values) if max(values) > 0 else 1
91
-
92
- n = len(labels)
93
- gap = 12
94
- bar_w = max(10, int((plot_w - gap * (n + 1)) / max(1, n)))
95
-
96
- for i, (lab, val) in enumerate(zip(labels, values)):
97
- x1 = left + gap + i * (bar_w + gap)
98
- x2 = x1 + bar_w
99
- h_px = int((val / max_val) * (plot_h - 10))
100
- y1 = height - bottom - h_px
101
- y2 = height - bottom - 1
102
- cv.rectangle(img, (x1, y1), (x2, y2), (0, 170, 60), -1) # groene balk
103
- cv.putText(img, str(val), (x1 + 2, y1 - 6), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 90, 30), 1, cv.LINE_AA)
104
-
105
- show_lab = lab if len(lab) <= 12 else lab[:11] + "…"
106
- (tw, th), _ = cv.getTextSize(show_lab, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
107
- tx = x1 + (bar_w - tw) // 2
108
- ty = height - bottom + th + 12
109
- cv.putText(img, show_lab, (tx, ty), cv.FONT_HERSHEY_SIMPLEX, 0.5, (40, 40, 40), 1, cv.LINE_AA)
110
-
111
- return cv.cvtColor(img, cv.COLOR_BGR2RGB)
112
-
113
- def process_image(input_image):
114
- """Helper: run detectie en retourneer (output_img, fer_res as list[int])."""
115
- image = cv.cvtColor(input_image, cv.COLOR_RGB2BGR)
116
- h, w, _ = image.shape
117
- detect_model.setInputSize([w, h])
118
- dets = detect_model.infer(image)
119
- if dets is None:
120
- return cv.cvtColor(image, cv.COLOR_BGR2RGB), []
121
- fer_res = [fer_model.infer(image, face_points[:-1])[0] for face_points in dets]
122
- output = visualize(image, dets, fer_res)
123
- return cv.cvtColor(output, cv.COLOR_BGR2RGB), fer_res
124
-
125
- def detect_expression(input_image):
126
- """Versie die WÉL statistieken bijwerkt (gebruik voor 'Verstuur')."""
127
- output_img, fer_res = process_image(input_image)
128
- emotion_md = summarize_emotions(fer_res)
129
- # update stats in NL-lowercase
130
- names_nl = [to_dutch_lower(FacialExpressionRecog.getDesc(x)) for x in fer_res]
131
- for name in names_nl:
132
- emotion_stats[name] += 1
133
- stats_plot = draw_bar_chart_cv(emotion_stats)
134
- return output_img, emotion_md, stats_plot
135
-
136
- def detect_expression_no_stats(input_image):
137
- """Versie die GEEN statistieken bijwerkt (gebruik voor gr.Examples & caching)."""
138
- output_img, fer_res = process_image(input_image)
139
- emotion_md = summarize_emotions(fer_res)
140
- stats_plot = draw_bar_chart_cv(emotion_stats) # toon huidige stand
141
- return output_img, emotion_md, stats_plot
142
-
143
- # Voorbeelden automatisch laden
144
- IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
145
- EXAMPLES_DIR = Path("examples")
146
- if EXAMPLES_DIR.exists() and EXAMPLES_DIR.is_dir():
147
- example_paths = [str(p) for p in sorted(EXAMPLES_DIR.iterdir()) if Path(p).suffix.lower() in IMAGE_EXTS]
148
- else:
149
- example_paths = []
150
- example_list = [[p] for p in example_paths]
151
- CACHE_EXAMPLES = bool(example_list)
152
-
153
- # CSS (groene emotietekst)
154
- custom_css = """
155
- #emotie-uitslag { color: #16a34a; }
156
- #emotie-uitslag h1, #emotie-uitslag h2, #emotie-uitslag h3 { margin: 0.25rem 0; }
157
- """
158
-
159
- with gr.Blocks(css=custom_css) as demo:
160
- gr.Markdown("## Herkenning van gezichtsuitdrukkingen (FER) met OpenCV DNN")
161
- gr.Markdown("Detecteert gezichten en herkent gezichtsuitdrukkingen met YuNet + MobileFaceNet (ONNX).")
162
-
163
- # Rij 1: Links upload/knoppen, Rechts output + emotie
164
- with gr.Row():
165
- with gr.Column():
166
- input_image = gr.Image(type="numpy", label="Afbeelding uploaden")
167
- with gr.Row():
168
- submit_btn = gr.Button("Verstuur", variant="primary")
169
- clear_btn = gr.Button("Wissen")
170
- with gr.Column():
171
- output_image = gr.Image(type="numpy", label="Resultaat gezichtsuitdrukking")
172
- emotion_md = gr.Markdown("## **Nog geen resultaat**", elem_id="emotie-uitslag")
173
-
174
- # Rij 2: Links mugshots (Examples), Rechts statistieken
175
- with gr.Row():
176
- with gr.Column():
177
- gr.Markdown("**Voorbeelden (klik om te testen):**")
178
- examples_component = gr.Examples(
179
- examples=example_list,
180
- inputs=input_image,
181
- outputs=[output_image, emotion_md], # stats volgt hieronder in dezelfde row
182
- fn=detect_expression_no_stats,
183
- examples_per_page=20,
184
- cache_examples=CACHE_EXAMPLES
185
- )
186
- with gr.Column():
187
- stats_image = gr.Image(
188
- label="Statistieken",
189
- type="numpy",
190
- value=draw_bar_chart_cv(emotion_stats) # start met lege/actuele chart
191
- )
192
-
193
- # Clear-helpers
194
- def clear_all_on_new():
195
- return None, "## **Nog geen resultaat**"
196
-
197
- def clear_all_button():
198
- # reset inputs/outputs; statistieken blijven behouden
199
- return None, None, "## **Nog geen resultaat**", draw_bar_chart_cv(emotion_stats)
200
-
201
- # Nieuwe upload wist output + emotietekst (grafiek blijft staan)
202
- input_image.change(fn=clear_all_on_new, outputs=[output_image, emotion_md])
203
- # Verwerken
204
- submit_btn.click(fn=detect_expression, inputs=input_image, outputs=[output_image, emotion_md, stats_image])
205
- # Wissen-knop: ook grafiek opnieuw tekenen (maar stats niet resetten)
206
- clear_btn.click(fn=clear_all_button, outputs=[input_image, output_image, emotion_md, stats_image])
207
-
208
- if __name__ == "__main__":
209
- demo.launch()
 
18
  fer_model = FacialExpressionRecog(modelPath=FER_MODEL_PATH, backendId=backend_id, targetId=target_id)
19
  detect_model = YuNet(modelPath=FD_MODEL_PATH)
20
 
21
+ # EN -> NL mapping (lowercase) incl. varianten/typo's
22
  EN_TO_NL = {
23
  "neutral": "neutraal",
24
+
25
  "happy": "blij",
26
+ "happiness": "blij",
27
+
28
  "sad": "verdrietig",
29
+ "sadness": "verdrietig",
30
+
31
  "surprise": "verrast",
32
+ "surprised": "verrast",
33
+ "supprised": "verrast", # veelvoorkomende typo
34
+ "surprized": "verrast",
35
+
36
  "angry": "boos",
37
  "anger": "boos",
38
+
39
  "disgust": "walging",
40
+
41
+ "fear": "angstig",
42
+ "fearful": "angstig",
43
+ "fearfull": "angstig", # veelvoorkomende typo
44
+
45
  "contempt": "minachting",
46
+
47
  "unknown": "onbekend",
48
  }
49
 
 
66
  fer_type_str_nl = to_dutch_lower(FacialExpressionRecog.getDesc(fer_type))
67
 
68
  cv.rectangle(output, (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3]), (0, 255, 0), 2)
69
+ cv.putText(output, fer_type_str_nl, (_