def iris_roi_from_face_landmarks(
        face_landmarks: Sequence[Landmark],
        image_size: Tuple[int, int]) -> Tuple[Rect, Rect]:
    """Extract iris landmark detection ROIs from face landmarks.

    Use this function to get the ROI for the left and right eye. The resulting
    bounding boxes are suitable for passing to `IrisDetection` as the ROI
    parameter. This is a pre-processing step originally found in the
    MediaPipe sub-graph "iris_landmark_landmarks_to_roi":

    ```
        def iris_detection(image, face_landmarks, iris_landmark_model):
            # extract left- and right eye ROI from face landmarks
            roi_left_eye, roi_right_eye = iris_roi_from_face_landmarks(
                face_landmarks)
            # use ROIs with iris detection
            iris_results_left = iris_landmark_model(image, roi_left_eye)
            iris_results_right = iris_landmark_model(image, roi_right_eye,
                                                    is_right_eye=True)
            return iris_result_left, iris_results_right
    ```

    Args:
        landmarks (list): Result of a `FaceLandmark` call containing face
            landmark detection results.

        image_size (tuple): Tuple of `(width, height)` representing the size
            of the image in pixels. The image must be the same as the one used
            for face lanmark detection.

    Return:
        (Rect, Rect) Tuple of ROIs containing the absolute pixel coordinates
        of the left and right eye regions. The ROIs can be passed to
        `IrisDetetion` together with the original image to detect iris
        landmarks.
    """
    left_eye_landmarks = (face_landmarks[LEFT_EYE_START],
                          face_landmarks[LEFT_EYE_END])
    bbox = bbox_from_landmarks(left_eye_landmarks)
    rotation_keypoints = [(point.x, point.y) for point in left_eye_landmarks]
    w, h = image_size
    left_eye_roi = bbox_to_roi(bbox, (w, h), rotation_keypoints, ROI_SCALE,
                               SizeMode.SQUARE_LONG)

    right_eye_landmarks = (face_landmarks[RIGHT_EYE_START],
                           face_landmarks[RIGHT_EYE_END])
    bbox = bbox_from_landmarks(right_eye_landmarks)
    rotation_keypoints = [(point.x, point.y) for point in right_eye_landmarks]
    right_eye_roi = bbox_to_roi(bbox, (w, h), rotation_keypoints, ROI_SCALE,
                                SizeMode.SQUARE_LONG)

    return left_eye_roi, right_eye_roi
Beispiel #2
0
def _get_iris_location(results: IrisResults,
                       image_size: _Size) -> Tuple[_Rect, _Size]:
    """Return iris location and -size"""
    bbox = bbox_from_landmarks(results.iris).absolute(image_size)
    width, height = int(bbox.width + 1), int(bbox.height + 1)
    size = (width, height)
    left, top = int(bbox.xmin), int(bbox.ymin)
    location = (left, top, left + width, top + height)
    return location, size
def _get_iris_mask(
    results: IrisResults,
    iris_location: _Rect,
    iris_size: _Size,
    image_size: _Size
) -> PILImage:
    """Return a mask for the visible portion of the iris inside eye landmarks.
    """
    left, top, _, bottom = iris_location
    iris_width, iris_height = iris_size
    img_width, img_height = image_size
    # sort lexicographically by x then y
    eyeball_sorted = sorted([(int(pt.x * img_width), int(pt.y * img_height))
                             for pt in results.eyeball_contour])
    bbox = bbox_from_landmarks(results.eyeball_contour).absolute(image_size)
    x_ofs = left
    y_ofs = top
    y_start = int(max(bbox.ymin, top))
    y_end = int(min(bbox.ymax, bottom))
    mask = np.zeros((iris_height, iris_width), dtype=np.uint8)
    # iris ellipse radii (horizontal and vertical radius)
    a = iris_width // 2
    b = iris_height // 2
    # iris ellipse foci (horizontal and vertical)
    cx = left + a
    cy = top + b
    box_center_y = int(bbox.ymin + bbox.ymax) // 2
    b_sqr = b**2
    for y in range(y_start, y_end):
        # evaluate iris ellipse at y
        x = int(a * np.math.sqrt(b_sqr - (y-cy)**2) / b)
        x0, x1 = cx - x, cx + x
        A, B = _find_contour_segment(eyeball_sorted, (x0, y))
        left_inside = _is_below_segment(A, B, (x0, y), box_center_y)
        C, D = _find_contour_segment(eyeball_sorted, (x1, y))
        right_inside = _is_below_segment(C, D, (x1, y), box_center_y)
        if not (left_inside or right_inside):
            continue
        elif not left_inside:
            x0 = int(max((B[0] - A[0])/(B[1] - A[1]) * (y - A[1]) + A[0], x0))
        elif not right_inside:
            x1 = int(min((D[0] - C[0])/(D[1] - C[1]) * (y - C[1]) + C[0], x1))
        # mark ellipse row as visible
        mask[(y - y_ofs), int(x0 - x_ofs):int(x1 - x_ofs)] = 255
    return Image.fromarray(mask, mode='L')