YuAnTsai commited on
Commit
65fa78e
·
verified ·
1 Parent(s): b734249

Update emotion.py

Browse files
Files changed (1) hide show
  1. emotion.py +58 -46
emotion.py CHANGED
@@ -8,6 +8,9 @@ from PIL import Image
8
 
9
  import cv2
10
  import mediapipe as mp
 
 
 
11
 
12
  from deepface import DeepFace
13
 
@@ -28,11 +31,22 @@ ALIGN_FACE = True # 保留參數(這版 ROI 已是人臉)
28
 
29
 
30
  # =========================
31
- # MediaPipe Face Detection(白框 + 紅點 keypoints)
32
  # =========================
33
- _mp_face = mp.solutions.face_detection
34
- _FACE_DET = _mp_face.FaceDetection(model_selection=0, min_detection_confidence=0.5)
35
- # model_selection=0 偏短距離偵測(接近 blaze_face_short_range)
 
 
 
 
 
 
 
 
 
 
 
36
 
37
 
38
  # =========================
@@ -196,70 +210,68 @@ def _zoom_center(frame: np.ndarray, zoom: float) -> np.ndarray:
196
  return cropped
197
 
198
 
199
- # =========================
200
- # MediaPipe:偵測臉 + 畫白框/紅點
201
- # =========================
202
- def _mp_detect_draw_bbox_kp_largest(frame_rgb: np.ndarray):
203
  """
204
- 最大臉策略:
205
- - 多人入鏡:挑 bbox 面積最大者
206
- 回傳:
207
- drawn_rgb:有臉就畫白框+紅點;沒臉回原圖
208
- bbox_px: (x, y, w, h) pixel;沒臉則 None
209
  """
210
- if frame_rgb is None:
211
- return frame_rgb, None
212
-
213
  h, w = frame_rgb.shape[:2]
214
- res = _FACE_DET.process(frame_rgb) # MediaPipe 吃 RGB
215
 
216
- if not res.detections:
 
 
 
 
 
 
 
217
  return frame_rgb, None
218
 
 
219
  best_det = None
220
  best_area = -1
221
  best_bbox = None
222
 
223
- # 逐個算 bbox 面積,挑最大
224
- for det in res.detections:
225
- loc = det.location_data
226
- rbb = loc.relative_bounding_box
227
- x = int(rbb.xmin * w)
228
- y = int(rbb.ymin * h)
229
- bw = int(rbb.width * w)
230
- bh = int(rbb.height * h)
231
-
232
- # clamp
233
- x = max(0, min(w - 1, x))
234
- y = max(0, min(h - 1, y))
235
- bw = max(1, min(w - x, bw))
236
- bh = max(1, min(h - y, bh))
237
-
238
- area = bw * bh
239
  if area > best_area:
240
  best_area = area
241
  best_det = det
242
- best_bbox = (x, y, bw, bh)
243
 
244
- if best_det is None or best_bbox is None:
245
- return frame_rgb, None
 
 
246
 
247
- x, y, bw, bh = best_bbox
248
- loc = best_det.location_data
 
 
 
249
 
250
  bgr = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2BGR)
251
 
252
- # 白框
253
- cv2.rectangle(bgr, (x, y), (x + bw, y + bh), (255, 255, 255), 3)
 
 
 
 
 
 
254
 
255
- # 紅點(五官特徵點)
256
- for kp in loc.relative_keypoints:
257
  cx = int(kp.x * w)
258
  cy = int(kp.y * h)
259
  cv2.circle(bgr, (cx, cy), 6, (0, 0, 255), -1)
260
 
261
  drawn = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
262
- return drawn, (x, y, bw, bh)
 
263
 
264
 
265
  def _reset_state_for_camera(st: AppState) -> AppState:
@@ -321,8 +333,8 @@ def on_stream(frame_rgb: np.ndarray, st: AppState):
321
  frame_rgb = _zoom_center(frame_rgb, ZOOM_FACTOR)
322
 
323
  # 每一幀先偵測臉:有臉才畫框/紅點
