|
|
import os
|
|
|
import cv2
|
|
|
import numpy as np
|
|
|
from codes.base.core import (
|
|
|
detections_to_rect,
|
|
|
landmarks_to_detections,
|
|
|
slice_from_roi,
|
|
|
tflite_inference,
|
|
|
transform_rect,
|
|
|
)
|
|
|
|
|
|
|
|
|
PATH2ROOT_ABS = os.path.dirname(__file__) + "/../../"
|
|
|
|
|
|
|
|
|
def from_landmarks_to_depth(
|
|
|
frame_rgb, eye_landmarks, image_size, is_right_eye=False, focal_length=None
|
|
|
):
|
|
|
"""
|
|
|
Predicting the iris position using eyes landmarks
|
|
|
|
|
|
Parameters:
|
|
|
frame_rgb: the frame (RGB)
|
|
|
eye_landmarks: the landmarks of the eyes
|
|
|
image_size: the image size
|
|
|
is_right_eye: whether or not it's the right eye
|
|
|
focal_length: the focal length of the camera
|
|
|
|
|
|
Returns:
|
|
|
success: whether or not the iris is detected
|
|
|
depth: distance to the camera
|
|
|
iris_size: the size of the iris
|
|
|
iris_landmarks: iris landmarks
|
|
|
eye_contours: eye contours
|
|
|
iris_landmarks_respect: iris landmarks respect to the eyes
|
|
|
"""
|
|
|
if focal_length is None:
|
|
|
focal_length = frame_rgb.shape[1]
|
|
|
|
|
|
detections = landmarks_to_detections(eye_landmarks)
|
|
|
rect = detections_to_rect(detections, image_size, rotation_vector_start_end=(0, 1))
|
|
|
roi = transform_rect(rect, image_size, scale_x=2.3, scale_y=2.3)
|
|
|
|
|
|
slice_y = slice_from_roi(roi, image_size, False)
|
|
|
slice_x = slice_from_roi(roi, image_size, True)
|
|
|
eye_image = frame_rgb[slice(*slice_y), slice(*slice_x), :]
|
|
|
position_in_frame = np.array((slice_x[0], slice_y[0], 0))
|
|
|
|
|
|
if eye_image.any():
|
|
|
success = True
|
|
|
eye_contours, iris_landmarks, eye_frame_low = detect_iris(
|
|
|
eye_image.copy(), is_right_eye=is_right_eye
|
|
|
)
|
|
|
|
|
|
iris_landmarks_respect = iris_landmarks.copy()
|
|
|
|
|
|
eye_contours[:, 0] = eye_contours[:, 0] * eye_image.shape[0]
|
|
|
eye_contours[:, 1] = eye_contours[:, 1] * eye_image.shape[1]
|
|
|
eye_contours = eye_contours + position_in_frame
|
|
|
|
|
|
eye_contours[:, 0] = eye_contours[:, 0] / frame_rgb.shape[1]
|
|
|
eye_contours[:, 1] = eye_contours[:, 1] / frame_rgb.shape[0]
|
|
|
|
|
|
iris_landmarks[:, 0] = iris_landmarks[:, 0] * eye_image.shape[0]
|
|
|
iris_landmarks[:, 1] = iris_landmarks[:, 1] * eye_image.shape[1]
|
|
|
iris_landmarks = iris_landmarks + position_in_frame
|
|
|
|
|
|
iris_landmarks[:, 0] = iris_landmarks[:, 0] / frame_rgb.shape[1]
|
|
|
iris_landmarks[:, 1] = iris_landmarks[:, 1] / frame_rgb.shape[0]
|
|
|
|
|
|
depth, iris_size = calculate_iris_depth(iris_landmarks, image_size, focal_length)
|
|
|
|
|
|
else:
|
|
|
success = False
|
|
|
depth = None
|
|
|
iris_size = None
|
|
|
iris_landmarks = None
|
|
|
eye_contours = None
|
|
|
iris_landmarks_respect = None
|
|
|
|
|
|
return success, depth, iris_size, iris_landmarks, eye_contours, iris_landmarks_respect
|
|
|
|
|
|
|
|
|
def detect_iris(eye_frame, is_right_eye=False):
|
|
|
side_low = 64
|
|
|
eye_frame_low = cv2.resize(
|
|
|
eye_frame, (side_low, side_low), interpolation=cv2.INTER_AREA
|
|
|
)
|
|
|
|
|
|
model_path = PATH2ROOT_ABS + "models/iris/iris_landmark.tflite"
|
|
|
|
|
|
if is_right_eye:
|
|
|
eye_frame_low = np.fliplr(eye_frame_low)
|
|
|
|
|
|
outputs = tflite_inference(eye_frame_low / 127.5 - 1.0, model_path)
|
|
|
eye_contours_low = np.reshape(outputs[0], (71, 3))
|
|
|
iris_landmarks_low = np.reshape(outputs[1], (5, 3))
|
|
|
|
|
|
eye_contours = eye_contours_low / side_low
|
|
|
iris_landmarks = iris_landmarks_low / side_low
|
|
|
|
|
|
if is_right_eye:
|
|
|
eye_contours[:, 0] = 1 - eye_contours[:, 0]
|
|
|
iris_landmarks[:, 0] = 1 - iris_landmarks[:, 0]
|
|
|
|
|
|
return eye_contours, iris_landmarks, eye_frame_low
|
|
|
|
|
|
|
|
|
def calculate_iris_depth(iris_landmarks, image_size, focal_length_pixel):
|
|
|
"""
|
|
|
iris_landmarks should be normalized to the complete image frame
|
|
|
depth in mm
|
|
|
"""
|
|
|
iris_size = calculate_iris_diameter(iris_landmarks, image_size)
|
|
|
depth = calculate_depth(
|
|
|
iris_landmarks[0, :], focal_length_pixel, iris_size, image_size
|
|
|
)
|
|
|
|
|
|
return depth, iris_size
|
|
|
|
|
|
|
|
|
def get_depth(x0, y0, x1, y1):
|
|
|
return np.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
|
|
|
|
|
|
|
|
|
def get_landmark_depth(ld0, ld1, image_size):
|
|
|
return get_depth(
|
|
|
ld0[0] * image_size[0],
|
|
|
ld0[1] * image_size[1],
|
|
|
ld1[0] * image_size[0],
|
|
|
ld1[1] * image_size[1],
|
|
|
)
|
|
|
|
|
|
|
|
|
def calculate_iris_diameter(iris_landmarks, image_size):
|
|
|
dist_vert = get_landmark_depth(
|
|
|
iris_landmarks[1, :], iris_landmarks[3, :], image_size
|
|
|
)
|
|
|
dist_hori = get_landmark_depth(
|
|
|
iris_landmarks[2, :], iris_landmarks[4, :], image_size
|
|
|
)
|
|
|
|
|
|
return (dist_hori + dist_vert) / 2.0
|
|
|
|
|
|
|
|
|
def calculate_depth(center_landmark, focal_length_pixel, iris_size, image_size):
|
|
|
|
|
|
human_iris_size_in_mm = 11.8
|
|
|
origin = np.array(image_size) / 2.0
|
|
|
center_landmark_pixel = center_landmark[:2] * np.array(image_size)
|
|
|
y = get_depth(
|
|
|
origin[0], origin[1], center_landmark_pixel[0], center_landmark_pixel[1]
|
|
|
)
|
|
|
x = np.sqrt(focal_length_pixel ** 2 + y ** 2)
|
|
|
depth = human_iris_size_in_mm * x / iris_size
|
|
|
|
|
|
return depth
|
|
|
|