# MediaPipe graph to detect/predict face landmarks. (CPU input, and inference is # executed on CPU.) # # It is required that "face_landmark.tflite" is available at # "mediapipe/modules/face_landmark/face_landmark.tflite" # path during execution if `with_attention` is not set or set to `false`. # # It is required that "face_landmark_with_attention.tflite" is available at # "mediapipe/modules/face_landmark/face_landmark_with_attention.tflite" # path during execution if `with_attention` is set to `true`. # # EXAMPLE: # node { # calculator: "FaceLandmarkCpu" # input_stream: "IMAGE:image" # input_stream: "ROI:face_roi" # input_side_packet: "WITH_ATTENTION:with_attention" # output_stream: "LANDMARKS:face_landmarks" # } type: "FaceLandmarkCpu" # CPU image. (ImageFrame) input_stream: "IMAGE:image" # ROI (region of interest) within the given image where a face is located. # (NormalizedRect) input_stream: "ROI:roi" # Whether to run face mesh model with attention on lips and eyes. (bool) # Attention provides more accuracy on lips and eye regions as well as iris # landmarks. input_side_packet: "WITH_ATTENTION:with_attention" # 468 or 478 facial landmarks within the given ROI. (NormalizedLandmarkList) # # Number of landmarks depends on the WITH_ATTENTION flag. If it's `true` - then # there will be 478 landmarks with refined lips, eyes and irises (10 extra # landmarks are for irises), otherwise 468 non-refined landmarks are returned. # # NOTE: if a face is not present within the given ROI, for this particular # timestamp there will not be an output packet in the LANDMARKS stream. However, # the MediaPipe framework will internally inform the downstream calculators of # the absence of this packet so that they don't wait for it unnecessarily. output_stream: "LANDMARKS:face_landmarks" # Transforms the input image into a 192x192 tensor. node: { calculator: "ImageToTensorCalculator" input_stream: "IMAGE:image" input_stream: "NORM_RECT:roi" output_stream: "TENSORS:input_tensors" options: { [mediapipe.ImageToTensorCalculatorOptions.ext] { output_tensor_width: 192 output_tensor_height: 192 output_tensor_float_range { min: 0.0 max: 1.0 } } } } # Loads the face landmarks TF Lite model. node { calculator: "FaceLandmarksModelLoader" input_side_packet: "WITH_ATTENTION:with_attention" output_side_packet: "MODEL:model" } # Generates a single side packet containing a TensorFlow Lite op resolver that # supports custom ops needed by the model used in this graph. node { calculator: "TfLiteCustomOpResolverCalculator" output_side_packet: "op_resolver" } # Runs a TensorFlow Lite model on CPU that takes an image tensor and outputs a # vector of tensors representing, for instance, detection boxes/keypoints and # scores. node { calculator: "InferenceCalculator" input_stream: "TENSORS:input_tensors" input_side_packet: "MODEL:model" input_side_packet: "CUSTOM_OP_RESOLVER:op_resolver" output_stream: "TENSORS:output_tensors" options: { [mediapipe.InferenceCalculatorOptions.ext] { delegate { xnnpack {} } } } } # Splits a vector of tensors into landmark tensors and face flag tensor. node { calculator: "SwitchContainer" input_side_packet: "ENABLE:with_attention" input_stream: "output_tensors" output_stream: "landmark_tensors" output_stream: "face_flag_tensor" options: { [mediapipe.SwitchContainerOptions.ext] { contained_node: { calculator: "SplitTensorVectorCalculator" options: { [mediapipe.SplitVectorCalculatorOptions.ext] { ranges: { begin: 0 end: 1 } ranges: { begin: 1 end: 2 } } } } contained_node: { calculator: "SplitTensorVectorCalculator" options: { [mediapipe.SplitVectorCalculatorOptions.ext] { ranges: { begin: 0 end: 6 } ranges: { begin: 6 end: 7 } } } } } } } # Converts the face-flag tensor into a float that represents the confidence # score of face presence. node { calculator: "TensorsToFloatsCalculator" input_stream: "TENSORS:face_flag_tensor" output_stream: "FLOAT:face_presence_score" options { [mediapipe.TensorsToFloatsCalculatorOptions.ext] { activation: SIGMOID } } } # Applies a threshold to the confidence score to determine whether a face is # present. node { calculator: "ThresholdingCalculator" input_stream: "FLOAT:face_presence_score" output_stream: "FLAG:face_presence" options: { [mediapipe.ThresholdingCalculatorOptions.ext] { threshold: 0.5 } } } # Drop landmarks tensors if face is not present. node { calculator: "GateCalculator" input_stream: "landmark_tensors" input_stream: "ALLOW:face_presence" output_stream: "ensured_landmark_tensors" } # Decodes the landmark tensors into a vector of landmarks, where the landmark # coordinates are normalized by the size of the input image to the model. node { calculator: "SwitchContainer" input_side_packet: "ENABLE:with_attention" input_stream: "TENSORS:ensured_landmark_tensors" output_stream: "LANDMARKS:landmarks" options: { [mediapipe.SwitchContainerOptions.ext] { contained_node: { calculator: "TensorsToFaceLandmarks" } contained_node: { calculator: "TensorsToFaceLandmarksWithAttention" } } } } # Projects the landmarks from the cropped face image to the corresponding # locations on the full image before cropping (input to the graph). node { calculator: "LandmarkProjectionCalculator" input_stream: "NORM_LANDMARKS:landmarks" input_stream: "NORM_RECT:roi" output_stream: "NORM_LANDMARKS:face_landmarks" }