import numpy as np import pytest from merlin.features.blink import BlinkDetector, BlinkEvent, eye_aspect_ratio LEFT_EYE = [33, 160, 158, 133, 153, 144] RIGHT_EYE = [362, 385, 387, 263, 373, 380] def _face(n: int = 478) -> np.ndarray: return np.zeros((n, 3), dtype=np.float32) def _set_eye_open(face: np.ndarray, indices: list[int]) -> None: """Set 6 EAR landmarks so EAR = ~0.35 (open eye).""" p1, p2, p3, p4, p5, p6 = indices face[p1] = [0.0, 0.0, 0.0] face[p4] = [1.0, 0.0, 0.0] face[p2] = [0.25, 0.2, 0.0] face[p6] = [0.25, -0.2, 0.0] face[p3] = [0.75, 0.2, 0.0] face[p5] = [0.75, -0.2, 0.0] def _set_eye_closed(face: np.ndarray, indices: list[int]) -> None: """Set 6 EAR landmarks so EAR ≈ 0 (closed).""" for i in indices: face[i] = [0.0, 0.0, 0.0] def test_ear_open_eye(): face = _face() _set_eye_open(face, LEFT_EYE) ear = eye_aspect_ratio(face, LEFT_EYE) assert ear > 0.20 def test_ear_closed_eye(): face = _face() _set_eye_closed(face, LEFT_EYE) ear = eye_aspect_ratio(face, LEFT_EYE) assert ear < 0.05 def test_no_blink_when_both_open(): detector = BlinkDetector(threshold=0.20) face = _face() _set_eye_open(face, LEFT_EYE) _set_eye_open(face, RIGHT_EYE) assert detector.detect(face) is None def test_left_blink_detected(): detector = BlinkDetector(threshold=0.20) face = _face() _set_eye_closed(face, LEFT_EYE) _set_eye_open(face, RIGHT_EYE) assert detector.detect(face) == BlinkEvent.LEFT def test_right_blink_detected(): detector = BlinkDetector(threshold=0.20) face = _face() _set_eye_open(face, LEFT_EYE) _set_eye_closed(face, RIGHT_EYE) assert detector.detect(face) == BlinkEvent.RIGHT def test_both_blink_detected(): detector = BlinkDetector(threshold=0.20) face = _face() _set_eye_closed(face, LEFT_EYE) _set_eye_closed(face, RIGHT_EYE) assert detector.detect(face) == BlinkEvent.BOTH