Update app.py
Browse files
app.py
CHANGED
@@ -4,8 +4,6 @@ import gradio as gr
|
|
4 |
from pathlib import Path
|
5 |
from collections import Counter, defaultdict
|
6 |
from huggingface_hub import hf_hub_download
|
7 |
-
import matplotlib.pyplot as plt
|
8 |
-
import io
|
9 |
|
10 |
from facial_fer_model import FacialExpressionRecog
|
11 |
from yunet import YuNet
|
@@ -40,7 +38,7 @@ def to_dutch(label: str) -> str:
|
|
40 |
key = label.strip().lower()
|
41 |
return EN_TO_NL.get(key, label)
|
42 |
|
43 |
-
#
|
44 |
emotion_stats = defaultdict(int)
|
45 |
|
46 |
def visualize(image, det_res, fer_res):
|
@@ -66,51 +64,100 @@ def summarize_emotions(fer_res):
|
|
66 |
details = ", ".join([f"{name} ({n})" for name, n in counts])
|
67 |
return f"# **{top}**\n\n_Gedetecteerde emoties: {details}_"
|
68 |
|
69 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
70 |
for name in names_nl:
|
71 |
emotion_stats[name] += 1
|
72 |
-
|
73 |
-
fig, ax = plt.subplots()
|
74 |
-
labels = list(emotion_stats.keys())
|
75 |
-
values = [emotion_stats[k] for k in labels]
|
76 |
-
ax.bar(labels, values)
|
77 |
-
ax.set_ylabel("Aantal keer gedetecteerd")
|
78 |
-
ax.set_title("Live emotie-statistieken")
|
79 |
-
plt.xticks(rotation=45)
|
80 |
-
buf = io.BytesIO()
|
81 |
-
plt.tight_layout()
|
82 |
-
fig.savefig(buf, format="png")
|
83 |
-
plt.close(fig)
|
84 |
-
buf.seek(0)
|
85 |
-
return buf
|
86 |
|
87 |
def detect_expression(input_image):
|
88 |
image = cv.cvtColor(input_image, cv.COLOR_RGB2BGR)
|
89 |
h, w, _ = image.shape
|
90 |
detect_model.setInputSize([w, h])
|
91 |
dets = detect_model.infer(image)
|
|
|
92 |
if dets is None:
|
93 |
emotion_md = summarize_emotions([])
|
94 |
-
|
|
|
95 |
return cv.cvtColor(image, cv.COLOR_BGR2RGB), emotion_md, stats_plot
|
|
|
96 |
fer_res = [fer_model.infer(image, face_points[:-1])[0] for face_points in dets]
|
97 |
output = visualize(image, dets, fer_res)
|
98 |
emotion_md = summarize_emotions(fer_res)
|
99 |
names_nl = [to_dutch(FacialExpressionRecog.getDesc(x)) for x in fer_res]
|
100 |
-
stats_plot =
|
|
|
101 |
return cv.cvtColor(output, cv.COLOR_BGR2RGB), emotion_md, stats_plot
|
102 |
|
103 |
# Voorbeelden automatisch laden
|
104 |
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
|
105 |
EXAMPLES_DIR = Path("examples")
|
106 |
-
if EXAMPLES_DIR.exists():
|
107 |
-
example_paths = [str(p) for p in sorted(EXAMPLES_DIR.iterdir()) if p.suffix.lower() in IMAGE_EXTS]
|
108 |
else:
|
109 |
example_paths = []
|
110 |
example_list = [[p] for p in example_paths]
|
111 |
CACHE_EXAMPLES = bool(example_list)
|
112 |
|
113 |
-
# CSS
|
114 |
custom_css = """
|
115 |
#emotie-uitslag { color: #16a34a; }
|
116 |
#emotie-uitslag h1, #emotie-uitslag h2, #emotie-uitslag h3 { margin: 0.25rem 0; }
|
@@ -131,12 +178,19 @@ with gr.Blocks(css=custom_css) as demo:
|
|
131 |
emotion_md = gr.Markdown("## **Nog geen resultaat**", elem_id="emotie-uitslag")
|
132 |
stats_image = gr.Image(label="Statistieken", type="numpy")
|
133 |
|
134 |
-
|
135 |
-
|
136 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
137 |
submit_btn.click(fn=detect_expression, inputs=input_image, outputs=[output_image, emotion_md, stats_image])
|
138 |
-
clear_btn.click(fn=
|
139 |
|
|
|
140 |
gr.Examples(
|
141 |
examples=example_list,
|
142 |
inputs=input_image,
|
|
|
4 |
from pathlib import Path
|
5 |
from collections import Counter, defaultdict
|
6 |
from huggingface_hub import hf_hub_download
|
|
|
|
|
7 |
|
8 |
from facial_fer_model import FacialExpressionRecog
|
9 |
from yunet import YuNet
|
|
|
38 |
key = label.strip().lower()
|
39 |
return EN_TO_NL.get(key, label)
|
40 |
|
41 |
+
# In-memory statistieken
|
42 |
emotion_stats = defaultdict(int)
|
43 |
|
44 |
def visualize(image, det_res, fer_res):
|
|
|
64 |
details = ", ".join([f"{name} ({n})" for name, n in counts])
|
65 |
return f"# **{top}**\n\n_Gedetecteerde emoties: {details}_"
|
66 |
|
67 |
+
# --- Staafdiagram tekenen met OpenCV (geen matplotlib nodig) ---
|
68 |
+
def draw_bar_chart_cv(stats: dict, width=640, height=320):
|
69 |
+
"""
|
70 |
+
Maakt een simpele staafdiagram als numpy image (RGB).
|
71 |
+
"""
|
72 |
+
# Wit canvas (BGR eerst, later naar RGB)
|
73 |
+
img = np.full((height, width, 3), 255, dtype=np.uint8)
|
74 |
+
|
75 |
+
# Titel
|
76 |
+
title = "Live emotie-statistieken"
|
77 |
+
cv.putText(img, title, (12, 28), cv.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 0), 2, cv.LINE_AA)
|
78 |
+
|
79 |
+
# Geen data?
|
80 |
+
if not stats:
|
81 |
+
msg = "Nog geen statistieken"
|
82 |
+
cv.putText(img, msg, (12, height//2), cv.FONT_HERSHEY_SIMPLEX, 0.9, (128, 128, 128), 2, cv.LINE_AA)
|
83 |
+
return cv.cvtColor(img, cv.COLOR_BGR2RGB)
|
84 |
+
|
85 |
+
# Marges & plotgebied
|
86 |
+
left, right, top, bottom = 60, 20, 50, 40
|
87 |
+
plot_w = width - left - right
|
88 |
+
plot_h = height - top - bottom
|
89 |
+
origin = (left, height - bottom)
|
90 |
+
|
91 |
+
# Assen
|
92 |
+
cv.line(img, origin, (left + plot_w, height - bottom), (0, 0, 0), 2) # x-as
|
93 |
+
cv.line(img, origin, (left, height - bottom - plot_h), (0, 0, 0), 2) # y-as
|
94 |
+
|
95 |
+
labels = list(stats.keys())
|
96 |
+
values = [stats[k] for k in labels]
|
97 |
+
max_val = max(values) if max(values) > 0 else 1
|
98 |
+
|
99 |
+
n = len(labels)
|
100 |
+
gap = 12
|
101 |
+
bar_w = max(10, int((plot_w - gap * (n + 1)) / max(1, n)))
|
102 |
+
|
103 |
+
# Bars (groen)
|
104 |
+
for i, (lab, val) in enumerate(zip(labels, values)):
|
105 |
+
x1 = left + gap + i * (bar_w + gap)
|
106 |
+
x2 = x1 + bar_w
|
107 |
+
# Hoogte proportioneel
|
108 |
+
h_px = int((val / max_val) * (plot_h - 10))
|
109 |
+
y1 = height - bottom - h_px
|
110 |
+
y2 = height - bottom - 1
|
111 |
+
cv.rectangle(img, (x1, y1), (x2, y2), (0, 170, 60), -1) # groene balk
|
112 |
+
|
113 |
+
# Waardelabel boven balk
|
114 |
+
cv.putText(img, str(val), (x1 + 2, y1 - 6), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 90, 30), 1, cv.LINE_AA)
|
115 |
+
|
116 |
+
# X-label onder balk (afgekort indien lang)
|
117 |
+
show_lab = lab if len(lab) <= 10 else lab[:9] + "…"
|
118 |
+
(tw, th), _ = cv.getTextSize(show_lab, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)
|
119 |
+
tx = x1 + (bar_w - tw) // 2
|
120 |
+
ty = height - bottom + th + 12
|
121 |
+
cv.putText(img, show_lab, (tx, ty), cv.FONT_HERSHEY_SIMPLEX, 0.5, (40, 40, 40), 1, cv.LINE_AA)
|
122 |
+
|
123 |
+
return cv.cvtColor(img, cv.COLOR_BGR2RGB)
|
124 |
+
|
125 |
+
def update_stats_and_chart(names_nl):
|
126 |
for name in names_nl:
|
127 |
emotion_stats[name] += 1
|
128 |
+
return draw_bar_chart_cv(emotion_stats)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
129 |
|
130 |
def detect_expression(input_image):
|
131 |
image = cv.cvtColor(input_image, cv.COLOR_RGB2BGR)
|
132 |
h, w, _ = image.shape
|
133 |
detect_model.setInputSize([w, h])
|
134 |
dets = detect_model.infer(image)
|
135 |
+
|
136 |
if dets is None:
|
137 |
emotion_md = summarize_emotions([])
|
138 |
+
# Geen incremente — alleen huidige chart tonen
|
139 |
+
stats_plot = draw_bar_chart_cv(emotion_stats)
|
140 |
return cv.cvtColor(image, cv.COLOR_BGR2RGB), emotion_md, stats_plot
|
141 |
+
|
142 |
fer_res = [fer_model.infer(image, face_points[:-1])[0] for face_points in dets]
|
143 |
output = visualize(image, dets, fer_res)
|
144 |
emotion_md = summarize_emotions(fer_res)
|
145 |
names_nl = [to_dutch(FacialExpressionRecog.getDesc(x)) for x in fer_res]
|
146 |
+
stats_plot = update_stats_and_chart(names_nl)
|
147 |
+
|
148 |
return cv.cvtColor(output, cv.COLOR_BGR2RGB), emotion_md, stats_plot
|
149 |
|
150 |
# Voorbeelden automatisch laden
|
151 |
IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
|
152 |
EXAMPLES_DIR = Path("examples")
|
153 |
+
if EXAMPLES_DIR.exists() and EXAMPLES_DIR.is_dir():
|
154 |
+
example_paths = [str(p) for p in sorted(EXAMPLES_DIR.iterdir()) if Path(p).suffix.lower() in IMAGE_EXTS]
|
155 |
else:
|
156 |
example_paths = []
|
157 |
example_list = [[p] for p in example_paths]
|
158 |
CACHE_EXAMPLES = bool(example_list)
|
159 |
|
160 |
+
# CSS (groene emotietekst)
|
161 |
custom_css = """
|
162 |
#emotie-uitslag { color: #16a34a; }
|
163 |
#emotie-uitslag h1, #emotie-uitslag h2, #emotie-uitslag h3 { margin: 0.25rem 0; }
|
|
|
178 |
emotion_md = gr.Markdown("## **Nog geen resultaat**", elem_id="emotie-uitslag")
|
179 |
stats_image = gr.Image(label="Statistieken", type="numpy")
|
180 |
|
181 |
+
# Clear-helpers
|
182 |
+
def clear_all_on_new():
|
183 |
+
return None, "## **Nog geen resultaat**", draw_bar_chart_cv(emotion_stats)
|
184 |
+
|
185 |
+
def clear_all_button():
|
186 |
+
# reset alleen UI; statistieken laten we staan
|
187 |
+
return None, None, "## **Nog geen resultaat**", draw_bar_chart_cv(emotion_stats)
|
188 |
+
|
189 |
+
input_image.change(fn=clear_all_on_new, outputs=[output_image, emotion_md, stats_image])
|
190 |
submit_btn.click(fn=detect_expression, inputs=input_image, outputs=[output_image, emotion_md, stats_image])
|
191 |
+
clear_btn.click(fn=clear_all_button, outputs=[input_image, output_image, emotion_md, stats_image])
|
192 |
|
193 |
+
gr.Markdown("Klik op een voorbeeld om te testen.")
|
194 |
gr.Examples(
|
195 |
examples=example_list,
|
196 |
inputs=input_image,
|