Marcel0123 commited on
Commit
f8f9179
·
verified ·
1 Parent(s): 5f45471

Update app.py

Browse files
Files changed (1) hide show
  1. app.py +52 -61
app.py CHANGED
@@ -2,13 +2,15 @@ import cv2 as cv
2
  import numpy as np
3
  import gradio as gr
4
  from pathlib import Path
5
- from collections import Counter
6
  from huggingface_hub import hf_hub_download
 
 
7
 
8
  from facial_fer_model import FacialExpressionRecog
9
  from yunet import YuNet
10
 
11
- # Download ONNX-modellen van Hugging Face
12
  FD_MODEL_PATH = hf_hub_download(repo_id="opencv/face_detection_yunet", filename="face_detection_yunet_2023mar.onnx")
13
  FER_MODEL_PATH = hf_hub_download(repo_id="opencv/facial_expression_recognition", filename="facial_expression_recognition_mobilefacenet_2022july.onnx")
14
 
@@ -18,7 +20,7 @@ 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 van emotielabels ===
22
  EN_TO_NL = {
23
  "neutral": "Neutraal",
24
  "happy": "Blij",
@@ -36,120 +38,109 @@ def to_dutch(label: str) -> str:
36
  if not label:
37
  return "Onbekend"
38
  key = label.strip().lower()
39
- return EN_TO_NL.get(key, label) # fallback naar origineel indien onbekend
 
 
 
40
 
41
  def visualize(image, det_res, fer_res):
42
  output = image.copy()
43
  landmark_color = [(255, 0, 0), (0, 0, 255), (0, 255, 0), (255, 0, 255), (0, 255, 255)]
44
-
45
  for det, fer_type in zip(det_res, fer_res):
46
  bbox = det[0:4].astype(np.int32)
47
- fer_type_str_en = FacialExpressionRecog.getDesc(fer_type)
48
- fer_type_str_nl = to_dutch(fer_type_str_en)
49
-
50
  cv.rectangle(output, (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3]), (0, 255, 0), 2)
51
  cv.putText(output, fer_type_str_nl, (bbox[0], max(0, bbox[1] - 10)),
52
  cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2, cv.LINE_AA)
53
-
54
  landmarks = det[4:14].astype(np.int32).reshape((5, 2))
55
  for idx, landmark in enumerate(landmarks):
56
  cv.circle(output, landmark, 2, landmark_color[idx], 2)
57
-
58
  return output
59
 
60
  def summarize_emotions(fer_res):
61
- """
62
- Maakt een Markdown-tekst met een grote, vetgedrukte samenvatting (NL).
63
- Bij meerdere gezichten wordt de meest voorkomende emotie uitgelicht.
64
- """
65
  if not fer_res:
66
  return "## **Geen gezicht gedetecteerd**"
67
-
68
- names_en = [FacialExpressionRecog.getDesc(x) for x in fer_res]
69
- names_nl = [to_dutch(n) for n in names_en]
70
  counts = Counter(names_nl).most_common()
71
- top, top_n = counts[0]
72
  details = ", ".join([f"{name} ({n})" for name, n in counts])
73
-
74
- # Grote headline + toelichting (kleur regelen we via CSS)
75
  return f"# **{top}**\n\n_Gedetecteerde emoties: {details}_"
76
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
77
  def detect_expression(input_image):
78
  image = cv.cvtColor(input_image, cv.COLOR_RGB2BGR)
79
  h, w, _ = image.shape
80
  detect_model.setInputSize([w, h])
81
-
82
  dets = detect_model.infer(image)
83
  if dets is None:
84
  emotion_md = summarize_emotions([])
85
- return cv.cvtColor(image, cv.COLOR_BGR2RGB), emotion_md
86
-
87
- fer_res = []
88
- for face_points in dets:
89
- result = fer_model.infer(image, face_points[:-1])
90
- fer_res.append(result[0])
91
-
92
  output = visualize(image, dets, fer_res)
93
  emotion_md = summarize_emotions(fer_res)
94
- return cv.cvtColor(output, cv.COLOR_BGR2RGB), emotion_md
 
 
95
 
