learntech
learntech

Reputation: 13

Have to find the EAR eye_aspect_ratio for the 3D facial_landmarks which has 468 points

I am trying to find the EAR eye aspect ratio for the below code. which is generated 468 facial_landmarks.

import time
import cv2
import numpy as np
from PIL import Image
from fdlite import FaceDetection, FaceLandmark, face_detection_to_roi
from fdlite.render import Colors, landmarks_to_render_data, render_to_image

EAR_THRESHOLD = 0.2  # Adjust this threshold as needed


def initialize_camera(camera_index=0):
    """
    Initialize the video capture from the specified camera index.

    Args:
    - camera_index (int): Index of the camera to capture video from (default is 0 for the default camera).

    Returns:
    - cv2.VideoCapture: Video capture object.
    """
    cap = cv2.VideoCapture(camera_index)
    if not cap.isOpened():
        raise ValueError("Failed to initialize the camera.")
    return cap


def resize_frame(frame, scale_factor=0.5):
    """
    Resize the frame to improve performance.

    Args:
    - frame (numpy.ndarray): Input frame.
    - scale_factor (float): Scaling factor (default is 0.5).

    Returns:
    - numpy.ndarray: Resized frame.
    """
    return cv2.resize(frame, None, fx=scale_factor, fy=scale_factor)


def convert_to_rgb(frame):
    """
    Convert the frame from OpenCV's BGR format to RGB (PIL format).

    Args:
    - frame (numpy.ndarray): Input frame in BGR format.

    Returns:
    - numpy.ndarray: Frame in RGB format.
    """
    return cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)


def detect_faces(frame, face_detector):
    """
    Detect faces in the frame.

    Args:
    - frame (numpy.ndarray): Input frame.
    - face_detector: Face detection model.

    Returns:
    - list: List of face detections.
    """
    return face_detector(frame)


def detect_landmarks(frame, face_roi, landmark_detector):
    """
    Detect landmarks in the face region of interest (ROI).

    Args:
    - frame (numpy.ndarray): Input frame.
    - face_roi (tuple): Region of interest (ROI) containing the face.
    - landmark_detector: Landmark detection model.

    Returns:
    - list: List of facial landmarks.
    """
    return landmark_detector(frame, face_roi)


def render_landmarks(frame, landmarks):
    """
    Render facial landmarks on the frame.

    Args:
    - frame (numpy.ndarray): Input frame.
    - landmarks (list): List of facial landmarks.

    Returns:
    - numpy.ndarray: Frame with landmarks rendered.
    """
    render_data = landmarks_to_render_data(landmarks, [], landmark_color=Colors.PINK, thickness=3)
    pil_frame = Image.fromarray(frame)
    return render_to_image(render_data, pil_frame)


def display_frame_with_landmarks(frame, fps):
    """
    Display the frame with landmarks and FPS information.

    Args:
    - frame (numpy.ndarray): Frame with landmarks rendered.
    - fps (float): Frames per second.
    """
    # Convert the frame to a numpy array before applying OpenCV functions
    frame_np = np.array(frame)

    # Apply OpenCV functions to the numpy array
    cv2.putText(frame_np, f"FPS: {fps:.2f}", (10, 60), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 255, 0), 2)

    # Display the frame with landmarks and FPS
    cv2.imshow("Face Landmarks Detection", frame_np)


def calculate_ear(eye_landmarks):
    """
    Calculate the eye aspect ratio (EAR) using the eye landmarks.

    Args:
    - eye_landmarks (list): List of landmarks for one eye.

    Returns:
    - float: Eye aspect ratio (EAR).
    """
    if len(eye_landmarks) != 6:
        return None  # Return None if the expected number of landmarks is not found

    try:
        # Extract relevant points for the eye (assuming the landmarks are in the format Landmark(x, y, z))
        # For left eye: 0, 1, 2, 3, 4, 5
        # For right eye: 0, 1, 2, 3, 4, 5
        v_dist1 = np.linalg.norm(
            np.array([eye_landmarks[1].x, eye_landmarks[1].y]) - np.array([eye_landmarks[5].x, eye_landmarks[5].y]))
        v_dist2 = np.linalg.norm(
            np.array([eye_landmarks[2].x, eye_landmarks[2].y]) - np.array([eye_landmarks[4].x, eye_landmarks[4].y]))
        h_dist = np.linalg.norm(
            np.array([eye_landmarks[0].x, eye_landmarks[0].y]) - np.array([eye_landmarks[3].x, eye_landmarks[3].y]))

        # Prevent division by zero
        if h_dist == 0:
            return None

        ear = (v_dist1 + v_dist2) / (2.0 * h_dist)
        return ear
    except Exception as e:
        print("Error calculating EAR:", e)
        return None


