Add back resolution threshold. Improve eye openness detection
This commit is contained in:
parent
fd4ef490c7
commit
dd55dcbf3c
1 changed files with 16 additions and 13 deletions
29
timelapse.py
29
timelapse.py
|
|
@ -249,7 +249,7 @@ def get_head_pose(landmarks, image):
|
||||||
return pitch, yaw, roll
|
return pitch, yaw, roll
|
||||||
|
|
||||||
|
|
||||||
def detect_landmarks(image, face_data, max_landmark_size=300):
|
def detect_landmarks(image, face_data, face_resolution_threshold):
|
||||||
"""
|
"""
|
||||||
Detects facial landmarks in the image, resizing if necessary for better detection.
|
Detects facial landmarks in the image, resizing if necessary for better detection.
|
||||||
|
|
||||||
|
|
@ -260,7 +260,7 @@ def detect_landmarks(image, face_data, max_landmark_size=300):
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
dict or None: Dictionary containing facial landmarks in numpy arrays if successful,
|
dict or None: Dictionary containing facial landmarks in numpy arrays if successful,
|
||||||
None if detection failed.
|
None if face resolution is too low.
|
||||||
"""
|
"""
|
||||||
# Get face rectangle from metadata with proper scaling
|
# Get face rectangle from metadata with proper scaling
|
||||||
face_img_width = face_data.get("imageWidth")
|
face_img_width = face_data.get("imageWidth")
|
||||||
|
|
@ -274,14 +274,18 @@ def detect_landmarks(image, face_data, max_landmark_size=300):
|
||||||
y2 = int(face_data.get("boundingBoxY2", 0) * scale_y)
|
y2 = int(face_data.get("boundingBoxY2", 0) * scale_y)
|
||||||
w = x2 - x1
|
w = x2 - x1
|
||||||
h = y2 - y1
|
h = y2 - y1
|
||||||
|
|
||||||
|
if w < face_resolution_threshold or h < face_resolution_threshold:
|
||||||
|
return None
|
||||||
|
|
||||||
# Crop the face region from the image
|
# Crop the face region from the image
|
||||||
face_crop = image.crop((x1, y1, x2, y2))
|
face_crop = image.crop((x1, y1, x2, y2))
|
||||||
|
|
||||||
# If the cropped face is too large, resize it for better landmark detection
|
# If the cropped face is too large, resize it for better landmark detection
|
||||||
|
optimal_size = 256 # optimal size for landmark detection
|
||||||
scale_factor = 1.0
|
scale_factor = 1.0
|
||||||
if w > max_landmark_size or h > max_landmark_size:
|
if w > optimal_size or h > optimal_size:
|
||||||
scale_factor = max_landmark_size / max(w, h)
|
scale_factor = optimal_size / max(w, h)
|
||||||
new_w = int(w * scale_factor)
|
new_w = int(w * scale_factor)
|
||||||
new_h = int(h * scale_factor)
|
new_h = int(h * scale_factor)
|
||||||
face_crop = face_crop.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
face_crop = face_crop.resize((new_w, new_h), Image.Resampling.LANCZOS)
|
||||||
|
|
@ -331,7 +335,7 @@ def detect_landmarks(image, face_data, max_landmark_size=300):
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
def check_eye_visibility(left_eye, right_eye, ear_threshold=0.2):
|
def check_eye_visibility(left_eye, right_eye, ear_threshold=0.2) -> bool:
|
||||||
"""
|
"""
|
||||||
Checks if both eyes are visible by calculating the Eye Aspect Ratio (EAR).
|
Checks if both eyes are visible by calculating the Eye Aspect Ratio (EAR).
|
||||||
|
|
||||||
|
|
@ -341,7 +345,7 @@ def check_eye_visibility(left_eye, right_eye, ear_threshold=0.2):
|
||||||
ear_threshold (float): Threshold for eye visibility.
|
ear_threshold (float): Threshold for eye visibility.
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (left_ear, right_ear) if both eyes are visible, None otherwise.
|
bool: True if both eyes are open enough, False otherwise.
|
||||||
"""
|
"""
|
||||||
def calculate_ear(eye):
|
def calculate_ear(eye):
|
||||||
v1 = np.linalg.norm(eye[1] - eye[5])
|
v1 = np.linalg.norm(eye[1] - eye[5])
|
||||||
|
|
@ -354,10 +358,9 @@ def check_eye_visibility(left_eye, right_eye, ear_threshold=0.2):
|
||||||
right_ear = calculate_ear(right_eye)
|
right_ear = calculate_ear(right_eye)
|
||||||
|
|
||||||
if left_ear < ear_threshold or right_ear < ear_threshold:
|
if left_ear < ear_threshold or right_ear < ear_threshold:
|
||||||
logger.info(f"Face turned too much to the side (EAR: L={left_ear:.2f}, R={right_ear:.2f})")
|
return False
|
||||||
return None
|
|
||||||
|
|
||||||
return left_ear, right_ear
|
return True
|
||||||
|
|
||||||
|
|
||||||
def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold, pose_threshold, left_eye_pos):
|
def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold, pose_threshold, left_eye_pos):
|
||||||
|
|
@ -376,7 +379,7 @@ def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold
|
||||||
PIL.Image or None: The aligned face image if successful, None otherwise.
|
PIL.Image or None: The aligned face image if successful, None otherwise.
|
||||||
"""
|
"""
|
||||||
try:
|
try:
|
||||||
# Get face rectangle from metadata with proper scaling
|
# DEBUG : remove after testing
|
||||||
face_img_width = face_data.get("imageWidth")
|
face_img_width = face_data.get("imageWidth")
|
||||||
face_img_height = face_data.get("imageHeight")
|
face_img_height = face_data.get("imageHeight")
|
||||||
img_width, img_height = image.size
|
img_width, img_height = image.size
|
||||||
|
|
@ -394,14 +397,14 @@ def crop_and_align_face(image, face_data, resize_size, face_resolution_threshold
|
||||||
img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
|
img_np = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
|
||||||
|
|
||||||
# Detect landmarks in the face region
|
# Detect landmarks in the face region
|
||||||
landmarks = detect_landmarks(image, face_data)
|
landmarks = detect_landmarks(image, face_data, face_resolution_threshold)
|
||||||
if not landmarks:
|
if not landmarks:
|
||||||
logger.info("No facial landmarks detected")
|
logger.info("Face resolution is too low")
|
||||||
draw_landmarks(img_np, None, (x1, y1, x2, y2), "discarded/no_landmarks.jpg")
|
|
||||||
return None
|
return None
|
||||||
|
|
||||||
# Check if both eyes are visible
|
# Check if both eyes are visible
|
||||||
if not check_eye_visibility(landmarks['left_eye'], landmarks['right_eye']):
|
if not check_eye_visibility(landmarks['left_eye'], landmarks['right_eye']):
|
||||||
|
logger.info("Eyes are too closed")
|
||||||
draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), "discarded/side_face.jpg")
|
draw_landmarks(img_np, landmarks['all_landmarks'], (x1, y1, x2, y2), "discarded/side_face.jpg")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue