239 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
			
		
		
	
	
			239 lines
		
	
	
		
			6.4 KiB
		
	
	
	
		
			Python
		
	
	
	
	
	
| # Copyright 2020 The MediaPipe Authors.
 | |
| #
 | |
| # Licensed under the Apache License, Version 2.0 (the "License");
 | |
| # you may not use this file except in compliance with the License.
 | |
| # You may obtain a copy of the License at
 | |
| #
 | |
| #      http://www.apache.org/licenses/LICENSE-2.0
 | |
| #
 | |
| # Unless required by applicable law or agreed to in writing, software
 | |
| # distributed under the License is distributed on an "AS IS" BASIS,
 | |
| # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 | |
| # See the License for the specific language governing permissions and
 | |
| # limitations under the License.
 | |
| 
 | |
| """MediaPipe FaceMesh."""
 | |
| 
 | |
| from typing import NamedTuple
 | |
| 
 | |
| import numpy as np
 | |
| 
 | |
| from mediapipe.calculators.core import constant_side_packet_calculator_pb2
 | |
| # pylint: disable=unused-import
 | |
| from mediapipe.calculators.core import gate_calculator_pb2
 | |
| from mediapipe.calculators.core import split_vector_calculator_pb2
 | |
| from mediapipe.calculators.tensor import image_to_tensor_calculator_pb2
 | |
| from mediapipe.calculators.tensor import inference_calculator_pb2
 | |
| from mediapipe.calculators.tensor import tensors_to_classification_calculator_pb2
 | |
| from mediapipe.calculators.tensor import tensors_to_detections_calculator_pb2
 | |
| from mediapipe.calculators.tensor import tensors_to_landmarks_calculator_pb2
 | |
| from mediapipe.calculators.tflite import ssd_anchors_calculator_pb2
 | |
| from mediapipe.calculators.util import association_calculator_pb2
 | |
| from mediapipe.calculators.util import detections_to_rects_calculator_pb2
 | |
| from mediapipe.calculators.util import logic_calculator_pb2
 | |
| from mediapipe.calculators.util import non_max_suppression_calculator_pb2
 | |
| from mediapipe.calculators.util import rect_transformation_calculator_pb2
 | |
| from mediapipe.calculators.util import thresholding_calculator_pb2
 | |
| # pylint: enable=unused-import
 | |
| from mediapipe.python.solution_base import SolutionBase
 | |
| 
 | |
| BINARYPB_FILE_PATH = 'mediapipe/modules/face_landmark/face_landmark_front_cpu.binarypb'
 | |
| FACE_CONNECTIONS = frozenset([
 | |
|     # Lips.
 | |
|     (61, 146),
 | |
|     (146, 91),
 | |
|     (91, 181),
 | |
|     (181, 84),
 | |
|     (84, 17),
 | |
|     (17, 314),
 | |
|     (314, 405),
 | |
|     (405, 321),
 | |
|     (321, 375),
 | |
|     (375, 291),
 | |
|     (61, 185),
 | |
|     (185, 40),
 | |
|     (40, 39),
 | |
|     (39, 37),
 | |
|     (37, 0),
 | |
|     (0, 267),
 | |
|     (267, 269),
 | |
|     (269, 270),
 | |
|     (270, 409),
 | |
|     (409, 291),
 | |
|     (78, 95),
 | |
|     (95, 88),
 | |
|     (88, 178),
 | |
|     (178, 87),
 | |
|     (87, 14),
 | |
|     (14, 317),
 | |
|     (317, 402),
 | |
|     (402, 318),
 | |
|     (318, 324),
 | |
|     (324, 308),
 | |
|     (78, 191),
 | |
|     (191, 80),
 | |
|     (80, 81),
 | |
|     (81, 82),
 | |
|     (82, 13),
 | |
|     (13, 312),
 | |
|     (312, 311),
 | |
|     (311, 310),
 | |
|     (310, 415),
 | |
|     (415, 308),
 | |
|     # Left eye.
 | |
|     (263, 249),
 | |
|     (249, 390),
 | |
|     (390, 373),
 | |
|     (373, 374),
 | |
|     (374, 380),
 | |
|     (380, 381),
 | |
|     (381, 382),
 | |
|     (382, 362),
 | |
|     (263, 466),
 | |
|     (466, 388),
 | |
|     (388, 387),
 | |
|     (387, 386),
 | |
|     (386, 385),
 | |
|     (385, 384),
 | |
|     (384, 398),
 | |
|     (398, 362),
 | |
|     # Left eyebrow.
 | |
|     (276, 283),
 | |
|     (283, 282),
 | |
|     (282, 295),
 | |
|     (295, 285),
 | |
|     (300, 293),
 | |
|     (293, 334),
 | |
|     (334, 296),
 | |
|     (296, 336),
 | |
|     # Right eye.
 | |
|     (33, 7),
 | |
|     (7, 163),
 | |
|     (163, 144),
 | |
|     (144, 145),
 | |
|     (145, 153),
 | |
|     (153, 154),
 | |
|     (154, 155),
 | |
|     (155, 133),
 | |
|     (33, 246),
 | |
|     (246, 161),
 | |
|     (161, 160),
 | |
|     (160, 159),
 | |
|     (159, 158),
 | |
|     (158, 157),
 | |
|     (157, 173),
 | |
|     (173, 133),
 | |
|     # Right eyebrow.
 | |
|     (46, 53),
 | |
|     (53, 52),
 | |
|     (52, 65),
 | |
|     (65, 55),
 | |
|     (70, 63),
 | |
|     (63, 105),
 | |
|     (105, 66),
 | |
|     (66, 107),
 | |
|     # Face oval.
 | |
|     (10, 338),
 | |
|     (338, 297),
 | |
|     (297, 332),
 | |
|     (332, 284),
 | |
|     (284, 251),
 | |
|     (251, 389),
 | |
|     (389, 356),
 | |
|     (356, 454),
 | |
|     (454, 323),
 | |
|     (323, 361),
 | |
|     (361, 288),
 | |
|     (288, 397),
 | |
|     (397, 365),
 | |
|     (365, 379),
 | |
|     (379, 378),
 | |
|     (378, 400),
 | |
|     (400, 377),
 | |
|     (377, 152),
 | |
|     (152, 148),
 | |
|     (148, 176),
 | |
|     (176, 149),
 | |
|     (149, 150),
 | |
|     (150, 136),
 | |
|     (136, 172),
 | |
|     (172, 58),
 | |
|     (58, 132),
 | |
|     (132, 93),
 | |
|     (93, 234),
 | |
|     (234, 127),
 | |
|     (127, 162),
 | |
|     (162, 21),
 | |
|     (21, 54),
 | |
|     (54, 103),
 | |
|     (103, 67),
 | |
|     (67, 109),
 | |
|     (109, 10)
 | |
| ])
 | |