96
- # === Automatisch voorbeelden inladen uit de map "examples/" ===
97
  IMAGE_EXTS = {".jpg", ".jpeg", ".png", ".bmp", ".webp"}
98
  EXAMPLES_DIR = Path("examples")
99
-
100
- if EXAMPLES_DIR.exists() and EXAMPLES_DIR.is_dir():
101
- example_paths = [
102
- str(p) for p in sorted(EXAMPLES_DIR.iterdir())
103
- if p.is_file() and p.suffix.lower() in IMAGE_EXTS
104
- ]
105
  else:
106
  example_paths = []
107
-
108
  example_list = [[p] for p in example_paths]
109
  CACHE_EXAMPLES = bool(example_list)
110
- # =============================================================
111
 
112
- # Gradio Interface (NL) + groene kleur voor de emotietekst
113
  custom_css = """
114
- .example * { font-style: italic; font-size: 18px !important; color: #0ea5e9 !important; }
115
- #emotie-uitslag { color: #16a34a; } /* GROEN */
116
  #emotie-uitslag h1, #emotie-uitslag h2, #emotie-uitslag h3 { margin: 0.25rem 0; }
117
  """
118
 
119
- with gr.Blocks(css=custom_css, theme=gr.themes.Default()) as demo:
120
  gr.Markdown("## Herkenning van gezichtsuitdrukkingen (FER) met OpenCV DNN")
121
  gr.Markdown("Detecteert gezichten en herkent gezichtsuitdrukkingen met YuNet + MobileFaceNet (ONNX).")
122
 
123
  with gr.Row():
124
- with gr.Column(scale=1):
125
  input_image = gr.Image(type="numpy", label="Afbeelding uploaden")
126
  with gr.Row():
127
  submit_btn = gr.Button("Verstuur", variant="primary")
128
  clear_btn = gr.Button("Wissen")
129
- with gr.Column(scale=1):
130
- # Eerst de afbeelding, daaronder de (groene) emotie-uitslag
131
  output_image = gr.Image(type="numpy", label="Resultaat gezichtsuitdrukking")
132
- emotion_md = gr.Markdown(
133
- value="## **Nog geen resultaat**",
134
- elem_id="emotie-uitslag"
135
- )
136
-
137
- # Output(s) leegmaken bij nieuwe upload
138
- def _clear_output_on_new_image():
139
- return None, "## **Nog geen resultaat**"
140
- input_image.change(fn=_clear_output_on_new_image, outputs=[output_image, emotion_md])
141
-
142
- # Knop-actie(s)
143
- submit_btn.click(fn=detect_expression, inputs=input_image, outputs=[output_image, emotion_md])
144
- clear_btn.click(fn=lambda: (None, None, "## **Nog geen resultaat**"),
145
- outputs=[input_image, output_image, emotion_md])
146
 
147
- gr.Markdown("Klik op een voorbeeld om te testen.", elem_classes=["example"])
 
 
 
 
148
 
