Project import generated by Copybara.
GitOrigin-RevId: 6e5aa035cd1f6a9333962df5d3ab97a05bd5744e
This commit is contained in:
committed by
Sebastian Schmidt
parent
4a20e9909d
commit
c688862570
@@ -16,6 +16,8 @@ load(
|
||||
"//mediapipe/framework/tool:mediapipe_graph.bzl",
|
||||
"mediapipe_simple_subgraph",
|
||||
)
|
||||
load("//mediapipe/framework/port:build_config.bzl", "mediapipe_proto_library")
|
||||
load("//mediapipe/framework:mediapipe_cc_test.bzl", "mediapipe_cc_test")
|
||||
|
||||
licenses(["notice"])
|
||||
|
||||
@@ -26,7 +28,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_short_range_by_roi_cpu.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeByRoiCpu",
|
||||
deps = [
|
||||
":face_detection_short_range_common",
|
||||
":face_detection_short_range",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
@@ -38,7 +40,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_short_range_by_roi_gpu.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeByRoiGpu",
|
||||
deps = [
|
||||
":face_detection_short_range_common",
|
||||
":face_detection_short_range",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
@@ -50,10 +52,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_short_range_cpu.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeCpu",
|
||||
deps = [
|
||||
":face_detection_short_range_common",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
":face_detection_short_range",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -62,22 +61,66 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_short_range_gpu.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeGpu",
|
||||
deps = [
|
||||
":face_detection_short_range_common",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
":face_detection_short_range",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_simple_subgraph(
|
||||
name = "face_detection_short_range_common",
|
||||
graph = "face_detection_short_range_common.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeCommon",
|
||||
name = "face_detection_short_range",
|
||||
graph = "face_detection_short_range.pbtxt",
|
||||
register_as = "FaceDetectionShortRange",
|
||||
deps = [
|
||||
":face_detection",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_simple_subgraph(
|
||||
name = "face_detection_full_range",
|
||||
graph = "face_detection_full_range.pbtxt",
|
||||
register_as = "FaceDetectionFullRange",
|
||||
deps = [
|
||||
":face_detection",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_simple_subgraph(
|
||||
name = "face_detection_without_roi",
|
||||
graph = "face_detection_without_roi.pbtxt",
|
||||
register_as = "FaceDetectionWithoutRoi",
|
||||
deps = [
|
||||
":face_detection",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_simple_subgraph(
|
||||
name = "face_detection",
|
||||
graph = "face_detection.pbtxt",
|
||||
register_as = "FaceDetection",
|
||||
deps = [
|
||||
":face_detection_cc_proto",
|
||||
":face_detection_options_lib",
|
||||
"//mediapipe/calculators/core:gate_calculator",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/tensor:tensors_to_detections_calculator",
|
||||
"//mediapipe/calculators/tflite:ssd_anchors_calculator",
|
||||
"//mediapipe/calculators/util:detection_projection_calculator",
|
||||
"//mediapipe/calculators/util:non_max_suppression_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_proto_library(
|
||||
name = "face_detection_proto",
|
||||
srcs = ["face_detection.proto"],
|
||||
deps = [
|
||||
"//mediapipe/calculators/core:gate_calculator_proto",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator_proto",
|
||||
"//mediapipe/calculators/tensor:inference_calculator_proto",
|
||||
"//mediapipe/calculators/tensor:tensors_to_detections_calculator_proto",
|
||||
"//mediapipe/calculators/tflite:ssd_anchors_calculator_proto",
|
||||
"//mediapipe/framework:calculator_options_proto",
|
||||
"//mediapipe/gpu:gpu_origin_proto",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -86,10 +129,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_full_range_cpu.pbtxt",
|
||||
register_as = "FaceDetectionFullRangeCpu",
|
||||
deps = [
|
||||
":face_detection_full_range_common",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
":face_detection_full_range",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -98,22 +138,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_full_range_gpu.pbtxt",
|
||||
register_as = "FaceDetectionFullRangeGpu",
|
||||
deps = [
|
||||
":face_detection_full_range_common",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
"//mediapipe/calculators/util:to_image_calculator",
|
||||
],
|
||||
)
|
||||
|
||||
mediapipe_simple_subgraph(
|
||||
name = "face_detection_full_range_common",
|
||||
graph = "face_detection_full_range_common.pbtxt",
|
||||
register_as = "FaceDetectionFullRangeCommon",
|
||||
deps = [
|
||||
"//mediapipe/calculators/tensor:tensors_to_detections_calculator",
|
||||
"//mediapipe/calculators/tflite:ssd_anchors_calculator",
|
||||
"//mediapipe/calculators/util:detection_projection_calculator",
|
||||
"//mediapipe/calculators/util:non_max_suppression_calculator",
|
||||
":face_detection_full_range",
|
||||
],
|
||||
)
|
||||
|
||||
@@ -122,7 +147,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_short_range_image.pbtxt",
|
||||
register_as = "FaceDetectionShortRangeImage",
|
||||
deps = [
|
||||
":face_detection_short_range_common",
|
||||
":face_detection_short_range",
|
||||
"//mediapipe/calculators/core:flow_limiter_calculator",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
@@ -134,7 +159,7 @@ mediapipe_simple_subgraph(
|
||||
graph = "face_detection_full_range_image.pbtxt",
|
||||
register_as = "FaceDetectionFullRangeImage",
|
||||
deps = [
|
||||
":face_detection_full_range_common",
|
||||
":face_detection_full_range",
|
||||
"//mediapipe/calculators/core:flow_limiter_calculator",
|
||||
"//mediapipe/calculators/tensor:image_to_tensor_calculator",
|
||||
"//mediapipe/calculators/tensor:inference_calculator",
|
||||
|
||||
@@ -0,0 +1,164 @@
|
||||
# MediaPipe graph to detect faces.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionFrontCpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# input_stream: "ROI:roi"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetection"
|
||||
|
||||
# The input image, either ImageFrame, GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# ROI (region of interest) within the given image where faces should be
|
||||
# detected. (NormalizedRect)
|
||||
input_stream: "ROI:roi"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Converts the input CPU or GPU image to the multi-backend image type (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
input_stream: "NORM_RECT:roi"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
}
|
||||
}
|
||||
option_value: "gpu_origin:options/gpu_origin"
|
||||
option_value: "output_tensor_width:options/tensor_width"
|
||||
option_value: "output_tensor_height:options/tensor_height"
|
||||
}
|
||||
|
||||
# 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {}
|
||||
}
|
||||
option_value: "delegate:options/delegate"
|
||||
option_value: "model_path:options/model_path"
|
||||
}
|
||||
|
||||
# Detection tensors. (std::vector<Tensor>)
|
||||
#input_stream: "TENSORS:detection_tensors"
|
||||
|
||||
# A 4x4 row-major-order matrix that maps a point represented in the detection
|
||||
# tensors to a desired coordinate system, e.g., in the original input image
|
||||
# before scaling/cropping. (std::array<float, 16>)
|
||||
#input_stream: "MATRIX:transform_matrix"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Generates a single side packet containing a vector of SSD anchors based on
|
||||
# the specification in the options.
|
||||
node {
|
||||
calculator: "SsdAnchorsCalculator"
|
||||
output_side_packet: "anchors"
|
||||
options: {
|
||||
[mediapipe.SsdAnchorsCalculatorOptions.ext] {
|
||||
num_layers: 1
|
||||
min_scale: 0.1484375
|
||||
max_scale: 0.75
|
||||
anchor_offset_x: 0.5
|
||||
anchor_offset_y: 0.5
|
||||
aspect_ratios: 1.0
|
||||
fixed_anchor_size: true
|
||||
}
|
||||
}
|
||||
option_value: "input_size_width:tensor_width"
|
||||
option_value: "input_size_height:tensor_height"
|
||||
option_value: "num_layers:num_layers"
|
||||
option_value: "strides:strides"
|
||||
option_value: "interpolated_scale_aspect_ratio:interpolated_scale_aspect_ratio"
|
||||
}
|
||||
|
||||
# Decodes the detection tensors generated by the TensorFlow Lite model, based on
|
||||
# the SSD anchors and the specification in the options, into a vector of
|
||||
# detections. Each detection describes a detected object.
|
||||
node {
|
||||
calculator: "TensorsToDetectionsCalculator"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_side_packet: "ANCHORS:anchors"
|
||||
output_stream: "DETECTIONS:unfiltered_detections"
|
||||
options: {
|
||||
[mediapipe.TensorsToDetectionsCalculatorOptions.ext] {
|
||||
num_classes: 1
|
||||
num_coords: 16
|
||||
box_coord_offset: 0
|
||||
keypoint_coord_offset: 4
|
||||
num_keypoints: 6
|
||||
num_values_per_keypoint: 2
|
||||
sigmoid_score: true
|
||||
score_clipping_thresh: 100.0
|
||||
reverse_output_order: true
|
||||
}
|
||||
}
|
||||
option_value: "num_boxes:num_boxes"
|
||||
option_value: "x_scale:x_scale"
|
||||
option_value: "y_scale:y_scale"
|
||||
option_value: "h_scale:h_scale"
|
||||
option_value: "w_scale:w_scale"
|
||||
option_value: "min_score_thresh:min_score_thresh"
|
||||
}
|
||||
|
||||
# Performs non-max suppression to remove excessive detections.
|
||||
node {
|
||||
calculator: "NonMaxSuppressionCalculator"
|
||||
input_stream: "unfiltered_detections"
|
||||
output_stream: "filtered_detections"
|
||||
options: {
|
||||
[mediapipe.NonMaxSuppressionCalculatorOptions.ext] {
|
||||
min_suppression_threshold: 0.3
|
||||
overlap_type: INTERSECTION_OVER_UNION
|
||||
algorithm: WEIGHTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Projects the detections from input tensor to the corresponding locations on
|
||||
# the original image (input to the graph).
|
||||
node {
|
||||
calculator: "DetectionProjectionCalculator"
|
||||
input_stream: "DETECTIONS:filtered_detections"
|
||||
input_stream: "PROJECTION_MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
// 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.
|
||||
|
||||
syntax = "proto2";
|
||||
|
||||
package mediapipe;
|
||||
|
||||
import "mediapipe/calculators/tensor/inference_calculator.proto";
|
||||
import "mediapipe/framework/calculator_options.proto";
|
||||
import "mediapipe/gpu/gpu_origin.proto";
|
||||
|
||||
option java_package = "com.google.mediapipe.modules.facedetection";
|
||||
option java_outer_classname = "FaceDetectionFrontProto";
|
||||
|
||||
// Defines the face geometry pipeline estimation result format.
|
||||
message FaceDetectionOptions {
|
||||
extend mediapipe.CalculatorOptions {
|
||||
optional FaceDetectionOptions ext = 374290926;
|
||||
}
|
||||
// Path to the TF Lite model (ex: /path/to/modelname.tflite).
|
||||
optional string model_path = 1;
|
||||
|
||||
// The coordinate origin corner, either CONVENTIONAL or TOP_LEFT.
|
||||
optional GpuOrigin.Mode gpu_origin = 11;
|
||||
|
||||
// Size of the tensor provided to the face-detection model.
|
||||
optional int32 tensor_width = 21;
|
||||
optional int32 tensor_height = 22;
|
||||
// Number of output feature maps to generate the anchors on.
|
||||
optional int32 num_layers = 23;
|
||||
// Strides of each output feature maps.
|
||||
repeated int32 strides = 24;
|
||||
// The aspect ratio of the interpolated anchor from the SsdAnchorsCalculator.
|
||||
optional float interpolated_scale_aspect_ratio = 25 [default = 1.0];
|
||||
|
||||
// The number of output boxes predicted by the detection model.
|
||||
optional int32 num_boxes = 31;
|
||||
// Parameters for decoding SSD detection model.
|
||||
optional float x_scale = 32 [default = 0.0];
|
||||
optional float y_scale = 33 [default = 0.0];
|
||||
optional float w_scale = 34 [default = 0.0];
|
||||
optional float h_scale = 35 [default = 0.0];
|
||||
// Score threshold for perserving from the SSD detections.
|
||||
optional float min_score_thresh = 36;
|
||||
|
||||
// TfLite delegate to run inference.
|
||||
optional InferenceCalculatorOptions.Delegate delegate = 6;
|
||||
}
|
||||
@@ -0,0 +1,54 @@
|
||||
# MediaPipe graph to detect faces. (CPU input and inference by default.)
|
||||
#
|
||||
# It is required that "face_detection_full_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_full_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRange"
|
||||
# input_stream: "IMAGE:image_frame"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetectionFullRange"
|
||||
|
||||
# The input image, either ImageFrame, GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# ROI (region of interest) within the given image where faces should be
|
||||
# detected. (NormalizedRect)
|
||||
input_stream: "ROI:roi"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
output_stream: "DETECTIONS:detections"
|
||||
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
node {
|
||||
calculator: "FaceDetection"
|
||||
input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
tensor_width: 192
|
||||
tensor_height: 192
|
||||
|
||||
num_layers: 1
|
||||
strides: 4
|
||||
interpolated_scale_aspect_ratio: 0.0
|
||||
|
||||
num_boxes: 2304
|
||||
x_scale: 192.0
|
||||
y_scale: 192.0
|
||||
h_scale: 192.0
|
||||
w_scale: 192.0
|
||||
min_score_thresh: 0.6
|
||||
}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
@@ -1,102 +0,0 @@
|
||||
# MediaPipe graph performing common processing to detect faces using
|
||||
# face_detection_full_range_sparse.tflite model, currently consisting of tensor
|
||||
# post processing.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionFullRangeCommon"
|
||||
# input_stream: "TENSORS:detection_tensors"
|
||||
# input_stream: "MATRIX:transform_matrix"
|
||||
# output_stream: "DETECTIONS:detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetectionShortRangeCommon"
|
||||
|
||||
# Detection tensors. (std::vector<Tensor>)
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
|
||||
# A 4x4 row-major-order matrix that maps a point represented in the detection
|
||||
# tensors to a desired coordinate system, e.g., in the original input image
|
||||
# before scaling/cropping. (std::array<float, 16>)
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Generates a single side packet containing a vector of SSD anchors based on
|
||||
# the specification in the options.
|
||||
node {
|
||||
calculator: "SsdAnchorsCalculator"
|
||||
output_side_packet: "anchors"
|
||||
options: {
|
||||
[mediapipe.SsdAnchorsCalculatorOptions.ext] {
|
||||
num_layers: 1
|
||||
min_scale: 0.1484375
|
||||
max_scale: 0.75
|
||||
input_size_height: 192
|
||||
input_size_width: 192
|
||||
anchor_offset_x: 0.5
|
||||
anchor_offset_y: 0.5
|
||||
strides: 4
|
||||
aspect_ratios: 1.0
|
||||
fixed_anchor_size: true
|
||||
interpolated_scale_aspect_ratio: 0.0
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Decodes the detection tensors generated by the TensorFlow Lite model, based on
|
||||
# the SSD anchors and the specification in the options, into a vector of
|
||||
# detections. Each detection describes a detected object.
|
||||
node {
|
||||
calculator: "TensorsToDetectionsCalculator"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_side_packet: "ANCHORS:anchors"
|
||||
output_stream: "DETECTIONS:unfiltered_detections"
|
||||
options: {
|
||||
[mediapipe.TensorsToDetectionsCalculatorOptions.ext] {
|
||||
num_classes: 1
|
||||
num_boxes: 2304
|
||||
num_coords: 16
|
||||
box_coord_offset: 0
|
||||
keypoint_coord_offset: 4
|
||||
num_keypoints: 6
|
||||
num_values_per_keypoint: 2
|
||||
sigmoid_score: true
|
||||
score_clipping_thresh: 100.0
|
||||
reverse_output_order: true
|
||||
x_scale: 192.0
|
||||
y_scale: 192.0
|
||||
h_scale: 192.0
|
||||
w_scale: 192.0
|
||||
min_score_thresh: 0.6
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs non-max suppression to remove excessive detections.
|
||||
node {
|
||||
calculator: "NonMaxSuppressionCalculator"
|
||||
input_stream: "unfiltered_detections"
|
||||
output_stream: "filtered_detections"
|
||||
options: {
|
||||
[mediapipe.NonMaxSuppressionCalculatorOptions.ext] {
|
||||
min_suppression_threshold: 0.3
|
||||
overlap_type: INTERSECTION_OVER_UNION
|
||||
algorithm: WEIGHTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Projects the detections from input tensor to the corresponding locations on
|
||||
# the original image (input to the graph).
|
||||
node {
|
||||
calculator: "DetectionProjectionCalculator"
|
||||
input_stream: "DETECTIONS:filtered_detections"
|
||||
input_stream: "PROJECTION_MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
}
|
||||
@@ -1,80 +1,25 @@
|
||||
# MediaPipe graph to detect faces. (CPU input, and inference is executed on
|
||||
# CPU.)
|
||||
#
|
||||
# It is required that "face_detection_full_range_sparse.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionFullRangeCpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (CPU input and inference.)
|
||||
|
||||
type: "FaceDetectionFullRangeCpu"
|
||||
|
||||
# CPU image. (ImageFrame)
|
||||
# The input image, either ImageFrame, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input CPU image (ImageFrame) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_CPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 192x192 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 192
|
||||
output_tensor_height: 192
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
delegate {
|
||||
xnnpack {}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionFullRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
calculator: "FaceDetectionFullRange"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
delegate { xnnpack {} }
|
||||
}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -1,80 +1,26 @@
|
||||
# MediaPipe graph to detect faces. (GPU input, and inference is executed on
|
||||
# GPU.)
|
||||
#
|
||||
# It is required that "face_detection_full_range_sparse.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionFullRangeGpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (GPU input and inference.)
|
||||
|
||||
type: "FaceDetectionFullRangeGpu"
|
||||
|
||||
# GPU image. (GpuBuffer)
|
||||
# The input image, either GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input GPU image (GpuBuffer) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_GPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 192
|
||||
output_tensor_height: 192
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
gpu_origin: TOP_LEFT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Runs a TensorFlow Lite model on GPU 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
#
|
||||
calculator: "FaceDetectionFullRange"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
gpu_origin: TOP_LEFT
|
||||
delegate: { gpu { use_advanced_gpu_api: true } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionFullRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -36,51 +36,12 @@ node {
|
||||
}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
node {
|
||||
calculator: "FaceDetectionFullRange"
|
||||
input_stream: "IMAGE:throttled_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 192
|
||||
output_tensor_height: 192
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
gpu_origin: CONVENTIONAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Runs a TensorFlow Lite model on GPU that takes an image tensor and outputs a
|
||||
# vector of tensors representing, for instance, detection boxes/keypoints and
|
||||
# scores.
|
||||
# TODO: Use GraphOptions to modify the delegate field to be
|
||||
# `delegate { xnnpack {} }` for the CPU only use cases.
|
||||
node {
|
||||
calculator: "InferenceCalculator"
|
||||
input_stream: "TENSORS:input_tensors"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_full_range_sparse.tflite"
|
||||
#
|
||||
delegate: { gpu { use_advanced_gpu_api: true } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionFullRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
# MediaPipe graph to detect faces. (CPU input and inference by default.)
|
||||
#
|
||||
# It is required that "face_detection_short_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRange"
|
||||
# input_stream: "IMAGE:image_frame"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetectionShortRange"
|
||||
|
||||
# The input image, either ImageFrame, GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# ROI (region of interest) within the given image where faces should be
|
||||
# detected. (NormalizedRect)
|
||||
input_stream: "ROI:roi"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
output_stream: "DETECTIONS:detections"
|
||||
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
node {
|
||||
calculator: "FaceDetection"
|
||||
input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
tensor_width: 128
|
||||
tensor_height: 128
|
||||
|
||||
num_layers: 4
|
||||
strides: 8
|
||||
strides: 16
|
||||
strides: 16
|
||||
strides: 16
|
||||
interpolated_scale_aspect_ratio: 1.0
|
||||
|
||||
num_boxes: 896
|
||||
x_scale: 128.0
|
||||
y_scale: 128.0
|
||||
h_scale: 128.0
|
||||
w_scale: 128.0
|
||||
min_score_thresh: 0.5
|
||||
}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
@@ -1,21 +1,8 @@
|
||||
# MediaPipe graph to detect faces. (CPU input, and inference is executed on
|
||||
# CPU.)
|
||||
#
|
||||
# It is required that "face_detection_short_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRangeByRoiCpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# input_stream: "ROI:roi"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (CPU input and inference, with region-of-interest.)
|
||||
|
||||
type: "FaceDetectionShortRangeByRoiCpu"
|
||||
type: "FaceDetectionShortRangeCpu"
|
||||
|
||||
# CPU image. (ImageFrame)
|
||||
# The input image, either ImageFrame, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# ROI (region of interest) within the given image where faces should be
|
||||
@@ -23,61 +10,21 @@ input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input CPU image (ImageFrame) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_CPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms specified region of image into 128x128 tensor keeping aspect ratio
|
||||
# (padding tensor if needed).
|
||||
node {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
input_stream: "NORM_RECT:roi"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 128
|
||||
output_tensor_height: 128
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
calculator: "FaceDetectionShortRange"
|
||||
input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
delegate { xnnpack {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionShortRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -1,21 +1,8 @@
|
||||
# MediaPipe graph to detect faces. (GPU input, and inference is executed on
|
||||
# GPU.)
|
||||
#
|
||||
# It is required that "face_detection_short_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRangeByRoiGpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# input_stream: "ROI:roi"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (GPU input and inference, with region-of-interest.)
|
||||
|
||||
type: "FaceDetectionShortRangeByRoiGpu"
|
||||
type: "FaceDetectionShortRangeGpu"
|
||||
|
||||
# GPU image. (GpuBuffer)
|
||||
# The input image, either ImageFrame, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# ROI (region of interest) within the given image where faces should be
|
||||
@@ -23,61 +10,22 @@ input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input GPU image (GpuBuffer) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_GPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms specified region of image into 128x128 tensor keeping aspect ratio
|
||||
# (padding tensor if needed).
|
||||
node {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
input_stream: "NORM_RECT:roi"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 128
|
||||
output_tensor_height: 128
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
gpu_origin: TOP_LEFT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Runs a TensorFlow Lite model on GPU 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionShortRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
calculator: "FaceDetectionShortRange"
|
||||
input_stream: "IMAGE:image"
|
||||
input_stream: "ROI:roi"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
gpu_origin: TOP_LEFT
|
||||
delegate: { gpu { use_advanced_gpu_api: true } }
|
||||
}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -1,103 +0,0 @@
|
||||
# MediaPipe graph performing common processing to detect faces, currently
|
||||
# consisting of tensor post processing.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRangeCommon"
|
||||
# input_stream: "TENSORS:detection_tensors"
|
||||
# input_stream: "MATRIX:transform_matrix"
|
||||
# output_stream: "DETECTIONS:detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetectionShortRangeCommon"
|
||||
|
||||
# Detection tensors. (std::vector<Tensor>)
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
|
||||
# A 4x4 row-major-order matrix that maps a point represented in the detection
|
||||
# tensors to a desired coordinate system, e.g., in the original input image
|
||||
# before scaling/cropping. (std::array<float, 16>)
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Generates a single side packet containing a vector of SSD anchors based on
|
||||
# the specification in the options.
|
||||
node {
|
||||
calculator: "SsdAnchorsCalculator"
|
||||
output_side_packet: "anchors"
|
||||
options: {
|
||||
[mediapipe.SsdAnchorsCalculatorOptions.ext] {
|
||||
num_layers: 4
|
||||
min_scale: 0.1484375
|
||||
max_scale: 0.75
|
||||
input_size_height: 128
|
||||
input_size_width: 128
|
||||
anchor_offset_x: 0.5
|
||||
anchor_offset_y: 0.5
|
||||
strides: 8
|
||||
strides: 16
|
||||
strides: 16
|
||||
strides: 16
|
||||
aspect_ratios: 1.0
|
||||
fixed_anchor_size: true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Decodes the detection tensors generated by the TensorFlow Lite model, based on
|
||||
# the SSD anchors and the specification in the options, into a vector of
|
||||
# detections. Each detection describes a detected object.
|
||||
node {
|
||||
calculator: "TensorsToDetectionsCalculator"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_side_packet: "ANCHORS:anchors"
|
||||
output_stream: "DETECTIONS:unfiltered_detections"
|
||||
options: {
|
||||
[mediapipe.TensorsToDetectionsCalculatorOptions.ext] {
|
||||
num_classes: 1
|
||||
num_boxes: 896
|
||||
num_coords: 16
|
||||
box_coord_offset: 0
|
||||
keypoint_coord_offset: 4
|
||||
num_keypoints: 6
|
||||
num_values_per_keypoint: 2
|
||||
sigmoid_score: true
|
||||
score_clipping_thresh: 100.0
|
||||
reverse_output_order: true
|
||||
x_scale: 128.0
|
||||
y_scale: 128.0
|
||||
h_scale: 128.0
|
||||
w_scale: 128.0
|
||||
min_score_thresh: 0.5
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs non-max suppression to remove excessive detections.
|
||||
node {
|
||||
calculator: "NonMaxSuppressionCalculator"
|
||||
input_stream: "unfiltered_detections"
|
||||
output_stream: "filtered_detections"
|
||||
options: {
|
||||
[mediapipe.NonMaxSuppressionCalculatorOptions.ext] {
|
||||
min_suppression_threshold: 0.3
|
||||
overlap_type: INTERSECTION_OVER_UNION
|
||||
algorithm: WEIGHTED
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Projects the detections from input tensor to the corresponding locations on
|
||||
# the original image (input to the graph).
|
||||
node {
|
||||
calculator: "DetectionProjectionCalculator"
|
||||
input_stream: "DETECTIONS:filtered_detections"
|
||||
input_stream: "PROJECTION_MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
}
|
||||
@@ -1,78 +1,25 @@
|
||||
# MediaPipe graph to detect faces. (CPU input, and inference is executed on
|
||||
# CPU.)
|
||||
#
|
||||
# It is required that "face_detection_short_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRangeCpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (CPU input and inference.)
|
||||
|
||||
type: "FaceDetectionShortRangeCpu"
|
||||
|
||||
# CPU image. (ImageFrame)
|
||||
# The input image, either ImageFrame, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input CPU image (ImageFrame) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_CPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 128
|
||||
output_tensor_height: 128
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
calculator: "FaceDetectionShortRange"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
delegate { xnnpack {} }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionShortRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -1,78 +1,26 @@
|
||||
# MediaPipe graph to detect faces. (GPU input, and inference is executed on
|
||||
# GPU.)
|
||||
#
|
||||
# It is required that "face_detection_short_range.tflite" is available at
|
||||
# "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
# path during execution.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionShortRangeGpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
# MediaPipe graph to detect faces. (GPU input and inference.)
|
||||
|
||||
type: "FaceDetectionShortRangeGpu"
|
||||
|
||||
# GPU image. (GpuBuffer)
|
||||
# The input image, either GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
# NOTE: there will not be an output packet in the DETECTIONS stream for this
|
||||
# particular timestamp if none of faces detected. 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: "DETECTIONS:detections"
|
||||
|
||||
# Converts the input GPU image (GpuBuffer) to the multi-backend image type
|
||||
# (Image).
|
||||
node: {
|
||||
calculator: "ToImageCalculator"
|
||||
input_stream: "IMAGE_GPU:image"
|
||||
output_stream: "IMAGE:multi_backend_image"
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
input_stream: "IMAGE:multi_backend_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 128
|
||||
output_tensor_height: 128
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
gpu_origin: TOP_LEFT
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Runs a TensorFlow Lite model on GPU 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"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionShortRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
calculator: "FaceDetectionShortRange"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {
|
||||
gpu_origin: TOP_LEFT
|
||||
delegate: { gpu { use_advanced_gpu_api: true } }
|
||||
}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -43,52 +43,12 @@ node {
|
||||
}
|
||||
}
|
||||
|
||||
# Transforms the input image into a 128x128 tensor while keeping the aspect
|
||||
# ratio (what is expected by the corresponding face detection model), resulting
|
||||
# in potential letterboxing in the transformed image.
|
||||
node: {
|
||||
calculator: "ImageToTensorCalculator"
|
||||
node {
|
||||
calculator: "FaceDetectionShortRange"
|
||||
input_stream: "IMAGE:throttled_image"
|
||||
output_stream: "TENSORS:input_tensors"
|
||||
output_stream: "MATRIX:transform_matrix"
|
||||
options: {
|
||||
[mediapipe.ImageToTensorCalculatorOptions.ext] {
|
||||
output_tensor_width: 128
|
||||
output_tensor_height: 128
|
||||
keep_aspect_ratio: true
|
||||
output_tensor_float_range {
|
||||
min: -1.0
|
||||
max: 1.0
|
||||
}
|
||||
border_mode: BORDER_ZERO
|
||||
gpu_origin: CONVENTIONAL
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Runs a TensorFlow Lite model on GPU that takes an image tensor and outputs a
|
||||
# vector of tensors representing, for instance, detection boxes/keypoints and
|
||||
# scores.
|
||||
# TODO: Use GraphOptions to modify the delegate field to be
|
||||
# `delegate { xnnpack {} }` for the CPU only use cases.
|
||||
node {
|
||||
calculator: "InferenceCalculator"
|
||||
input_stream: "TENSORS:input_tensors"
|
||||
output_stream: "TENSORS:detection_tensors"
|
||||
options: {
|
||||
[mediapipe.InferenceCalculatorOptions.ext] {
|
||||
model_path: "mediapipe/modules/face_detection/face_detection_short_range.tflite"
|
||||
|
||||
#
|
||||
delegate: { gpu { use_advanced_gpu_api: true } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Performs tensor post processing to generate face detections.
|
||||
node {
|
||||
calculator: "FaceDetectionShortRangeCommon"
|
||||
input_stream: "TENSORS:detection_tensors"
|
||||
input_stream: "MATRIX:transform_matrix"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
|
||||
@@ -0,0 +1,384 @@
|
||||
// Copyright 2019 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.
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include "mediapipe/calculators/tensor/image_to_tensor_calculator.pb.h"
|
||||
#include "mediapipe/calculators/tensor/inference_calculator.pb.h"
|
||||
#include "mediapipe/calculators/tensor/tensors_to_detections_calculator.pb.h"
|
||||
#include "mediapipe/calculators/tflite/ssd_anchors_calculator.pb.h"
|
||||
#include "mediapipe/calculators/util/non_max_suppression_calculator.pb.h"
|
||||
#include "mediapipe/framework/calculator_framework.h"
|
||||
#include "mediapipe/framework/formats/detection.pb.h"
|
||||
#include "mediapipe/framework/formats/rect.pb.h"
|
||||
#include "mediapipe/framework/port/file_helpers.h"
|
||||
#include "mediapipe/framework/port/gtest.h"
|
||||
#include "mediapipe/framework/port/parse_text_proto.h"
|
||||
#include "mediapipe/framework/port/status_matchers.h"
|
||||
#include "mediapipe/framework/tool/options_util.h"
|
||||
#include "mediapipe/framework/tool/test_util.h"
|
||||
#include "mediapipe/gpu/gpu_origin.pb.h"
|
||||
#include "mediapipe/modules/face_detection/face_detection.pb.h"
|
||||
|
||||
#if !defined(__APPLE__) && !__ANDROID__
|
||||
#include "mediapipe/gpu/gl_app_texture_support.h"
|
||||
#include "mediapipe/gpu/gl_calculator_helper.h"
|
||||
#include "mediapipe/gpu/gpu_test_base.h"
|
||||
#endif // !defined(__APPLE__) && !__ANDROID__
|
||||
|
||||
namespace mediapipe {
|
||||
namespace {
|
||||
using mediapipe::FaceDetectionOptions;
|
||||
|
||||
// Ensure protobuf registration.
|
||||
void RegisterProtobufTypes() {
|
||||
MakePacket<mediapipe::InferenceCalculatorOptions::Delegate>();
|
||||
MakePacket<mediapipe::FaceDetectionOptions>();
|
||||
MakePacket<mediapipe::InferenceCalculatorOptions>();
|
||||
|
||||
MakePacket<mediapipe::ImageToTensorCalculatorOptions>();
|
||||
MakePacket<mediapipe::SsdAnchorsCalculatorOptions>();
|
||||
MakePacket<mediapipe::TensorsToDetectionsCalculatorOptions>();
|
||||
MakePacket<mediapipe::NonMaxSuppressionCalculatorOptions>();
|
||||
}
|
||||
|
||||
// Returns a Packet with an ImageFrame showing a face.
|
||||
Packet TestImageFrame() {
|
||||
std::unique_ptr<ImageFrame> input_image = LoadTestPng(
|
||||
file::JoinPath(GetTestRootDir(), "mediapipe/objc/testdata/sergey.png"));
|
||||
EXPECT_EQ(input_image->Height(), 600);
|
||||
return MakePacket<ImageFrame>(std::move(*input_image));
|
||||
}
|
||||
|
||||
// Returns the registered type name for the basic face-detection-graph.
|
||||
std::string GetFaceDetectionGraphType() { return "FaceDetectionWithoutRoi"; }
|
||||
|
||||
// Returns the config from "face_detection_without_roi.pbtxt".
|
||||
CalculatorGraphConfig GetFaceDetectionGraph() {
|
||||
return GraphRegistry().CreateByName("", GetFaceDetectionGraphType()).value();
|
||||
}
|
||||
|
||||
// Returns the config from "face_detection.pbtxt".
|
||||
CalculatorGraphConfig GetFaceDetectionWithRoiGraph() {
|
||||
return GraphRegistry().CreateByName("", "FaceDetection").value();
|
||||
}
|
||||
|
||||
// Returns the config from "face_detection_short_range.pbtxt".
|
||||
CalculatorGraphConfig GetFaceDetectionShortRangeCpu() {
|
||||
CalculatorGraphConfig config =
|
||||
GraphRegistry().CreateByName("", "FaceDetectionShortRangeCpu").value();
|
||||
return config;
|
||||
}
|
||||
|
||||
// Returns the FaceDetectionOptions from "face_detection_short_range_cpu.pbtxt".
|
||||
FaceDetectionOptions GetFaceDetectionShortRangeOptions() {
|
||||
CalculatorGraphConfig config;
|
||||
LoadTestGraph(&config,
|
||||
GetTestFilePath("mediapipe/modules/face_detection/"
|
||||
"face_detection_short_range.binarypb"));
|
||||
tool::OptionsMap map;
|
||||
map.Initialize(config.node(0));
|
||||
return map.Get<FaceDetectionOptions>();
|
||||
}
|
||||
|
||||
// Returns the FaceDetectionOptions from "face_detection_full_range_cpu.pbtxt".
|
||||
FaceDetectionOptions GetFaceDetectionFullRangeOptions() {
|
||||
CalculatorGraphConfig config;
|
||||
LoadTestGraph(&config, GetTestFilePath("mediapipe/modules/face_detection/"
|
||||
"face_detection_full_range.binarypb"));
|
||||
tool::OptionsMap map;
|
||||
map.Initialize(config.node(0));
|
||||
return map.Get<FaceDetectionOptions>();
|
||||
}
|
||||
|
||||
// Returns the FaceDetectionOptions needed to enable CPU processing.
|
||||
FaceDetectionOptions GetCpuOptions() {
|
||||
FaceDetectionOptions result;
|
||||
result.mutable_delegate()->xnnpack();
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns the FaceDetectionOptions needed to enable GPU processing.
|
||||
FaceDetectionOptions GetGpuOptions() {
|
||||
FaceDetectionOptions result;
|
||||
result.set_gpu_origin(mediapipe::GpuOrigin_Mode::GpuOrigin_Mode_TOP_LEFT);
|
||||
result.mutable_delegate()->mutable_gpu()->set_use_advanced_gpu_api(true);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Returns an example region of interest rectangle.
|
||||
mediapipe::NormalizedRect GetTestRoi() {
|
||||
mediapipe::NormalizedRect result;
|
||||
result.set_x_center(0.5);
|
||||
result.set_y_center(0.5);
|
||||
result.set_width(0.8);
|
||||
result.set_height(0.8);
|
||||
return result;
|
||||
}
|
||||
|
||||
// Tests for options input and output packets and streams.
|
||||
class FaceDetectionTest : public ::testing::Test {
|
||||
protected:
|
||||
void SetUp() override { RegisterProtobufTypes(); }
|
||||
void TearDown() override {}
|
||||
};
|
||||
|
||||
TEST_F(FaceDetectionTest, ExpandFaceDetectionShortRangeCpu) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionShortRangeCpu();
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize(config));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionTest, ExpandFaceDetection) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionShortRangeOptions();
|
||||
face_options.MergeFrom(GetCpuOptions());
|
||||
config.clear_graph_options();
|
||||
config.add_graph_options()->PackFrom(face_options);
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize(config));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionTest, FaceDetectionShortRangeApi) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionShortRangeOptions();
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
face_options.MergeFrom(GetCpuOptions());
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize({config}, {}, {}, GetFaceDetectionGraphType(),
|
||||
&graph_options));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionTest, FaceDetectionWrapperApi) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionShortRangeOptions();
|
||||
face_options.MergeFrom(GetCpuOptions());
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize({config}, {}, {}, GetFaceDetectionGraphType(),
|
||||
&graph_options));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionTest, FaceDetectionFullRangeApi) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionFullRangeOptions();
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
face_options.MergeFrom(GetCpuOptions());
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize({config}, {}, {}, GetFaceDetectionGraphType(),
|
||||
&graph_options));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionTest, FaceDetectionShortRangeByRoiCpu) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionWithRoiGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionShortRangeOptions();
|
||||
face_options.MergeFrom(GetCpuOptions());
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = TestImageFrame();
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(
|
||||
graph.Initialize({config}, {}, {}, "FaceDetection", &graph_options));
|
||||
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.AddPacketToInputStream(
|
||||
"roi", MakePacket<mediapipe::NormalizedRect>(GetTestRoi())
|
||||
.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
// These GpuBuffer tests are disabled on mobile for now.
|
||||
#if !defined(__APPLE__) && !__ANDROID__
|
||||
|
||||
class FaceDetectionGpuTest : public mediapipe::GpuTestBase {
|
||||
protected:
|
||||
void SetUp() override {}
|
||||
void TearDown() override {}
|
||||
|
||||
// Returns a Packet with a GpuBuffer from an ImageFrame.
|
||||
Packet GpuBuffer(Packet image_frame) {
|
||||
std::unique_ptr<mediapipe::GpuBuffer> gpu_buffer;
|
||||
helper_.RunInGlContext([this, &image_frame, &gpu_buffer] {
|
||||
auto src = helper_.CreateSourceTexture(image_frame.Get<ImageFrame>());
|
||||
gpu_buffer = src.GetFrame<mediapipe::GpuBuffer>();
|
||||
});
|
||||
return Adopt(gpu_buffer.release());
|
||||
}
|
||||
};
|
||||
|
||||
TEST_F(FaceDetectionGpuTest, FaceDetectionFullRangeGpu) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionFullRangeOptions();
|
||||
face_options.MergeFrom(GetGpuOptions());
|
||||
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = GpuBuffer(TestImageFrame());
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize({config}, {}, {}, GetFaceDetectionGraphType(),
|
||||
&graph_options));
|
||||
|
||||
MP_ASSERT_OK(mediapipe::SetExternalGlContextForGraph(
|
||||
&graph, helper_.GetGlContext().native_context()));
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
TEST_F(FaceDetectionGpuTest, FaceDetectionShortRangeGpu) {
|
||||
CalculatorGraphConfig config = GetFaceDetectionGraph();
|
||||
config.clear_graph_options();
|
||||
mediapipe::FaceDetectionOptions face_options =
|
||||
GetFaceDetectionShortRangeOptions();
|
||||
face_options.MergeFrom(GetGpuOptions());
|
||||
|
||||
Subgraph::SubgraphOptions graph_options;
|
||||
graph_options.add_node_options()->PackFrom(face_options);
|
||||
Packet frame1 = GpuBuffer(TestImageFrame());
|
||||
|
||||
CalculatorGraph graph;
|
||||
MP_ASSERT_OK(graph.Initialize({config}, {}, {}, GetFaceDetectionGraphType(),
|
||||
&graph_options));
|
||||
|
||||
MP_ASSERT_OK(mediapipe::SetExternalGlContextForGraph(
|
||||
&graph, helper_.GetGlContext().native_context()));
|
||||
std::vector<Packet> output;
|
||||
MP_ASSERT_OK(graph.ObserveOutputStream("detections", [&](const Packet& p) {
|
||||
output.push_back(p);
|
||||
return absl::OkStatus();
|
||||
}));
|
||||
MP_ASSERT_OK(graph.StartRun({}));
|
||||
MP_ASSERT_OK(
|
||||
graph.AddPacketToInputStream("image", frame1.At(Timestamp(20000))));
|
||||
MP_ASSERT_OK(graph.CloseAllPacketSources());
|
||||
MP_EXPECT_OK(graph.WaitUntilDone());
|
||||
ASSERT_EQ(output.size(), 1);
|
||||
EXPECT_EQ(output.front().Get<std::vector<mediapipe::Detection>>().size(), 1);
|
||||
}
|
||||
|
||||
#endif // #if !defined(__APPLE__) && !__ANDROID__
|
||||
|
||||
} // namespace
|
||||
} // namespace mediapipe
|
||||
@@ -0,0 +1,35 @@
|
||||
# MediaPipe graph to detect faces.
|
||||
# This graph omits the "ROI" input stream of the FaceDetection graph.
|
||||
# For now top level graph input streams can only be ommitted using an
|
||||
# enclosing graph, see b/202896911.
|
||||
# TODO: Remove this graph after b/202896911 is addressed.
|
||||
#
|
||||
# EXAMPLE:
|
||||
# node {
|
||||
# calculator: "FaceDetectionFrontCpu"
|
||||
# input_stream: "IMAGE:image"
|
||||
# output_stream: "DETECTIONS:face_detections"
|
||||
# }
|
||||
|
||||
type: "FaceDetectionWithoutRoi"
|
||||
|
||||
# The input image, either ImageFrame, GpuBuffer, or (multi-backend) Image.
|
||||
input_stream: "IMAGE:image"
|
||||
|
||||
# Detected faces. (std::vector<Detection>)
|
||||
output_stream: "DETECTIONS:detections"
|
||||
|
||||
# The face detection graph options.
|
||||
graph_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
|
||||
node {
|
||||
calculator: "FaceDetection"
|
||||
input_stream: "IMAGE:image"
|
||||
output_stream: "DETECTIONS:detections"
|
||||
node_options: {
|
||||
[type.googleapis.com/mediapipe.FaceDetectionOptions] {}
|
||||
}
|
||||
option_value: "OPTIONS:options"
|
||||
}
|
||||
Reference in New Issue
Block a user