| 
 | |
| 
 | |
| class FaceMesh(SolutionBase):
 | |
|   """MediaPipe FaceMesh.
 | |
| 
 | |
|   MediaPipe FaceMesh processes an RGB image and returns the face landmarks on
 | |
|   each detected face.
 | |
| 
 | |
|   Please refer to https://solutions.mediapipe.dev/face_mesh#python-solution-api
 | |
|   for usage examples.
 | |
|   """
 | |
| 
 | |
|   def __init__(self,
 | |
|                static_image_mode=False,
 | |
|                max_num_faces=1,
 | |
|                min_detection_confidence=0.5,
 | |
|                min_tracking_confidence=0.5):
 | |
|     """Initializes a MediaPipe FaceMesh object.
 | |
| 
 | |
|     Args:
 | |
|       static_image_mode: Whether to treat the input images as a batch of static
 | |
|         and possibly unrelated images, or a video stream. See details in
 | |
|         https://solutions.mediapipe.dev/face_mesh#static_image_mode.
 | |
|       max_num_faces: Maximum number of faces to detect. See details in
 | |
|         https://solutions.mediapipe.dev/face_mesh#max_num_faces.
 | |
|       min_detection_confidence: Minimum confidence value ([0.0, 1.0]) for face
 | |
|         detection to be considered successful. See details in
 | |
|         https://solutions.mediapipe.dev/face_mesh#min_detection_confidence.
 | |
|       min_tracking_confidence: Minimum confidence value ([0.0, 1.0]) for the
 | |
|         face landmarks to be considered tracked successfully. See details in
 | |
|         https://solutions.mediapipe.dev/face_mesh#min_tracking_confidence.
 | |
|     """
 | |
|     super().__init__(
 | |
|         binary_graph_path=BINARYPB_FILE_PATH,
 | |
|         side_inputs={
 | |
|             'num_faces': max_num_faces,
 | |
|         },
 | |
|         calculator_params={
 | |
|             'ConstantSidePacketCalculator.packet': [
 | |
|                 constant_side_packet_calculator_pb2
 | |
|                 .ConstantSidePacketCalculatorOptions.ConstantSidePacket(
 | |
|                     bool_value=not static_image_mode)
 | |
|             ],
 | |
|             'facedetectionfrontcpu__TensorsToDetectionsCalculator.min_score_thresh':
 | |
|                 min_detection_confidence,
 | |
|             'facelandmarkcpu__ThresholdingCalculator.threshold':
 | |
|                 min_tracking_confidence,
 | |
|         },
 | |
|         outputs=['multi_face_landmarks'])
 | |
| 
 | |
|   def process(self, image: np.ndarray) -> NamedTuple:
 | |
|     """Processes an RGB image and returns the face landmarks on each detected face.
 | |
| 
 | |
|     Args:
 | |
|       image: An RGB image represented as a numpy ndarray.
 | |
| 
 | |
|     Raises:
 | |
|       RuntimeError: If the underlying graph throws any error.
 | |
|       ValueError: If the input image is not three channel RGB.
 | |
| 
 | |
|     Returns:
 | |
|       A NamedTuple object with a "multi_face_landmarks" field that contains the
 | |
|       face landmarks on each detected face.
 | |
|     """
 | |
| 
 | |
|     return super().process(input_data={'image': image})
 |