def detect_drowsiness(left_eye_landmarks, right_eye_landmarks):
    """
    Detect drowsiness based on eye aspect ratio (EAR).

    Args:
    - left_eye_landmarks (list): List of landmarks for the left eye.
    - right_eye_landmarks (list): List of landmarks for the right eye.

    Returns:
    - bool: True if drowsiness is detected, False otherwise.
    """
    left_ear = calculate_ear(left_eye_landmarks)
    right_ear = calculate_ear(right_eye_landmarks)
    avg_ear = (left_ear + right_ear) / 2.0
    print('avg_ear', avg_ear)
    if avg_ear < EAR_THRESHOLD:
        return True
    else:
        return False


def main():
    # Initialize detection models
    detect_faces_model = FaceDetection()
    detect_landmarks_model = FaceLandmark()

    # Initialize camera
    cap = initialize_camera()

    # Initialize variables for FPS calculation
    frame_count = 0
    start_time = time.time()

    # Variables for drowsiness detection
    CONSECUTIVE_FRAMES_THRESHOLD = 20
    closed_eye_frames = 0

    while True:
        # Read a frame from the video capture
        ret, frame = cap.read()
        if not ret:
            print("Error: Failed to capture frame.")
            break
        frame_count += 1

        # Resize frame for performance
        resized_frame = resize_frame(frame)

        # Convert frame to RGB format
        rgb_frame = convert_to_rgb(resized_frame)

        # Detect faces
        face_detections = detect_faces(rgb_frame, detect_faces_model)

        if face_detections:
            # Get ROI for the first face found
            face_roi = face_detection_to_roi(face_detections[0], (resized_frame.shape[1], resized_frame.shape[0]))

            # Detect face landmarks
            landmarks = detect_landmarks(rgb_frame, face_roi, detect_landmarks_model)

            # Render landmarks on the frame
            frame_with_landmarks = render_landmarks(resized_frame, landmarks)

            # Calculate FPS
            elapsed_time = time.time() - start_time
            fps = frame_count / elapsed_time

            # Display frame with landmarks and FPS
            display_frame_with_landmarks(frame_with_landmarks, fps)

            # Detect drowsiness
            left_eye_landmarks = landmarks[0:6]  # Assuming the first 6 landmarks correspond to the left eye
            right_eye_landmarks = landmarks[6:12]  # Assuming the next 6 landmarks correspond to the right eye
            if detect_drowsiness(left_eye_landmarks, right_eye_landmarks):
                print("Drowsiness detected!")

        else:
            # Display the original frame if no face is detected
            cv2.putText(resized_frame, "No Face Detected", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (0, 0, 255), 2)
            cv2.imshow("Face Landmarks Detection", resized_frame)

        # Check for key press to exit
        key = cv2.waitKey(1)
        if key == ord('q'):
            break

    # Release the video capture and close all OpenCV windows
    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

The landmarks i got from as result id 3D array as like this Landmark(x=0.6211224, y=0.46492937, z=-0.013669399), Landmark(x=0.66713226, y=0.4619585, z=0.0010283475) for the below line of code

# Detect face landmarks landmarks = detect_landmarks(rgb_frame, face_roi, detect_landmarks_model)

enter image description here

i tried by changing the EAR_THRESHOLD by not working and i am not able to find the where the issue is happening , Kindly help me to find the eye aspect ratio to detect that person is closed his/her eyes.

Upvotes: 0

Views: 51

Answers (0)

Related Questions