149
  gr.Examples(
150
  examples=example_list,
151
  inputs=input_image,
152
- outputs=[output_image, emotion_md],
153
  fn=detect_expression,
154
  examples_per_page=20,
155
  cache_examples=CACHE_EXAMPLES
 
2
  import numpy as np
3
  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
12
 
13
+ # Download ONNX-modellen
14
  FD_MODEL_PATH = hf_hub_download(repo_id="opencv/face_detection_yunet", filename="face_detection_yunet_2023mar.onnx")
15
  FER_MODEL_PATH = hf_hub_download(repo_id="opencv/facial_expression_recognition", filename="facial_expression_recognition_mobilefacenet_2022july.onnx")
16
 
 
20
  fer_model = FacialExpressionRecog(modelPath=FER_MODEL_PATH, backendId=backend_id, targetId=target_id)
21
  detect_model = YuNet(modelPath=FD_MODEL_PATH)
22
 
23
+ # EN -> NL mapping
24
  EN_TO_NL = {
25
  "neutral": "Neutraal",
26
  "happy": "Blij",
 
38
  if not label:
39
  return "Onbekend"
40
  key = label.strip().lower()
41
+ return EN_TO_NL.get(key, label)
42
+
43
+ # Opslag voor statistieken
44
+ emotion_stats = defaultdict(int)
45
 
46
  def visualize(image, det_res, fer_res):
47
  output = image.copy()
48
  landmark_color = [(255, 0, 0), (0, 0, 255), (0, 255, 0), (255, 0, 255), (0, 255, 255)]
 
49
  for det, fer_type in zip(det_res, fer_res):
50
  bbox = det[0:4].astype(np.int32)
51
+ fer_type_str_nl = to_dutch(FacialExpressionRecog.getDesc(fer_type))
 
 
52
  cv.rectangle(output, (bbox[0], bbox[1]), (bbox[0]+bbox[2], bbox[1]+bbox[3]), (0, 255, 0), 2)
53
  cv.putText(output, fer_type_str_nl, (bbox[0], max(0, bbox[1] - 10)),
54
  cv.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2, cv.LINE_AA)
 
55
  landmarks = det[4:14].astype(np.int32).reshape((5, 2))
56
  for idx, landmark in enumerate(landmarks):
57
  cv.circle(output, landmark, 2, landmark_color[idx], 2)
 
58
  return output
59
 
60
  def summarize_emotions(fer_res):
 
 
 
 
61
  if not fer_res:
62
  return "## **Geen gezicht gedetecteerd**"
63
+ names_nl = [to_dutch(FacialExpressionRecog.getDesc(x)) for x in fer_res]
 
 
64
  counts = Counter(names_nl).most_common()
65
+ top = counts[0][0]
66
  details = ", ".join([f"{name} ({n})" for name, n in counts])
 
 
67
  return f"# **{top}**\n\n_Gedetecteerde emoties: {details}_"
68
 
69
+ def update_stats_and_plot(names_nl):
70
+ for name in names_nl:
71
+ emotion_stats[name] += 1
72
+ # Maak plot
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
+ stats_plot = update_stats_and_plot([])
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 = update_stats_and_plot(names_nl)
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 voor groene tekst
114
  custom_css = """
115
+ #emotie-uitslag { color: #16a34a; }
 
116
  #emotie-uitslag h1, #emotie-uitslag h2, #emotie-uitslag h3 { margin: 0.25rem 0; }
117
  """
118
 
119
+ with gr.Blocks(css=custom_css) as demo:
120
  gr.Markdown("## Herkenning van gezichtsuitdrukkingen (FER) met OpenCV DNN")
121
  gr.Markdown("Detecteert gezichten en herkent gezichtsuitdrukkingen met YuNet + MobileFaceNet (ONNX).")
122
 
123
  with gr.Row():
124
+ with gr.Column():
125
  input_image = gr.Image(type="numpy", label="Afbeelding uploaden")
126
  with gr.Row():
127
  submit_btn = gr.Button("Verstuur", variant="primary")
128
  clear_btn = gr.Button("Wissen")
129
+ with gr.Column():
 
130
  output_image = gr.Image(type="numpy", label="Resultaat gezichtsuitdrukking")
131
+ emotion_md = gr.Markdown("## **Nog geen resultaat**", elem_id="emotie-uitslag")
132
+ stats_image = gr.Image(label="Statistieken", type="numpy")
 
 
 
 
 
 
 
 
 
 
 
 
133
 
134
+ def clear_all():
135
+ return None, "## **Nog geen resultaat**", None
136
+ input_image.change(fn=clear_all, outputs=[output_image, emotion_md, stats_image])
137
+ submit_btn.click(fn=detect_expression, inputs=input_image, outputs=[output_image, emotion_md, stats_image])
138
+ clear_btn.click(fn=clear_all, outputs=[input_image, output_image, emotion_md, stats_image])
139
 
140
  gr.Examples(
141
  examples=example_list,
142
  inputs=input_image,
143
+ outputs=[output_image, emotion_md, stats_image],
144
  fn=detect_expression,
145
  examples_per_page=20,
146
  cache_examples=CACHE_EXAMPLES