Update emotion.py
Browse files- emotion.py +30 -2
emotion.py
CHANGED
|
@@ -18,7 +18,7 @@ from deepface import DeepFace
|
|
| 18 |
# =========================
|
| 19 |
# 參數(可微調)
|
| 20 |
# =========================
|
| 21 |
-
ANALYZE_EVERY_SEC =
|
| 22 |
EMA_ALPHA = 0.45
|
| 23 |
CONF_TH = 40.0 # DeepFace emotion confidence 門檻
|
| 24 |
SWITCH_CONFIRM_SEC = 2.5 # 連續穩定多久才算完成
|
|
@@ -328,18 +328,46 @@ def _analyze_worker():
|
|
| 328 |
_ANALYZE_THREAD = None
|
| 329 |
|
| 330 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 331 |
def _enqueue_analyze(face_roi: np.ndarray):
|
| 332 |
"""把最新 ROI 丟給背景 thread,若 thread 沒在跑就啟動。"""
|
| 333 |
global _PENDING_FACE, _ANALYZE_THREAD
|
| 334 |
|
|
|
|
|
|
|
|
|
|
| 335 |
with _ANALYZE_LOCK:
|
| 336 |
-
_PENDING_FACE =
|
| 337 |
|
| 338 |
if _ANALYZE_THREAD is None:
|
| 339 |
_ANALYZE_THREAD = threading.Thread(target=_analyze_worker, daemon=True)
|
| 340 |
_ANALYZE_THREAD.start()
|
| 341 |
|
| 342 |
|
|
|
|
| 343 |
# =========================
|
| 344 |
# state helper
|
| 345 |
# =========================
|
|
|
|
| 18 |
# =========================
|
| 19 |
# 參數(可微調)
|
| 20 |
# =========================
|
| 21 |
+
ANALYZE_EVERY_SEC = 2.0 # ⭐ 建議 1.5~2.0:HF CPU 比較順
|
| 22 |
EMA_ALPHA = 0.45
|
| 23 |
CONF_TH = 40.0 # DeepFace emotion confidence 門檻
|
| 24 |
SWITCH_CONFIRM_SEC = 2.5 # 連續穩定多久才算完成
|
|
|
|
| 328 |
_ANALYZE_THREAD = None
|
| 329 |
|
| 330 |
|
| 331 |
+
def _resize_letterbox_rgb(img: np.ndarray, size: int = 224) -> np.ndarray:
|
| 332 |
+
"""
|
| 333 |
+
把 ROI 變成 size×size,保持比例,用黑邊補滿(letterbox)。
|
| 334 |
+
好處:不會把臉拉伸變形,對情緒分類通常更穩。
|
| 335 |
+
"""
|
| 336 |
+
img = _to_rgb_uint8(img)
|
| 337 |
+
h, w = img.shape[:2]
|
| 338 |
+
if h <= 0 or w <= 0:
|
| 339 |
+
return img
|
| 340 |
+
|
| 341 |
+
scale = size / max(h, w)
|
| 342 |
+
nh, nw = int(h * scale), int(w * scale)
|
| 343 |
+
nh = max(1, nh)
|
| 344 |
+
nw = max(1, nw)
|
| 345 |
+
|
| 346 |
+
resized = cv2.resize(img, (nw, nh), interpolation=cv2.INTER_AREA)
|
| 347 |
+
|
| 348 |
+
out = np.zeros((size, size, 3), dtype=np.uint8)
|
| 349 |
+
y0 = (size - nh) // 2
|
| 350 |
+
x0 = (size - nw) // 2
|
| 351 |
+
out[y0:y0+nh, x0:x0+nw] = resized
|
| 352 |
+
return out
|
| 353 |
+
|
| 354 |
+
|
| 355 |
def _enqueue_analyze(face_roi: np.ndarray):
|
| 356 |
"""把最新 ROI 丟給背景 thread,若 thread 沒在跑就啟動。"""
|
| 357 |
global _PENDING_FACE, _ANALYZE_THREAD
|
| 358 |
|
| 359 |
+
# ✅ 這行是你要的:先把 ROI 縮到固定大小(224×224)
|
| 360 |
+
face_small = _resize_letterbox_rgb(face_roi, size=224)
|
| 361 |
+
|
| 362 |
with _ANALYZE_LOCK:
|
| 363 |
+
_PENDING_FACE = face_small
|
| 364 |
|
| 365 |
if _ANALYZE_THREAD is None:
|
| 366 |
_ANALYZE_THREAD = threading.Thread(target=_analyze_worker, daemon=True)
|
| 367 |
_ANALYZE_THREAD.start()
|
| 368 |
|
| 369 |
|
| 370 |
+
|
| 371 |
# =========================
|
| 372 |
# state helper
|
| 373 |
# =========================
|