324
- frame_drawn, bbox_px = _mp_detect_draw_bbox_kp_largest(frame_rgb)
325
-
326
  # 沒有人臉:不畫框/點,並提醒
327
  if bbox_px is None:
328
  return (
 
8
 
9
  import cv2
10
  import mediapipe as mp
11
+ from mediapipe.tasks import python
12
+ from mediapipe.tasks.python import vision
13
+
14
 
15
  from deepface import DeepFace
16
 
 
31
 
32
 
33
  # =========================
34
+ # MediaPipe Tasks Face Detector
35
  # =========================
36
+ BaseOptions = python.BaseOptions
37
+ FaceDetector = vision.FaceDetector
38
+ FaceDetectorOptions = vision.FaceDetectorOptions
39
+ VisionRunningMode = vision.RunningMode
40
+
41
+ _face_detector = FaceDetector.create_from_options(
42
+ FaceDetectorOptions(
43
+ base_options=BaseOptions(
44
+ model_asset_path="blaze_face_short_range.tflite"
45
+ ),
46
+ running_mode=VisionRunningMode.IMAGE,
47
+ )
48
+ )
49
+
50
 
51
 
52
  # =========================
 
210
  return cropped
211
 
212
 
213
+ def mp_tasks_detect_and_draw(frame_rgb: np.ndarray):
 
 
 
214
  """
215
+ 使用 MediaPipe Tasks
216
+ - 有臉:畫白框 + 紅色 keypoints
217
+ - 回傳 bbox (x,y,w,h)
 
 
218
  """
 
 
 
219
  h, w = frame_rgb.shape[:2]
 
220
 
221
+ mp_image = mp.Image(
222
+ image_format=mp.ImageFormat.SRGB,
223
+ data=frame_rgb
224
+ )
225
+
226
+ result = _face_detector.detect(mp_image)
227
+
228
+ if not result.detections:
229
  return frame_rgb, None
230
 
231
+ # 取「最大臉」
232
  best_det = None
233
  best_area = -1
234
  best_bbox = None
235
 
236
+ for det in result.detections:
237
+ bbox = det.bounding_box
238
+ area = bbox.width * bbox.height
 
 
 
 
 
 
 
 
 
 
 
 
 
239
  if area > best_area:
240
  best_area = area
241
  best_det = det
242
+ best_bbox = bbox
243
 
244
+ lx = int(best_bbox.origin_x)
245
+ ly = int(best_bbox.origin_y)
246
+ bw = int(best_bbox.width)
247
+ bh = int(best_bbox.height)
248
 
249
+ # clamp
250
+ lx = max(0, min(w - 1, lx))
251
+ ly = max(0, min(h - 1, ly))
252
+ bw = max(1, min(w - lx, bw))
253
+ bh = max(1, min(h - ly, bh))
254
 
255
  bgr = cv2.cvtColor(frame_rgb, cv2.COLOR_RGB2BGR)
256
 
257
+ # 白色框
258
+ cv2.rectangle(
259
+ bgr,
260
+ (lx, ly),
261
+ (lx + bw, ly + bh),
262
+ (255, 255, 255),
263
+ 3
264
+ )
265
 
266
+ # 紅色五官點
267
+ for kp in best_det.keypoints:
268
  cx = int(kp.x * w)
269
  cy = int(kp.y * h)
270
  cv2.circle(bgr, (cx, cy), 6, (0, 0, 255), -1)
271
 
272
  drawn = cv2.cvtColor(bgr, cv2.COLOR_BGR2RGB)
273
+ return drawn, (lx, ly, bw, bh)
274
+
275
 
276
 
277
  def _reset_state_for_camera(st: AppState) -> AppState:
 
333
  frame_rgb = _zoom_center(frame_rgb, ZOOM_FACTOR)
334
 
335
  # 每一幀先偵測臉:有臉才畫框/紅點
336
+ frame_drawn, bbox_px = mp_tasks_detect_and_draw(frame_rgb)
337
+
338
  # 沒有人臉:不畫框/點,並提醒
339
  if bbox_px is None:
340
  return (