From 3b58752e860b6bf1055bdbe88911b715bccf340e Mon Sep 17 00:00:00 2001 From: homuler Date: Mon, 23 Nov 2020 13:15:00 +0900 Subject: [PATCH] feat: upgrade MediaPipe(0.8.0) --- .../CPU/MultiHandTrackingGraphCPU.prefab | 76 --------- .../CPU/MultiHandTrackingGraphCPU.prefab.meta | 7 - .../Objects/Graph/GPU/FaceMeshGraphGPU.prefab | 5 +- .../Graph/GPU/HandTrackingGraphGPU.prefab | 10 +- .../GPU/MultiHandTrackingGraphGPU.prefab | 65 ------- .../GPU/MultiHandTrackingGraphGPU.prefab.meta | 7 - .../Resources/face_detection_desktop_live.txt | 161 +++--------------- .../Resources/face_detection_mobile_gpu.txt | 161 +++--------------- .../Resources/face_mesh_desktop_live.txt | 26 +-- ...ktop_live_gpu.txt => face_mesh_mobile.txt} | 29 ++-- ...gpu.txt.meta => face_mesh_mobile.txt.meta} | 2 +- .../Resources/hand_tracking_desktop_live.txt | 97 +++-------- .../Resources/hand_tracking_mobile.txt | 104 +++-------- .../multi_hand_tracking_desktop_live.txt | 126 -------------- .../multi_hand_tracking_desktop_live.txt.meta | 7 - .../Resources/multi_hand_tracking_mobile.txt | 134 --------------- .../multi_hand_tracking_mobile.txt.meta | 7 - .../FaceDetection/FaceDetectionGraph.cs | 32 ++-- .../Scripts/FaceMesh/FaceMeshGraph.cs | 3 + .../Scripts/GraphSelectorController.cs | 2 - .../HandTrackingAnnotationController.cs | 34 ++-- .../Scripts/HandTracking/HandTrackingGraph.cs | 79 +++++---- .../Scripts/HandTracking/HandTrackingValue.cs | 18 +- .../MultiHandTrackingAnnotationController.cs | 39 ----- .../HandTracking/MultiHandTrackingGraph.cs | 82 --------- .../MultiHandTrackingGraph.cs.meta | 11 -- .../HandTracking/MultiHandTrackingValue.cs | 16 -- .../MultiHandTrackingValue.cs.meta | 11 -- Assets/MediaPipe/SDK/Scripts/Format.cs | 4 +- .../Scripts/Framework/Formats/ImageFrame.cs | 2 +- .../Packet/ClassificationListVectorPacket.cs | 22 +++ .../ClassificationListVectorPacket.cs.meta} | 2 +- .../NativeMethods/External/Protobuf_Unsafe.cs | 3 + C/WORKSPACE | 26 +-- C/mediapipe_api/BUILD | 22 +-- .../framework/formats/classification.cc | 4 + .../framework/formats/classification.h | 1 + .../com/google/mediapipe/mediapipe_aar.bzl | 3 +- C/third_party/BUILD | 11 +- 39 files changed, 288 insertions(+), 1163 deletions(-) delete mode 100644 Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab delete mode 100644 Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab.meta delete mode 100644 Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab delete mode 100644 Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab.meta rename Assets/MediaPipe/Examples/Resources/{face_mesh_desktop_live_gpu.txt => face_mesh_mobile.txt} (65%) rename Assets/MediaPipe/Examples/Resources/{face_mesh_desktop_live_gpu.txt.meta => face_mesh_mobile.txt.meta} (75%) delete mode 100644 Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt delete mode 100644 Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt.meta delete mode 100644 Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt delete mode 100644 Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt.meta delete mode 100644 Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs delete mode 100644 Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs delete mode 100644 Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs.meta delete mode 100644 Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs delete mode 100644 Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs.meta create mode 100644 Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs rename Assets/MediaPipe/{Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs.meta => SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs.meta} (83%) diff --git a/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab b/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab deleted file mode 100644 index 5a2af368d..000000000 --- a/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab +++ /dev/null @@ -1,76 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1001 &8515798618609444619 -PrefabInstance: - m_ObjectHideFlags: 0 - serializedVersion: 2 - m_Modification: - m_TransformParent: {fileID: 0} - m_Modifications: - - target: {fileID: 2049382192924603272, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: config - value: - objectReference: {fileID: 4900000, guid: 00e4ddf383767ad25b6776ca868b595b, type: 3} - - target: {fileID: 2049382192924603273, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_Name - value: MultiHandTrackingGraph Variant - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalPosition.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalPosition.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalPosition.z - value: -10 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalRotation.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalRotation.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalRotation.z - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalRotation.w - value: 1 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_RootOrder - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalEulerAnglesHint.x - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalEulerAnglesHint.y - value: 0 - objectReference: {fileID: 0} - - target: {fileID: 2049382192924603275, guid: 0de25789197f23cdea7e3edb16daf326, - type: 3} - propertyPath: m_LocalEulerAnglesHint.z - value: 0 - objectReference: {fileID: 0} - m_RemovedComponents: [] - m_SourcePrefab: {fileID: 100100000, guid: 0de25789197f23cdea7e3edb16daf326, type: 3} diff --git a/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab.meta b/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab.meta deleted file mode 100644 index f324aca63..000000000 --- a/Assets/MediaPipe/Examples/Objects/Graph/CPU/MultiHandTrackingGraphCPU.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 50d43cff30debe51781e5c6df83865be -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Objects/Graph/GPU/FaceMeshGraphGPU.prefab b/Assets/MediaPipe/Examples/Objects/Graph/GPU/FaceMeshGraphGPU.prefab index 1dfa2c2b1..141a2cf0c 100644 --- a/Assets/MediaPipe/Examples/Objects/Graph/GPU/FaceMeshGraphGPU.prefab +++ b/Assets/MediaPipe/Examples/Objects/Graph/GPU/FaceMeshGraphGPU.prefab @@ -12,7 +12,7 @@ GameObject: - component: {fileID: 7004806987071314288} - component: {fileID: 7004806987071314290} m_Layer: 0 - m_Name: FaceMeshGraph + m_Name: FaceMeshGraphGPU m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -44,7 +44,8 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: 860c2553189c962f597b1b7dc1ee4c82, type: 3} m_Name: m_EditorClassIdentifier: - config: {fileID: 4900000, guid: 83097db0ae996a3ae8b65ad6b8db6444, type: 3} + config: {fileID: 4900000, guid: daf329e7d9e05b86e87226eba2dd3f32, type: 3} + numFaces: 3 --- !u!114 &7004806987071314290 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/MediaPipe/Examples/Objects/Graph/GPU/HandTrackingGraphGPU.prefab b/Assets/MediaPipe/Examples/Objects/Graph/GPU/HandTrackingGraphGPU.prefab index 27ce70949..f263c5323 100644 --- a/Assets/MediaPipe/Examples/Objects/Graph/GPU/HandTrackingGraphGPU.prefab +++ b/Assets/MediaPipe/Examples/Objects/Graph/GPU/HandTrackingGraphGPU.prefab @@ -12,7 +12,7 @@ GameObject: - component: {fileID: 6942115883526269424} - component: {fileID: 8479715968756539202} m_Layer: 0 - m_Name: MediapipeGraph + m_Name: HandTrackingGraphGPU m_TagString: Untagged m_Icon: {fileID: 0} m_NavMeshLayer: 0 @@ -57,11 +57,9 @@ MonoBehaviour: m_Script: {fileID: 11500000, guid: d8082593da04f2420974527dc1b29c06, type: 3} m_Name: m_EditorClassIdentifier: - handednessPrefab: {fileID: 5340126888248019913, guid: 3144fd50b7773ed768c77b259a74dbe6, + handLandmarkListsPrefab: {fileID: 2737917561592217227, guid: 2aac8e2b0b4f821fbbccc5cebab7bceb, type: 3} - handLandmarkListPrefab: {fileID: 3100741085041498678, guid: 4eb3a6d7cfea73afdb656b7166ae1a8d, + palmRectsPrefab: {fileID: 3702375667864819085, guid: 38f44807158015f02bddcfcc8dfe65b7, type: 3} - handRectPrefab: {fileID: 1405412484651109527, guid: c5c846cc7bbefdfa7af64f9d29912b70, - type: 3} - palmDetectionsPrefab: {fileID: 6957250898008990224, guid: 8d335567a8544a10e98a42b234b64b13, + palmDetectionsPrefab: {fileID: 5670327508126957478, guid: 324d403c9690c972abca928f3e614afc, type: 3} diff --git a/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab b/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab deleted file mode 100644 index fa3c91ccb..000000000 --- a/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab +++ /dev/null @@ -1,65 +0,0 @@ -%YAML 1.1 -%TAG !u! tag:unity3d.com,2011: ---- !u!1 &2049382192924603273 -GameObject: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - serializedVersion: 6 - m_Component: - - component: {fileID: 2049382192924603275} - - component: {fileID: 2049382192924603272} - - component: {fileID: 2049382192924603274} - m_Layer: 0 - m_Name: MediapipeGraph - m_TagString: Untagged - m_Icon: {fileID: 0} - m_NavMeshLayer: 0 - m_StaticEditorFlags: 0 - m_IsActive: 1 ---- !u!4 &2049382192924603275 -Transform: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2049382192924603273} - m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} - m_LocalPosition: {x: 0, y: 0, z: -10} - m_LocalScale: {x: 1, y: 1, z: 1} - m_Children: [] - m_Father: {fileID: 0} - m_RootOrder: 0 - m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} ---- !u!114 &2049382192924603272 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2049382192924603273} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: bf727f801974b69dd9593f712166a50b, type: 3} - m_Name: - m_EditorClassIdentifier: - config: {fileID: 4900000, guid: 79a190956c8b3545e806abe3d39dbf76, type: 3} ---- !u!114 &2049382192924603274 -MonoBehaviour: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 2049382192924603273} - m_Enabled: 1 - m_EditorHideFlags: 0 - m_Script: {fileID: 11500000, guid: 52378be1b2ebb49b294c6e5d2fcf0a25, type: 3} - m_Name: - m_EditorClassIdentifier: - handLandmarkListsPrefab: {fileID: 2737917561592217227, guid: 2aac8e2b0b4f821fbbccc5cebab7bceb, - type: 3} - palmDetectionsPrefab: {fileID: 5670327508126957478, guid: 324d403c9690c972abca928f3e614afc, - type: 3} - palmRectsPrefab: {fileID: 3702375667864819085, guid: 38f44807158015f02bddcfcc8dfe65b7, - type: 3} diff --git a/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab.meta b/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab.meta deleted file mode 100644 index 3a7391520..000000000 --- a/Assets/MediaPipe/Examples/Objects/Graph/GPU/MultiHandTrackingGraphGPU.prefab.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 0de25789197f23cdea7e3edb16daf326 -PrefabImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Resources/face_detection_desktop_live.txt b/Assets/MediaPipe/Examples/Resources/face_detection_desktop_live.txt index 8e12ea61e..d3d6e995d 100644 --- a/Assets/MediaPipe/Examples/Resources/face_detection_desktop_live.txt +++ b/Assets/MediaPipe/Examples/Resources/face_detection_desktop_live.txt @@ -12,26 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. +# CPU buffer. (ImageFrame) input_stream: "input_video" -output_stream: "output_detections" + +# Detected faces. (std::vector) +output_stream: "face_detections" +output_stream: "face_detections_presence" # Throttles the images flowing downstream for flow control. It passes through -# the very first incoming image unaltered, and waits for -# TfLiteTensorsToDetectionsCalculator downstream in the graph to finish -# generating the corresponding detections before it passes through another -# image. All images that come in while waiting are dropped, limiting the number -# of in-flight images between this calculator and -# TfLiteTensorsToDetectionsCalculator to 1. This prevents the nodes in between -# from queuing up incoming images and data excessively, which leads to increased -# latency and memory usage, unwanted in real-time mobile applications. It also -# eliminates unnecessarily computation, e.g., a transformed image produced by -# ImageTransformationCalculator may get dropped downstream if the subsequent -# TfLiteConverterCalculator or TfLiteInferenceCalculator is still busy -# processing previous inputs. +# the very first incoming image unaltered, and waits for downstream nodes +# (calculators and subgraphs) in the graph to finish their tasks before it +# passes through another image. All images that come in while waiting are +# dropped, limiting the number of in-flight images in most part of the graph to +# 1. This prevents the downstream nodes from queuing up incoming images and data +# excessively, which leads to increased latency and memory usage, unwanted in +# real-time mobile applications. It also eliminates unnecessarily computation, +# e.g., the output produced by a node may get dropped downstream if the +# subsequent nodes are still busy processing previous inputs. node { calculator: "FlowLimiterCalculator" input_stream: "input_video" - input_stream: "FINISHED:detections" + input_stream: "FINISHED:face_detections_presence" input_stream_info: { tag_index: "FINISHED" back_edge: true @@ -39,133 +40,15 @@ node { output_stream: "throttled_input_video" } -# Transforms the input image on CPU to a 128x128 image. To scale the input -# image, the scale_mode option is set to FIT to preserve the aspect ratio, -# resulting in potential letterboxing in the transformed image. -node: { - calculator: "ImageTransformationCalculator" - input_stream: "IMAGE:throttled_input_video" - output_stream: "IMAGE:transformed_input_video_cpu" - output_stream: "LETTERBOX_PADDING:letterbox_padding" - node_options: { - [type.googleapis.com/mediapipe.ImageTransformationCalculatorOptions] { - output_width: 128 - output_height: 128 - scale_mode: FIT - } - } -} - -# Converts the transformed input image on CPU into an image tensor stored as a -# TfLiteTensor. -node { - calculator: "TfLiteConverterCalculator" - input_stream: "IMAGE:transformed_input_video_cpu" - output_stream: "TENSORS:image_tensor" -} - -# 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: "TfLiteInferenceCalculator" - input_stream: "TENSORS:image_tensor" - output_stream: "TENSORS:detection_tensors" - node_options: { - [type.googleapis.com/mediapipe.TfLiteInferenceCalculatorOptions] { - model_path: "mediapipe/models/face_detection_front.tflite" - } - } -} - -# 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" - node_options: { - [type.googleapis.com/mediapipe.SsdAnchorsCalculatorOptions] { - 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: "TfLiteTensorsToDetectionsCalculator" - input_stream: "TENSORS:detection_tensors" - input_side_packet: "ANCHORS:anchors" - output_stream: "DETECTIONS:detections" - node_options: { - [type.googleapis.com/mediapipe.TfLiteTensorsToDetectionsCalculatorOptions] { - 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. +# Subgraph that detects faces. node { - calculator: "NonMaxSuppressionCalculator" - input_stream: "detections" - output_stream: "filtered_detections" - node_options: { - [type.googleapis.com/mediapipe.NonMaxSuppressionCalculatorOptions] { - min_suppression_threshold: 0.3 - overlap_type: INTERSECTION_OVER_UNION - algorithm: WEIGHTED - return_empty_detections: true - } - } -} - -# Maps detection label IDs to the corresponding label text ("Face"). The label -# map is provided in the label_map_path option. -node { - calculator: "DetectionLabelIdToTextCalculator" - input_stream: "filtered_detections" - output_stream: "labeled_detections" - node_options: { - [type.googleapis.com/mediapipe.DetectionLabelIdToTextCalculatorOptions] { - label_map_path: "mediapipe/models/face_detection_front_labelmap.txt" - } - } + calculator: "FaceDetectionFrontCpu" + input_stream: "IMAGE:throttled_input_video" + output_stream: "DETECTIONS:face_detections" } -# Adjusts detection locations (already normalized to [0.f, 1.f]) on the -# letterboxed image (after image transformation with the FIT scale mode) to the -# corresponding locations on the same image with the letterbox removed (the -# input image to the graph before image transformation). node { - calculator: "DetectionLetterboxRemovalCalculator" - input_stream: "DETECTIONS:labeled_detections" - input_stream: "LETTERBOX_PADDING:letterbox_padding" - output_stream: "DETECTIONS:output_detections" + calculator: "PacketPresenceCalculator" + input_stream: "PACKET:face_detections" + output_stream: "PRESENCE:face_detections_presence" } diff --git a/Assets/MediaPipe/Examples/Resources/face_detection_mobile_gpu.txt b/Assets/MediaPipe/Examples/Resources/face_detection_mobile_gpu.txt index ed64648f6..255c7983b 100644 --- a/Assets/MediaPipe/Examples/Resources/face_detection_mobile_gpu.txt +++ b/Assets/MediaPipe/Examples/Resources/face_detection_mobile_gpu.txt @@ -12,26 +12,27 @@ # See the License for the specific language governing permissions and # limitations under the License. +# GPU buffer. (GpuBuffer) input_stream: "input_video" -output_stream: "output_detections" + +# Detected faces. (std::vector) +output_stream: "face_detections" +output_stream: "face_detections_presence" # Throttles the images flowing downstream for flow control. It passes through -# the very first incoming image unaltered, and waits for -# TfLiteTensorsToDetectionsCalculator downstream in the graph to finish -# generating the corresponding detections before it passes through another -# image. All images that come in while waiting are dropped, limiting the number -# of in-flight images between this calculator and -# TfLiteTensorsToDetectionsCalculator to 1. This prevents the nodes in between -# from queuing up incoming images and data excessively, which leads to increased -# latency and memory usage, unwanted in real-time mobile applications. It also -# eliminates unnecessarily computation, e.g., a transformed image produced by -# ImageTransformationCalculator may get dropped downstream if the subsequent -# TfLiteConverterCalculator or TfLiteInferenceCalculator is still busy -# processing previous inputs. +# the very first incoming image unaltered, and waits for downstream nodes +# (calculators and subgraphs) in the graph to finish their tasks before it +# passes through another image. All images that come in while waiting are +# dropped, limiting the number of in-flight images in most part of the graph to +# 1. This prevents the downstream nodes from queuing up incoming images and data +# excessively, which leads to increased latency and memory usage, unwanted in +# real-time mobile applications. It also eliminates unnecessarily computation, +# e.g., the output produced by a node may get dropped downstream if the +# subsequent nodes are still busy processing previous inputs. node { calculator: "FlowLimiterCalculator" input_stream: "input_video" - input_stream: "FINISHED:detections" + input_stream: "FINISHED:face_detections_presence" input_stream_info: { tag_index: "FINISHED" back_edge: true @@ -39,133 +40,15 @@ node { output_stream: "throttled_input_video" } -# Transforms the input image on GPU to a 128x128 image. To scale the input -# image, the scale_mode option is set to FIT to preserve the aspect ratio, -# resulting in potential letterboxing in the transformed image. -node: { - calculator: "ImageTransformationCalculator" - input_stream: "IMAGE_GPU:throttled_input_video" - output_stream: "IMAGE_GPU:transformed_input_video" - output_stream: "LETTERBOX_PADDING:letterbox_padding" - node_options: { - [type.googleapis.com/mediapipe.ImageTransformationCalculatorOptions] { - output_width: 128 - output_height: 128 - scale_mode: FIT - } - } -} - -# Converts the transformed input image on GPU into an image tensor stored as a -# TfLiteTensor. -node { - calculator: "TfLiteConverterCalculator" - input_stream: "IMAGE_GPU:transformed_input_video" - output_stream: "TENSORS_GPU:image_tensor" -} - -# 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: "TfLiteInferenceCalculator" - input_stream: "TENSORS_GPU:image_tensor" - output_stream: "TENSORS_GPU:detection_tensors" - node_options: { - [type.googleapis.com/mediapipe.TfLiteInferenceCalculatorOptions] { - model_path: "mediapipe/models/face_detection_front.tflite" - } - } -} - -# 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" - node_options: { - [type.googleapis.com/mediapipe.SsdAnchorsCalculatorOptions] { - 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: "TfLiteTensorsToDetectionsCalculator" - input_stream: "TENSORS_GPU:detection_tensors" - input_side_packet: "ANCHORS:anchors" - output_stream: "DETECTIONS:detections" - node_options: { - [type.googleapis.com/mediapipe.TfLiteTensorsToDetectionsCalculatorOptions] { - 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: "detections" - output_stream: "filtered_detections" - node_options: { - [type.googleapis.com/mediapipe.NonMaxSuppressionCalculatorOptions] { - min_suppression_threshold: 0.3 - overlap_type: INTERSECTION_OVER_UNION - algorithm: WEIGHTED - return_empty_detections: true - } - } -} - -# Maps detection label IDs to the corresponding label text ("Face"). The label -# map is provided in the label_map_path option. +# Subgraph that detects faces. node { - calculator: "DetectionLabelIdToTextCalculator" - input_stream: "filtered_detections" - output_stream: "labeled_detections" - node_options: { - [type.googleapis.com/mediapipe.DetectionLabelIdToTextCalculatorOptions] { - label_map_path: "mediapipe/models/face_detection_front_labelmap.txt" - } - } + calculator: "FaceDetectionFrontGpu" + input_stream: "IMAGE:throttled_input_video" + output_stream: "DETECTIONS:face_detections" } -# Adjusts detection locations (already normalized to [0.f, 1.f]) on the -# letterboxed image (after image transformation with the FIT scale mode) to the -# corresponding locations on the same image with the letterbox removed (the -# input image to the graph before image transformation). node { - calculator: "DetectionLetterboxRemovalCalculator" - input_stream: "DETECTIONS:labeled_detections" - input_stream: "LETTERBOX_PADDING:letterbox_padding" - output_stream: "DETECTIONS:output_detections" + calculator: "PacketPresenceCalculator" + input_stream: "PACKET:face_detections" + output_stream: "PRESENCE:face_detections_presence" } diff --git a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live.txt b/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live.txt index d09ff62f7..f9fbd1184 100644 --- a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live.txt +++ b/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live.txt @@ -14,15 +14,28 @@ # MediaPipe graph that performs face mesh with TensorFlow Lite on CPU. +# Input image. (ImageFrame) input_stream: "input_video" +# Collection of detected/processed faces, each represented as a list of +# landmarks. (std::vector) output_stream: "multi_face_landmarks" + output_stream: "face_rects_from_landmarks" output_stream: "face_detections" output_stream: "multi_face_landmarks_presence" output_stream: "face_detections_presence" -# Throttles the images flowing downstream for flow control. +# Throttles the images flowing downstream for flow control. It passes through +# the very first incoming image unaltered, and waits for downstream nodes +# (calculators and subgraphs) in the graph to finish their tasks before it +# passes through another image. All images that come in while waiting are +# dropped, limiting the number of in-flight images in most part of the graph to +# 1. This prevents the downstream nodes from queuing up incoming images and data +# excessively, which leads to increased latency and memory usage, unwanted in +# real-time mobile applications. It also eliminates unnecessarily computation, +# e.g., the output produced by a node may get dropped downstream if the +# subsequent nodes are still busy processing previous inputs. node { calculator: "FlowLimiterCalculator" input_stream: "input_video" @@ -34,17 +47,6 @@ node { output_stream: "throttled_input_video" } -# Defines side packets for further use in the graph. -node { - calculator: "ConstantSidePacketCalculator" - output_side_packet: "PACKET:num_faces" - node_options: { - [type.googleapis.com/mediapipe.ConstantSidePacketCalculatorOptions]: { - packet { int_value: 1 } - } - } -} - # Subgraph that detects faces and corresponding landmarks. node { calculator: "FaceLandmarkFrontCpu" diff --git a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt b/Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt similarity index 65% rename from Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt rename to Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt index cf29320b1..821deefab 100644 --- a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt +++ b/Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt @@ -14,15 +14,31 @@ # MediaPipe graph that performs face mesh with TensorFlow Lite on GPU. +# GPU buffer. (GpuBuffer) input_stream: "input_video" +# Max number of faces to detect/process. (int) +input_side_packet: "num_faces" + +# Collection of detected/processed faces, each represented as a list of +# landmarks. (std::vector) output_stream: "multi_face_landmarks" + output_stream: "face_rects_from_landmarks" output_stream: "face_detections" output_stream: "multi_face_landmarks_presence" output_stream: "face_detections_presence" -# Throttles the images flowing downstream for flow control. +# Throttles the images flowing downstream for flow control. It passes through +# the very first incoming image unaltered, and waits for downstream nodes +# (calculators and subgraphs) in the graph to finish their tasks before it +# passes through another image. All images that come in while waiting are +# dropped, limiting the number of in-flight images in most part of the graph to +# 1. This prevents the downstream nodes from queuing up incoming images and data +# excessively, which leads to increased latency and memory usage, unwanted in +# real-time mobile applications. It also eliminates unnecessarily computation, +# e.g., the output produced by a node may get dropped downstream if the +# subsequent nodes are still busy processing previous inputs. node { calculator: "FlowLimiterCalculator" input_stream: "input_video" @@ -34,17 +50,6 @@ node { output_stream: "throttled_input_video" } -# Defines side packets for further use in the graph. -node { - calculator: "ConstantSidePacketCalculator" - output_side_packet: "PACKET:num_faces" - node_options: { - [type.googleapis.com/mediapipe.ConstantSidePacketCalculatorOptions]: { - packet { int_value: 1 } - } - } -} - # Subgraph that detects faces and corresponding landmarks. node { calculator: "FaceLandmarkFrontGpu" diff --git a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt.meta b/Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt.meta similarity index 75% rename from Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt.meta rename to Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt.meta index 50fb9ab23..3e842ecbf 100644 --- a/Assets/MediaPipe/Examples/Resources/face_mesh_desktop_live_gpu.txt.meta +++ b/Assets/MediaPipe/Examples/Resources/face_mesh_mobile.txt.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 83097db0ae996a3ae8b65ad6b8db6444 +guid: daf329e7d9e05b86e87226eba2dd3f32 TextScriptImporter: externalObjects: {} userData: diff --git a/Assets/MediaPipe/Examples/Resources/hand_tracking_desktop_live.txt b/Assets/MediaPipe/Examples/Resources/hand_tracking_desktop_live.txt index f63af952d..981a38c6e 100644 --- a/Assets/MediaPipe/Examples/Resources/hand_tracking_desktop_live.txt +++ b/Assets/MediaPipe/Examples/Resources/hand_tracking_desktop_live.txt @@ -17,96 +17,39 @@ # Used in the example in # mediapipie/examples/desktop/hand_tracking:hand_tracking_cpu. +# CPU image. (ImageFrame) input_stream: "input_video" -output_stream: "handedness" +# Max number of hands to detect/process. (int) +input_side_packet: "num_hands" + +# Collection of detected/predicted hands, each represented as a list of +# landmarks. (std::vector) output_stream: "hand_landmarks" -output_stream: "hand_rect" + +output_stream: "handedness" output_stream: "palm_detections" +output_stream: "hand_rects_from_landmarks" +output_stream: "hand_rects_from_palm_detections" +output_stream: "hand_landmarks_presence" output_stream: "palm_detections_presence" -# Caches a hand-presence decision fed back from HandLandmarkSubgraph, and upon -# the arrival of the next input image sends out the cached decision with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand-presence decision. Note that upon the arrival -# of the very first input image, an empty packet is sent out to jump start the -# feedback loop. -node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:input_video" - input_stream: "LOOP:hand_presence" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_hand_presence" -} - -# Drops the incoming image if HandLandmarkSubgraph was able to identify hand -# presence in the previous image. Otherwise, passes the incoming image through -# to trigger a new round of hand detection in HandDetectionSubgraph. -node { - calculator: "GateCalculator" - input_stream: "input_video" - input_stream: "DISALLOW:prev_hand_presence" - output_stream: "hand_detection_input_video" - - node_options: { - [type.googleapis.com/mediapipe.GateCalculatorOptions] { - empty_packets_as_allow: true - } - } -} - -# Subgraph that detections hands (see hand_detection_cpu.pbtxt). -node { - calculator: "HandDetectionSubgraph" - input_stream: "hand_detection_input_video" - output_stream: "DETECTIONS:palm_detections" - output_stream: "NORM_RECT:hand_rect_from_palm_detections" -} - -# Subgraph that localizes hand landmarks (see hand_landmark_cpu.pbtxt). +# Detects/tracks hand landmarks. node { - calculator: "HandLandmarkSubgraph" + calculator: "HandLandmarkTrackingCpu" input_stream: "IMAGE:input_video" - input_stream: "NORM_RECT:hand_rect" + input_side_packet: "NUM_HANDS:num_hands" output_stream: "LANDMARKS:hand_landmarks" - output_stream: "NORM_RECT:hand_rect_from_landmarks" output_stream: "HANDEDNESS:handedness" - output_stream: "PRESENCE:hand_presence" + output_stream: "PALM_DETECTIONS:palm_detections" + output_stream: "HAND_ROIS_FROM_LANDMARKS:hand_rects_from_landmarks" + output_stream: "HAND_ROIS_FROM_PALM_DETECTIONS:hand_rects_from_palm_detections" } -# Caches a hand rectangle fed back from HandLandmarkSubgraph, and upon the -# arrival of the next input image sends out the cached rectangle with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand rectangle. Note that upon the arrival of the -# very first input image, an empty packet is sent out to jump start the -# feedback loop. node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:input_video" - input_stream: "LOOP:hand_rect_from_landmarks" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_hand_rect_from_landmarks" -} - -# Merges a stream of hand rectangles generated by HandDetectionSubgraph and that -# generated by HandLandmarkSubgraph into a single output stream by selecting -# between one of the two streams. The former is selected if the incoming packet -# is not empty, i.e., hand detection is performed on the current image by -# HandDetectionSubgraph (because HandLandmarkSubgraph could not identify hand -# presence in the previous image). Otherwise, the latter is selected, which is -# never empty because HandLandmarkSubgraphs processes all images (that went -# through FlowLimiterCaculator). -node { - calculator: "MergeCalculator" - input_stream: "hand_rect_from_palm_detections" - input_stream: "prev_hand_rect_from_landmarks" - output_stream: "hand_rect" + calculator: "PacketPresenceCalculator" + input_stream: "PACKET:hand_landmarks" + output_stream: "PRESENCE:hand_landmarks_presence" } node { diff --git a/Assets/MediaPipe/Examples/Resources/hand_tracking_mobile.txt b/Assets/MediaPipe/Examples/Resources/hand_tracking_mobile.txt index c2fef85dc..623de8f5d 100644 --- a/Assets/MediaPipe/Examples/Resources/hand_tracking_mobile.txt +++ b/Assets/MediaPipe/Examples/Resources/hand_tracking_mobile.txt @@ -12,15 +12,25 @@ # See the License for the specific language governing permissions and # limitations under the License. -# MediaPipe graph that performs hand tracking with TensorFlow Lite on GPU. +# MediaPipe graph that performs multi-hand tracking with TensorFlow Lite on GPU. +# Used in the examples in +# mediapipe/examples/android/src/java/com/mediapipe/apps/multihandtrackinggpu. -# Images coming into and out of the graph. +# GPU image. (GpuBuffer) input_stream: "input_video" -output_stream: "handedness" +# Max number of hands to detect/process. (int) +input_side_packet: "num_hands" + +# Collection of detected/predicted hands, each represented as a list of +# landmarks. (std::vector) output_stream: "hand_landmarks" -output_stream: "hand_rect" + +output_stream: "handedness" output_stream: "palm_detections" +output_stream: "hand_rects_from_landmarks" +output_stream: "hand_rects_from_palm_detections" +output_stream: "hand_landmarks_presence" output_stream: "palm_detections_presence" # Throttles the images flowing downstream for flow control. It passes through @@ -36,7 +46,7 @@ output_stream: "palm_detections_presence" node { calculator: "FlowLimiterCalculator" input_stream: "input_video" - input_stream: "FINISHED:hand_rect" + input_stream: "FINISHED:hand_landmarks_presence" input_stream_info: { tag_index: "FINISHED" back_edge: true @@ -44,88 +54,22 @@ node { output_stream: "throttled_input_video" } -# Caches a hand-presence decision fed back from HandLandmarkSubgraph, and upon -# the arrival of the next input image sends out the cached decision with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand-presence decision. Note that upon the arrival -# of the very first input image, an empty packet is sent out to jump start the -# feedback loop. +# Detects/tracks hand landmarks. node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:throttled_input_video" - input_stream: "LOOP:hand_presence" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_hand_presence" -} - -# Drops the incoming image if HandLandmarkSubgraph was able to identify hand -# presence in the previous image. Otherwise, passes the incoming image through -# to trigger a new round of hand detection in HandDetectionSubgraph. -node { - calculator: "GateCalculator" - input_stream: "throttled_input_video" - input_stream: "DISALLOW:prev_hand_presence" - output_stream: "hand_detection_input_video" - - node_options: { - [type.googleapis.com/mediapipe.GateCalculatorOptions] { - empty_packets_as_allow: true - } - } -} - -# Subgraph that detections hands (see hand_detection_gpu.pbtxt). -node { - calculator: "HandDetectionSubgraph" - input_stream: "hand_detection_input_video" - output_stream: "DETECTIONS:palm_detections" - output_stream: "NORM_RECT:hand_rect_from_palm_detections" -} - -# Subgraph that localizes hand landmarks (see hand_landmark_gpu.pbtxt). -node { - calculator: "HandLandmarkSubgraph" + calculator: "HandLandmarkTrackingGpu" input_stream: "IMAGE:throttled_input_video" - input_stream: "NORM_RECT:hand_rect" + input_side_packet: "NUM_HANDS:num_hands" output_stream: "LANDMARKS:hand_landmarks" - output_stream: "NORM_RECT:hand_rect_from_landmarks" - output_stream: "PRESENCE:hand_presence" output_stream: "HANDEDNESS:handedness" + output_stream: "PALM_DETECTIONS:palm_detections" + output_stream: "HAND_ROIS_FROM_LANDMARKS:hand_rects_from_landmarks" + output_stream: "HAND_ROIS_FROM_PALM_DETECTIONS:hand_rects_from_palm_detections" } -# Caches a hand rectangle fed back from HandLandmarkSubgraph, and upon the -# arrival of the next input image sends out the cached rectangle with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand rectangle. Note that upon the arrival of the -# very first input image, an empty packet is sent out to jump start the -# feedback loop. -node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:throttled_input_video" - input_stream: "LOOP:hand_rect_from_landmarks" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_hand_rect_from_landmarks" -} - -# Merges a stream of hand rectangles generated by HandDetectionSubgraph and that -# generated by HandLandmarkSubgraph into a single output stream by selecting -# between one of the two streams. The former is selected if the incoming packet -# is not empty, i.e., hand detection is performed on the current image by -# HandDetectionSubgraph (because HandLandmarkSubgraph could not identify hand -# presence in the previous image). Otherwise, the latter is selected, which is -# never empty because HandLandmarkSubgraphs processes all images (that went -# through FlowLimiterCaculator). node { - calculator: "MergeCalculator" - input_stream: "hand_rect_from_palm_detections" - input_stream: "prev_hand_rect_from_landmarks" - output_stream: "hand_rect" + calculator: "PacketPresenceCalculator" + input_stream: "PACKET:hand_landmarks" + output_stream: "PRESENCE:hand_landmarks_presence" } node { diff --git a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt b/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt deleted file mode 100644 index a07bc9e6b..000000000 --- a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt +++ /dev/null @@ -1,126 +0,0 @@ -# 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. - -# MediaPipe graph that performs multi-hand tracking on desktop with TensorFlow -# Lite on CPU. -# Used in the example in -# mediapipie/examples/desktop/hand_tracking:multi_hand_tracking_cpu. - -input_stream: "input_video" - -output_stream: "multi_hand_landmarks" -output_stream: "multi_palm_detections" -output_stream: "multi_palm_rects" -output_stream: "multi_palm_detections_presence" - -# Determines if an input vector of NormalizedRect has a size greater than or -# equal to the provided min_size. -node { - calculator: "NormalizedRectVectorHasMinSizeCalculator" - input_stream: "ITERABLE:prev_multi_hand_rects_from_landmarks" - output_stream: "prev_has_enough_hands" - node_options: { - [type.googleapis.com/mediapipe.CollectionHasMinSizeCalculatorOptions] { - # This value can be changed to support tracking arbitrary number of hands. - # Please also remember to modify max_vec_size in - # ClipVectorSizeCalculatorOptions in - # mediapipe/graphs/hand_tracking/subgraphs/multi_hand_detection_gpu.pbtxt - min_size: 2 - } - } -} - -# Drops the incoming image if the previous frame had at least N hands. -# Otherwise, passes the incoming image through to trigger a new round of hand -# detection in MultiHandDetectionSubgraph. -node { - calculator: "GateCalculator" - input_stream: "input_video" - input_stream: "DISALLOW:prev_has_enough_hands" - output_stream: "multi_hand_detection_input_video" - node_options: { - [type.googleapis.com/mediapipe.GateCalculatorOptions] { - empty_packets_as_allow: true - } - } -} - -# Subgraph that detections hands (see multi_hand_detection_cpu.pbtxt). -node { - calculator: "MultiHandDetectionSubgraph" - input_stream: "multi_hand_detection_input_video" - output_stream: "DETECTIONS:multi_palm_detections" - output_stream: "NORM_RECTS:multi_palm_rects" -} - -# Subgraph that localizes hand landmarks for multiple hands (see -# multi_hand_landmark.pbtxt). -node { - calculator: "MultiHandLandmarkSubgraph" - input_stream: "IMAGE:input_video" - input_stream: "NORM_RECTS:multi_hand_rects" - output_stream: "LANDMARKS:multi_hand_landmarks" - output_stream: "NORM_RECTS:multi_hand_rects_from_landmarks" -} - -# Caches a hand rectangle fed back from MultiHandLandmarkSubgraph, and upon the -# arrival of the next input image sends out the cached rectangle with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand rectangle. Note that upon the arrival of the -# very first input image, an empty packet is sent out to jump start the -# feedback loop. -node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:input_video" - input_stream: "LOOP:multi_hand_rects_from_landmarks" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_multi_hand_rects_from_landmarks" -} - -# Performs association between NormalizedRect vector elements from previous -# frame and those from the current frame if MultiHandDetectionSubgraph runs. -# This calculator ensures that the output multi_hand_rects vector doesn't -# contain overlapping regions based on the specified min_similarity_threshold. -node { - calculator: "AssociationNormRectCalculator" - input_stream: "prev_multi_hand_rects_from_landmarks" - input_stream: "multi_palm_rects" - output_stream: "multi_hand_rects" - node_options: { - [type.googleapis.com/mediapipe.AssociationCalculatorOptions] { - min_similarity_threshold: 0.5 - } - } -} - -# Subgraph that renders annotations and overlays them on top of the input -# images (see multi_hand_renderer_cpu.pbtxt). -node { - calculator: "MultiHandRendererSubgraph" - input_stream: "IMAGE:input_video" - input_stream: "DETECTIONS:multi_palm_detections" - input_stream: "LANDMARKS:multi_hand_landmarks" - input_stream: "NORM_RECTS:0:multi_palm_rects" - input_stream: "NORM_RECTS:1:multi_hand_rects" - output_stream: "IMAGE:output_video" -} - -node { - calculator: "PacketPresenceCalculator" - input_stream: "PACKET:multi_palm_detections" - output_stream: "PRESENCE:multi_palm_detections_presence" -} diff --git a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt.meta b/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt.meta deleted file mode 100644 index 71aa03ff8..000000000 --- a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_desktop_live.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 00e4ddf383767ad25b6776ca868b595b -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt b/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt deleted file mode 100644 index dcc139421..000000000 --- a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt +++ /dev/null @@ -1,134 +0,0 @@ -# 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. - -# MediaPipe graph that performs multi-hand tracking with TensorFlow Lite on GPU. -# Used in the examples in -# mediapipe/examples/android/src/java/com/mediapipe/apps/multihandtrackinggpu. - -input_stream: "input_video" - -output_stream: "multi_hand_landmarks" -output_stream: "multi_palm_detections" -output_stream: "multi_palm_rects" -output_stream: "multi_palm_detections_presence" - -# Throttles the images flowing downstream for flow control. It passes through -# the very first incoming image unaltered, and waits for downstream nodes -# (calculators and subgraphs) in the graph to finish their tasks before it -# passes through another image. All images that come in while waiting are -# dropped, limiting the number of in-flight images in most part of the graph to -# 1. This prevents the downstream nodes from queuing up incoming images and data -# excessively, which leads to increased latency and memory usage, unwanted in -# real-time mobile applications. It also eliminates unnecessarily computation, -# e.g., the output produced by a node may get dropped downstream if the -# subsequent nodes are still busy processing previous inputs. -node { - calculator: "FlowLimiterCalculator" - input_stream: "input_video" - input_stream: "FINISHED:multi_hand_rects" - input_stream_info: { - tag_index: "FINISHED" - back_edge: true - } - output_stream: "throttled_input_video" -} - -# Determines if an input vector of NormalizedRect has a size greater than or -# equal to the provided min_size. -node { - calculator: "NormalizedRectVectorHasMinSizeCalculator" - input_stream: "ITERABLE:prev_multi_hand_rects_from_landmarks" - output_stream: "prev_has_enough_hands" - node_options: { - [type.googleapis.com/mediapipe.CollectionHasMinSizeCalculatorOptions] { - # This value can be changed to support tracking arbitrary number of hands. - # Please also remember to modify max_vec_size in - # ClipVectorSizeCalculatorOptions in - # mediapipe/graphs/hand_tracking/subgraphs/multi_hand_detection_gpu.pbtxt - min_size: 2 - } - } -} - -# Drops the incoming image if the previous frame had at least N hands. -# Otherwise, passes the incoming image through to trigger a new round of hand -# detection in MultiHandDetectionSubgraph. -node { - calculator: "GateCalculator" - input_stream: "throttled_input_video" - input_stream: "DISALLOW:prev_has_enough_hands" - output_stream: "multi_hand_detection_input_video" - node_options: { - [type.googleapis.com/mediapipe.GateCalculatorOptions] { - empty_packets_as_allow: true - } - } -} - -# Subgraph that detections hands (see multi_hand_detection_gpu.pbtxt). -node { - calculator: "MultiHandDetectionSubgraph" - input_stream: "multi_hand_detection_input_video" - output_stream: "DETECTIONS:multi_palm_detections" - output_stream: "NORM_RECTS:multi_palm_rects" -} - -# Subgraph that localizes hand landmarks for multiple hands (see -# multi_hand_landmark.pbtxt). -node { - calculator: "MultiHandLandmarkSubgraph" - input_stream: "IMAGE:throttled_input_video" - input_stream: "NORM_RECTS:multi_hand_rects" - output_stream: "LANDMARKS:multi_hand_landmarks" - output_stream: "NORM_RECTS:multi_hand_rects_from_landmarks" -} - -# Caches a hand rectangle fed back from MultiHandLandmarkSubgraph, and upon the -# arrival of the next input image sends out the cached rectangle with the -# timestamp replaced by that of the input image, essentially generating a packet -# that carries the previous hand rectangle. Note that upon the arrival of the -# very first input image, an empty packet is sent out to jump start the -# feedback loop. -node { - calculator: "PreviousLoopbackCalculator" - input_stream: "MAIN:throttled_input_video" - input_stream: "LOOP:multi_hand_rects_from_landmarks" - input_stream_info: { - tag_index: "LOOP" - back_edge: true - } - output_stream: "PREV_LOOP:prev_multi_hand_rects_from_landmarks" -} - -# Performs association between NormalizedRect vector elements from previous -# frame and those from the current frame if MultiHandDetectionSubgraph runs. -# This calculator ensures that the output multi_hand_rects vector doesn't -# contain overlapping regions based on the specified min_similarity_threshold. -node { - calculator: "AssociationNormRectCalculator" - input_stream: "prev_multi_hand_rects_from_landmarks" - input_stream: "multi_palm_rects" - output_stream: "multi_hand_rects" - node_options: { - [type.googleapis.com/mediapipe.AssociationCalculatorOptions] { - min_similarity_threshold: 0.5 - } - } -} - -node { - calculator: "PacketPresenceCalculator" - input_stream: "PACKET:multi_palm_detections" - output_stream: "PRESENCE:multi_palm_detections_presence" -} diff --git a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt.meta b/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt.meta deleted file mode 100644 index 2d51882fa..000000000 --- a/Assets/MediaPipe/Examples/Resources/multi_hand_tracking_mobile.txt.meta +++ /dev/null @@ -1,7 +0,0 @@ -fileFormatVersion: 2 -guid: 79a190956c8b3545e806abe3d39dbf76 -TextScriptImporter: - externalObjects: {} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Scripts/FaceDetection/FaceDetectionGraph.cs b/Assets/MediaPipe/Examples/Scripts/FaceDetection/FaceDetectionGraph.cs index 58432b1e1..af29ae16b 100644 --- a/Assets/MediaPipe/Examples/Scripts/FaceDetection/FaceDetectionGraph.cs +++ b/Assets/MediaPipe/Examples/Scripts/FaceDetection/FaceDetectionGraph.cs @@ -1,21 +1,27 @@ using Mediapipe; using System.Collections.Generic; -using UnityEngine; public class FaceDetectionGraph : DemoGraph { - private const string outputDetectionsStream = "output_detections"; - private OutputStreamPoller> outputDetectionsStreamPoller; - private DetectionVectorPacket outputDetectionsPacket; + private const string faceDetectionsStream = "face_detections"; + private OutputStreamPoller> faceDetectionsStreamPoller; + private DetectionVectorPacket faceDetectionsPacket; - public override Status StartRun(SidePacket sidePacket) { - outputDetectionsStreamPoller = graph.AddOutputStreamPoller>(outputDetectionsStream).ConsumeValueOrDie(); - outputDetectionsPacket = new DetectionVectorPacket(); + private const string faceDetectionsPresenceStream = "face_detections_presence"; + private OutputStreamPoller faceDetectionsPresenceStreamPoller; + private BoolPacket faceDetectionsPresencePacket; - return graph.StartRun(sidePacket); + public override Status StartRun() { + faceDetectionsStreamPoller = graph.AddOutputStreamPoller>(faceDetectionsStream).ConsumeValueOrDie(); + faceDetectionsPacket = new DetectionVectorPacket(); + + faceDetectionsPresenceStreamPoller = graph.AddOutputStreamPoller(faceDetectionsPresenceStream).ConsumeValueOrDie(); + faceDetectionsPresencePacket = new BoolPacket(); + + return graph.StartRun(); } public override void RenderOutput(WebCamScreenController screenController, PixelData pixelData) { - var detections = FetchNextOutputDetections(); + var detections = FetchNextFaceDetectionsPresence() ? FetchNextFaceDetections() : new List(); RenderAnnotation(screenController, detections); var texture = screenController.GetScreen(); @@ -23,8 +29,12 @@ public override void RenderOutput(WebCamScreenController screenController, Pixel texture.Apply(); } - private List FetchNextOutputDetections() { - return FetchNextVector(outputDetectionsStreamPoller, outputDetectionsPacket, outputDetectionsStream); + private bool FetchNextFaceDetectionsPresence() { + return FetchNext(faceDetectionsPresenceStreamPoller, faceDetectionsPresencePacket, faceDetectionsPresenceStream); + } + + private List FetchNextFaceDetections() { + return FetchNextVector(faceDetectionsStreamPoller, faceDetectionsPacket, faceDetectionsStream); } private void RenderAnnotation(WebCamScreenController screenController, List detections) { diff --git a/Assets/MediaPipe/Examples/Scripts/FaceMesh/FaceMeshGraph.cs b/Assets/MediaPipe/Examples/Scripts/FaceMesh/FaceMeshGraph.cs index 2e0f44726..572989a55 100644 --- a/Assets/MediaPipe/Examples/Scripts/FaceMesh/FaceMeshGraph.cs +++ b/Assets/MediaPipe/Examples/Scripts/FaceMesh/FaceMeshGraph.cs @@ -3,6 +3,8 @@ using UnityEngine; public class FaceMeshGraph : DemoGraph { + [SerializeField] int numFaces = 1; + private const string multiFaceLandmarksStream = "multi_face_landmarks"; private OutputStreamPoller> multiFaceLandmarksStreamPoller; private NormalizedLandmarkListVectorPacket multiFaceLandmarksPacket; @@ -42,6 +44,7 @@ public override Status StartRun() { faceDetectionsPresencePacket = new BoolPacket(); sidePacket = new SidePacket(); + sidePacket.Emplace("num_faces", new IntPacket(numFaces)); return graph.StartRun(sidePacket); } diff --git a/Assets/MediaPipe/Examples/Scripts/GraphSelectorController.cs b/Assets/MediaPipe/Examples/Scripts/GraphSelectorController.cs index fe5a422b2..9799ace16 100644 --- a/Assets/MediaPipe/Examples/Scripts/GraphSelectorController.cs +++ b/Assets/MediaPipe/Examples/Scripts/GraphSelectorController.cs @@ -9,7 +9,6 @@ public class GraphSelectorController : MonoBehaviour { [SerializeField] GameObject faceMeshGraph = null; [SerializeField] GameObject irisTrackingGraph = null; [SerializeField] GameObject handTrackingGraph = null; - [SerializeField] GameObject multiHandTrackingGraph = null; [SerializeField] GameObject poseTrackingGraph = null; [SerializeField] GameObject hairSegmentationGraph = null; [SerializeField] GameObject objectDetectionGraph = null; @@ -33,7 +32,6 @@ void InitializeOptions() { AddGraph("Face Mesh", faceMeshGraph); AddGraph("Iris Tracking", irisTrackingGraph); AddGraph("Hand Tracking", handTrackingGraph); - AddGraph("Multi-hand Tracking", multiHandTrackingGraph); AddGraph("Pose Tracking", poseTrackingGraph); AddGraph("Hair Segmentation", hairSegmentationGraph); AddGraph("Object Detection", objectDetectionGraph); diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingAnnotationController.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingAnnotationController.cs index 24e394c3a..8a49c4bd6 100644 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingAnnotationController.cs +++ b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingAnnotationController.cs @@ -3,43 +3,37 @@ using UnityEngine; public class HandTrackingAnnotationController : AnnotationController { - [SerializeField] GameObject handednessPrefab = null; - [SerializeField] GameObject handLandmarkListPrefab = null; - [SerializeField] GameObject handRectPrefab = null; + [SerializeField] GameObject handLandmarkListsPrefab = null; + [SerializeField] GameObject palmRectsPrefab = null; [SerializeField] GameObject palmDetectionsPrefab = null; - private GameObject handednessAnnotation; - private GameObject handLandmarkListAnnotation; - private GameObject handRectAnnotation; + private GameObject handLandmarkListsAnnotation; + private GameObject palmRectsAnnotation; private GameObject palmDetectionsAnnotation; void Awake() { - handednessAnnotation = Instantiate(handednessPrefab); - handLandmarkListAnnotation = Instantiate(handLandmarkListPrefab); - handRectAnnotation = Instantiate(handRectPrefab); + handLandmarkListsAnnotation = Instantiate(handLandmarkListsPrefab); + palmRectsAnnotation = Instantiate(palmRectsPrefab); palmDetectionsAnnotation = Instantiate(palmDetectionsPrefab); } void OnDestroy() { - Destroy(handednessAnnotation); - Destroy(handLandmarkListAnnotation); - Destroy(handRectAnnotation); + Destroy(handLandmarkListsAnnotation); Destroy(palmDetectionsAnnotation); + Destroy(palmRectsAnnotation); } public override void Clear() { - handednessAnnotation.GetComponent().Clear(); - handRectAnnotation.GetComponent().Clear(); - handLandmarkListAnnotation.GetComponent().Clear(); + handLandmarkListsAnnotation.GetComponent().Clear(); palmDetectionsAnnotation.GetComponent().Clear(); + palmRectsAnnotation.GetComponent().Clear(); } - public void Draw(Transform screenTransform, ClassificationList handedness, NormalizedLandmarkList handLandmarkList, - NormalizedRect handRect, List palmDetections, bool isFlipped = false) + public void Draw(Transform screenTransform, List handLandmarkLists, List handednesses, + List palmDetections, List handRects, bool isFlipped = false) { - handednessAnnotation.GetComponent().Draw(screenTransform, handedness); - handLandmarkListAnnotation.GetComponent().Draw(screenTransform, handLandmarkList, isFlipped); - handRectAnnotation.GetComponent().Draw(screenTransform, handRect, isFlipped); + handLandmarkListsAnnotation.GetComponent().Draw(screenTransform, handLandmarkLists, isFlipped); palmDetectionsAnnotation.GetComponent().Draw(screenTransform, palmDetections, isFlipped); + palmRectsAnnotation.GetComponent().Draw(screenTransform, handRects, isFlipped); } } diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingGraph.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingGraph.cs index c1f181027..2c2c905ff 100644 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingGraph.cs +++ b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingGraph.cs @@ -1,45 +1,56 @@ using Mediapipe; using System.Collections.Generic; -using UnityEngine; public class HandTrackingGraph : DemoGraph { - private const string handednessStream = "handedness"; - private OutputStreamPoller handednessStreamPoller; - private ClassificationListPacket handednessPacket; - - private const string handRectStream = "hand_rect"; - private OutputStreamPoller handRectStreamPoller; - private NormalizedRectPacket handRectPacket; - private const string handLandmarksStream = "hand_landmarks"; - private OutputStreamPoller handLandmarksStreamPoller; - private NormalizedLandmarkListPacket handLandmarksPacket; + private OutputStreamPoller> handLandmarksStreamPoller; + private NormalizedLandmarkListVectorPacket handLandmarksPacket; + + private const string handednessStream = "handedness"; + private OutputStreamPoller> handednessStreamPoller; + private ClassificationListVectorPacket handednessPacket; private const string palmDetectionsStream = "palm_detections"; private OutputStreamPoller> palmDetectionsStreamPoller; private DetectionVectorPacket palmDetectionsPacket; + private const string palmRectsStream = "hand_rects_from_palm_detections"; + private OutputStreamPoller> palmRectsStreamPoller; + private NormalizedRectVectorPacket palmRectsPacket; + + private const string handLandmarksPresenceStream = "hand_landmarks_presence"; + private OutputStreamPoller handLandmarksPresenceStreamPoller; + private BoolPacket handLandmarksPresencePacket; + private const string palmDetectionsPresenceStream = "palm_detections_presence"; private OutputStreamPoller palmDetectionsPresenceStreamPoller; private BoolPacket palmDetectionsPresencePacket; - public override Status StartRun() { - handednessStreamPoller = graph.AddOutputStreamPoller(handednessStream).ConsumeValueOrDie(); - handednessPacket = new ClassificationListPacket(); + private SidePacket sidePacket; - handRectStreamPoller = graph.AddOutputStreamPoller(handRectStream).ConsumeValueOrDie(); - handRectPacket = new NormalizedRectPacket(); + public override Status StartRun() { + handLandmarksStreamPoller = graph.AddOutputStreamPoller>(handLandmarksStream).ConsumeValueOrDie(); + handLandmarksPacket = new NormalizedLandmarkListVectorPacket(); - handLandmarksStreamPoller = graph.AddOutputStreamPoller(handLandmarksStream).ConsumeValueOrDie(); - handLandmarksPacket = new NormalizedLandmarkListPacket(); + handednessStreamPoller = graph.AddOutputStreamPoller>(handednessStream).ConsumeValueOrDie(); + handednessPacket = new ClassificationListVectorPacket(); palmDetectionsStreamPoller = graph.AddOutputStreamPoller>(palmDetectionsStream).ConsumeValueOrDie(); palmDetectionsPacket = new DetectionVectorPacket(); + palmRectsStreamPoller = graph.AddOutputStreamPoller>(palmRectsStream).ConsumeValueOrDie(); + palmRectsPacket = new NormalizedRectVectorPacket(); + + handLandmarksPresenceStreamPoller = graph.AddOutputStreamPoller(handLandmarksPresenceStream).ConsumeValueOrDie(); + handLandmarksPresencePacket = new BoolPacket(); + palmDetectionsPresenceStreamPoller = graph.AddOutputStreamPoller(palmDetectionsPresenceStream).ConsumeValueOrDie(); palmDetectionsPresencePacket = new BoolPacket(); - return graph.StartRun(); + sidePacket = new SidePacket(); + sidePacket.Emplace("num_hands", new IntPacket(2)); + + return graph.StartRun(sidePacket); } public override void RenderOutput(WebCamScreenController screenController, PixelData pixelData) { @@ -53,31 +64,33 @@ public override void RenderOutput(WebCamScreenController screenController, Pixel } private HandTrackingValue FetchNextHandTrackingValue() { - var handedness = FetchNextHandedness(); - var handLandmarks = FetchNextHandLandmarks(); - var handRect = FetchNextHandRect(); + var isPalmDetectionsPresent = FetchNextPalmDetectionsPresence(); + var isHandLandmarksPresent = FetchNextHandLandmarksPresence(); - if (!FetchNextPalmDetectionsPresence()) { - return new HandTrackingValue(handedness, handLandmarks, handRect); - } + var handLandmarks = isHandLandmarksPresent ? FetchNextHandLandmarks() : new List(); + var handednesses = isHandLandmarksPresent ? FetchNextHandednesses() : new List(); + var palmDetections = isPalmDetectionsPresent ? FetchNextPalmDetections() : new List(); + var palmRects = isPalmDetectionsPresent ? FetchNextPalmRects() : new List(); - var palmDetections = FetchNextPalmDetections(); - - return new HandTrackingValue(handedness, handLandmarks, handRect, palmDetections); + return new HandTrackingValue(handLandmarks, handednesses, palmDetections, palmRects); } - private ClassificationList FetchNextHandedness() { + private List FetchNextHandednesses() { return FetchNext(handednessStreamPoller, handednessPacket, handednessStream); } - private NormalizedRect FetchNextHandRect() { - return FetchNext(handRectStreamPoller, handRectPacket, handRectStream); + private List FetchNextPalmRects() { + return FetchNext(palmRectsStreamPoller, palmRectsPacket, palmRectsStream); } - private NormalizedLandmarkList FetchNextHandLandmarks() { + private List FetchNextHandLandmarks() { return FetchNext(handLandmarksStreamPoller, handLandmarksPacket, handLandmarksStream); } + private bool FetchNextHandLandmarksPresence() { + return FetchNext(handLandmarksPresenceStreamPoller, handLandmarksPresencePacket, handLandmarksPresenceStream); + } + private bool FetchNextPalmDetectionsPresence() { return FetchNext(palmDetectionsPresenceStreamPoller, palmDetectionsPresencePacket, palmDetectionsPresenceStream); } @@ -89,6 +102,6 @@ private List FetchNextPalmDetections() { private void RenderAnnotation(WebCamScreenController screenController, HandTrackingValue value) { // NOTE: input image is flipped GetComponent().Draw( - screenController.transform, value.Handedness, value.HandLandmarkList, value.HandRect, value.PalmDetections, true); + screenController.transform, value.HandLandmarkLists, value.Handednesses, value.PalmDetections, value.PalmRects, true); } } diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingValue.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingValue.cs index 80c13a470..900669512 100644 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingValue.cs +++ b/Assets/MediaPipe/Examples/Scripts/HandTracking/HandTrackingValue.cs @@ -2,18 +2,16 @@ using System.Collections.Generic; class HandTrackingValue { - public readonly ClassificationList Handedness; - public readonly NormalizedLandmarkList HandLandmarkList; - public readonly NormalizedRect HandRect; + public readonly List HandLandmarkLists; + public readonly List Handednesses; public readonly List PalmDetections; + public readonly List PalmRects; - public HandTrackingValue(ClassificationList classificationList, NormalizedLandmarkList landmarkList, NormalizedRect rect, List detections) { - Handedness = classificationList; - HandLandmarkList = landmarkList; - HandRect = rect; + public HandTrackingValue(List landmarkLists, List classificationLists, + List detections, List rects) { + HandLandmarkLists = landmarkLists; + Handednesses = classificationLists; PalmDetections = detections; + PalmRects = rects; } - - public HandTrackingValue(ClassificationList classificationList, NormalizedLandmarkList landmarkList, NormalizedRect rect) : - this(classificationList, landmarkList, rect, new List()) {} } diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs deleted file mode 100644 index 3c9c7a464..000000000 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs +++ /dev/null @@ -1,39 +0,0 @@ -using Mediapipe; -using System.Collections.Generic; -using UnityEngine; - -public class MultiHandTrackingAnnotationController : AnnotationController { - [SerializeField] GameObject handLandmarkListsPrefab = null; - [SerializeField] GameObject palmDetectionsPrefab = null; - [SerializeField] GameObject palmRectsPrefab = null; - - private GameObject handLandmarkListsAnnotation; - private GameObject palmDetectionsAnnotation; - private GameObject palmRectsAnnotation; - - void Awake() { - handLandmarkListsAnnotation = Instantiate(handLandmarkListsPrefab); - palmDetectionsAnnotation = Instantiate(palmDetectionsPrefab); - palmRectsAnnotation = Instantiate(palmRectsPrefab); - } - - void OnDestroy() { - Destroy(handLandmarkListsAnnotation); - Destroy(palmDetectionsAnnotation); - Destroy(palmRectsAnnotation); - } - - public override void Clear() { - handLandmarkListsAnnotation.GetComponent().Clear(); - palmDetectionsAnnotation.GetComponent().Clear(); - palmRectsAnnotation.GetComponent().Clear(); - } - - public void Draw(Transform screenTransform, List handLandmarkLists, - List palmDetections, List palmRects, bool isFlipped = false) - { - handLandmarkListsAnnotation.GetComponent().Draw(screenTransform, handLandmarkLists, isFlipped); - palmDetectionsAnnotation.GetComponent().Draw(screenTransform, palmDetections, isFlipped); - palmRectsAnnotation.GetComponent().Draw(screenTransform, palmRects, isFlipped); - } -} diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs deleted file mode 100644 index 4c7fcd920..000000000 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs +++ /dev/null @@ -1,82 +0,0 @@ -using Mediapipe; -using System.Collections.Generic; -using UnityEngine; - -public class MultiHandTrackingGraph : DemoGraph { - private const string multiHandLandmarksStream = "multi_hand_landmarks"; - private OutputStreamPoller> multiHandLandmarksStreamPoller; - private NormalizedLandmarkListVectorPacket multiHandLandmarksPacket; - - private const string multiPalmDetectionsStream = "multi_palm_detections"; - private OutputStreamPoller> multiPalmDetectionsStreamPoller; - private DetectionVectorPacket multiPalmDetectionsPacket; - - private const string multiPalmRectsStream = "multi_palm_rects"; - private OutputStreamPoller> multiPalmRectsStreamPoller; - private NormalizedRectVectorPacket multiPalmRectsPacket; - - private const string multiPalmDetectionsPresenceStream = "multi_palm_detections_presence"; - private OutputStreamPoller multiPalmDetectionsPresenceStreamPoller; - private BoolPacket multiPalmDetectionsPresencePacket; - - public override Status StartRun() { - multiHandLandmarksStreamPoller = graph.AddOutputStreamPoller>(multiHandLandmarksStream).ConsumeValueOrDie(); - multiHandLandmarksPacket = new NormalizedLandmarkListVectorPacket(); - - multiPalmDetectionsStreamPoller = graph.AddOutputStreamPoller>(multiPalmDetectionsStream).ConsumeValueOrDie(); - multiPalmDetectionsPacket = new DetectionVectorPacket(); - - multiPalmRectsStreamPoller = graph.AddOutputStreamPoller>(multiPalmRectsStream).ConsumeValueOrDie(); - multiPalmRectsPacket = new NormalizedRectVectorPacket(); - - multiPalmDetectionsPresenceStreamPoller = graph.AddOutputStreamPoller(multiPalmDetectionsPresenceStream).ConsumeValueOrDie(); - multiPalmDetectionsPresencePacket = new BoolPacket(); - - return graph.StartRun(); - } - - public override void RenderOutput(WebCamScreenController screenController, PixelData pixelData) { - var multiHandTrackingValue = FetchNextMultiHandTrackingValue(); - RenderAnnotation(screenController, multiHandTrackingValue); - - var texture = screenController.GetScreen(); - texture.SetPixels32(pixelData.Colors); - - texture.Apply(); - } - - private MultiHandTrackingValue FetchNextMultiHandTrackingValue() { - var multiHandLandmarks = FetchNextMultiHandLandmarks(); - - if (!FetchNextMultiPalmDetectionsPresence()) { - return new MultiHandTrackingValue(multiHandLandmarks); - } - - var multiPalmRects = FetchNextMultiPalmRects(); - var multiPalmDetections = FetchNextMultiPalmDetections(); - - return new MultiHandTrackingValue(multiHandLandmarks, multiPalmDetections, multiPalmRects); - } - - private List FetchNextMultiHandLandmarks() { - return FetchNextVector(multiHandLandmarksStreamPoller, multiHandLandmarksPacket, multiHandLandmarksStream); - } - - private List FetchNextMultiPalmDetections() { - return FetchNextVector(multiPalmDetectionsStreamPoller, multiPalmDetectionsPacket, multiPalmDetectionsStream); - } - - private List FetchNextMultiPalmRects() { - return FetchNextVector(multiPalmRectsStreamPoller, multiPalmRectsPacket, multiPalmRectsStream); - } - - private bool FetchNextMultiPalmDetectionsPresence() { - return FetchNext(multiPalmDetectionsPresenceStreamPoller, multiPalmDetectionsPresencePacket, multiPalmDetectionsPresenceStream); - } - - private void RenderAnnotation(WebCamScreenController screenController, MultiHandTrackingValue value) { - // NOTE: input image is flipped - GetComponent().Draw( - screenController.transform, value.MultiHandLandmarks, value.MultiPalmDetections, value.MultiPalmRects, true); - } -} diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs.meta b/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs.meta deleted file mode 100644 index 16e5a2bba..000000000 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingGraph.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: bf727f801974b69dd9593f712166a50b -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs b/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs deleted file mode 100644 index 79722f58d..000000000 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs +++ /dev/null @@ -1,16 +0,0 @@ -using Mediapipe; -using System.Collections.Generic; - -class MultiHandTrackingValue { - public readonly List MultiHandLandmarks; - public readonly List MultiPalmDetections; - public readonly List MultiPalmRects; - - public MultiHandTrackingValue(List landmarks, List detections, List rects) { - MultiHandLandmarks = landmarks; - MultiPalmDetections = detections; - MultiPalmRects = rects; - } - - public MultiHandTrackingValue(List landmarks) : this(landmarks, new List(), new List()) {} -} diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs.meta b/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs.meta deleted file mode 100644 index 3d871aaad..000000000 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingValue.cs.meta +++ /dev/null @@ -1,11 +0,0 @@ -fileFormatVersion: 2 -guid: f9efda9b5360f067989a36e4b5f09899 -MonoImporter: - externalObjects: {} - serializedVersion: 2 - defaultReferences: [] - executionOrder: 0 - icon: {instanceID: 0} - userData: - assetBundleName: - assetBundleVariant: diff --git a/Assets/MediaPipe/SDK/Scripts/Format.cs b/Assets/MediaPipe/SDK/Scripts/Format.cs index dc029d2b2..5cc78d084 100644 --- a/Assets/MediaPipe/SDK/Scripts/Format.cs +++ b/Assets/MediaPipe/SDK/Scripts/Format.cs @@ -13,7 +13,7 @@ public class Format { /// but in the returned array, left to right, top to bottom. /// public static NativeArray FromPixels32(Color32[] colors, int width, int height, bool isFlipped = false, Allocator allocator = Allocator.Temp) { - var pixelData = new NativeArray(colors.Length * 3, allocator, NativeArrayOptions.UninitializedMemory); + var pixelData = new NativeArray(colors.Length * 4, allocator, NativeArrayOptions.UninitializedMemory); unsafe { fixed (Color32* src = colors) { @@ -26,6 +26,7 @@ public static NativeArray FromPixels32(Color32[] colors, int width, int he *pDest++ = pSrc->r; *pDest++ = pSrc->g; *pDest++ = pSrc->b; + *pDest++ = pSrc->a; pSrc--; } } else { @@ -38,6 +39,7 @@ public static NativeArray FromPixels32(Color32[] colors, int width, int he *pDest++ = pRowSrc->r; *pDest++ = pRowSrc->g; *pDest++ = pRowSrc->b; + *pDest++ = pRowSrc->a; pRowSrc++; } } diff --git a/Assets/MediaPipe/SDK/Scripts/Framework/Formats/ImageFrame.cs b/Assets/MediaPipe/SDK/Scripts/Framework/Formats/ImageFrame.cs index 56fb27997..b8a8ff76d 100644 --- a/Assets/MediaPipe/SDK/Scripts/Framework/Formats/ImageFrame.cs +++ b/Assets/MediaPipe/SDK/Scripts/Framework/Formats/ImageFrame.cs @@ -149,7 +149,7 @@ public Color32[] GetColor32s(bool isFlipped = false) { } public static ImageFrame FromPixels32(Color32[] colors, int width, int height, bool isFlipped = false) { - return new ImageFrame(ImageFormat.Format.SRGB, width, height, 3 * width, Mediapipe.Format.FromPixels32(colors, width, height, isFlipped)); + return new ImageFrame(ImageFormat.Format.SRGBA, width, height, 4 * width, Mediapipe.Format.FromPixels32(colors, width, height, isFlipped)); } private delegate MpReturnCode CopyToBufferHandler(IntPtr ptr, IntPtr buffer, int bufferSize); diff --git a/Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs b/Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs new file mode 100644 index 000000000..a04ea17ae --- /dev/null +++ b/Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs @@ -0,0 +1,22 @@ +using System; +using System.Collections.Generic; + +namespace Mediapipe { + public class ClassificationListVectorPacket : Packet> { + public ClassificationListVectorPacket() : base() {} + + public override List Get() { + UnsafeNativeMethods.mp_Packet__GetClassificationListVector(mpPtr, out var serializedProtoVectorPtr).Assert(); + GC.KeepAlive(this); + + var detections = Protobuf.DeserializeProtoVector(serializedProtoVectorPtr, ClassificationList.Parser); + UnsafeNativeMethods.mp_api_SerializedProtoVector__delete(serializedProtoVectorPtr); + + return detections; + } + + public override StatusOr> Consume() { + throw new NotSupportedException(); + } + } +} diff --git a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs.meta b/Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs.meta similarity index 83% rename from Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs.meta rename to Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs.meta index d23f4a0e5..4a960d9ae 100644 --- a/Assets/MediaPipe/Examples/Scripts/HandTracking/MultiHandTrackingAnnotationController.cs.meta +++ b/Assets/MediaPipe/SDK/Scripts/Framework/Packet/ClassificationListVectorPacket.cs.meta @@ -1,5 +1,5 @@ fileFormatVersion: 2 -guid: 52378be1b2ebb49b294c6e5d2fcf0a25 +guid: c078b368cd8dfd66fba14dce3e749bcc MonoImporter: externalObjects: {} serializedVersion: 2 diff --git a/Assets/MediaPipe/SDK/Scripts/PInvoke/NativeMethods/External/Protobuf_Unsafe.cs b/Assets/MediaPipe/SDK/Scripts/PInvoke/NativeMethods/External/Protobuf_Unsafe.cs index 02d2e6d65..885f3547a 100644 --- a/Assets/MediaPipe/SDK/Scripts/PInvoke/NativeMethods/External/Protobuf_Unsafe.cs +++ b/Assets/MediaPipe/SDK/Scripts/PInvoke/NativeMethods/External/Protobuf_Unsafe.cs @@ -16,6 +16,9 @@ internal static partial class UnsafeNativeMethods { [DllImport (MediaPipeLibrary, ExactSpelling = true)] public static extern MpReturnCode mp_Packet__GetClassificationList(IntPtr packet, out IntPtr serializedProto); + [DllImport (MediaPipeLibrary, ExactSpelling = true)] + public static extern MpReturnCode mp_Packet__GetClassificationListVector(IntPtr packet, out IntPtr serializedProto); + [DllImport (MediaPipeLibrary, ExactSpelling = true)] public static extern MpReturnCode mp_Packet__GetDetection(IntPtr packet, out IntPtr serializedProto); diff --git a/C/WORKSPACE b/C/WORKSPACE index ec9a8909c..15f6048af 100644 --- a/C/WORKSPACE +++ b/C/WORKSPACE @@ -7,6 +7,7 @@ workspace(name = "mediapipe_api") # - exception: opencv_linux # - android_opencv sha256 is added # - unity dependency +# - rules_pkg load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") @@ -18,17 +19,16 @@ http_archive( sha256 = "1dde365491125a3db70731e25658dfdd3bc5dbdfd11b840b3e987ecf043c7ca0", ) load("@bazel_skylib//lib:versions.bzl", "versions") +versions.check(minimum_bazel_version = "3.4.0") http_archive( name = "rules_pkg", - url = "https://github.com/bazelbuild/rules_pkg/releases/download/0.2.5/rules_pkg-0.2.5.tar.gz", - sha256 = "352c090cc3d3f9a6b4e676cf42a6047c16824959b438895a76c2989c6d7c246a", + url = "https://github.com/bazelbuild/rules_pkg/releases/download/0.3.0/rules_pkg-0.3.0.tar.gz", + sha256 = "6b5969a7acd7b60c02f816773b06fcf32fbe8ba0c7919ccdc2df4f8fb923804a", ) load("@rules_pkg//:deps.bzl", "rules_pkg_dependencies") rules_pkg_dependencies() -versions.check(minimum_bazel_version = "2.0.0") - new_local_repository( name = "unity", build_file = "@//third_party:unity.BUILD", @@ -38,8 +38,8 @@ new_local_repository( # mediapipe http_archive( name = "com_google_mediapipe", - sha256 = "99915c8d5049a6d03771821b271366257b0a4109f1d357b30f0e740fe50d2bd2", - strip_prefix = "mediapipe-0.7.11", + sha256 = "0b129a28864fd2cd2822948621645efb9d62b6d043d1c4da3cf2d01886bfd901", + strip_prefix = "mediapipe-0.8.0", patches = [ "@//third_party:mediapipe_visibility.diff", "@//third_party:mediapipe_model_path.diff", @@ -48,7 +48,7 @@ http_archive( patch_args = [ "-p1", ], - urls = ["https://github.com/google/mediapipe/archive/v0.7.11.tar.gz"], + urls = ["https://github.com/google/mediapipe/archive/0.8.0.tar.gz"], ) # ABSL cpp library lts_2020_02_25 @@ -363,8 +363,9 @@ maven_install( "androidx.lifecycle:lifecycle-common:2.2.0", "androidx.annotation:annotation:aar:1.1.0", "androidx.appcompat:appcompat:aar:1.1.0-rc01", - "androidx.camera:camera-core:aar:1.0.0-alpha06", - "androidx.camera:camera-camera2:aar:1.0.0-alpha06", + "androidx.camera:camera-core:1.0.0-beta10", + "androidx.camera:camera-camera2:1.0.0-beta10", + "androidx.camera:camera-lifecycle:1.0.0-beta10", "androidx.constraintlayout:constraintlayout:aar:1.1.3", "androidx.core:core:aar:1.1.0-rc03", "androidx.legacy:legacy-support-v4:aar:1.0.0", @@ -376,6 +377,7 @@ maven_install( "com.google.flogger:flogger-system-backend:0.3.1", "com.google.flogger:flogger:0.3.1", "com.google.guava:guava:27.0.1-android", + "com.google.guava:listenablefuture:1.0", "junit:junit:4.12", "org.hamcrest:hamcrest-library:1.3", ], @@ -401,9 +403,9 @@ http_archive( ) #Tensorflow repo should always go after the other external dependencies. -# 2020-08-30 -_TENSORFLOW_GIT_COMMIT = "57b009e31e59bd1a7ae85ef8c0232ed86c9b71db" -_TENSORFLOW_SHA256= "de7f5f06204e057383028c7e53f3b352cdf85b3a40981b1a770c9a415a792c0e" +# 2020-10-30 +_TENSORFLOW_GIT_COMMIT = "84384703c0d8b502e33ff6fd7eefd219dca5ff8e" +_TENSORFLOW_SHA256= "23fb322fc15a20f7a7838d9a31f8b16f60700a494ea654311a0aa8621769df98" http_archive( name = "org_tensorflow", urls = [ diff --git a/C/mediapipe_api/BUILD b/C/mediapipe_api/BUILD index 0b976acf7..904810642 100644 --- a/C/mediapipe_api/BUILD +++ b/C/mediapipe_api/BUILD @@ -50,23 +50,20 @@ cc_library( "@com_google_mediapipe//mediapipe/calculators/core:packet_presence_calculator", ] + select({ "@com_google_mediapipe//mediapipe/gpu:disable_gpu": [ - "@com_google_mediapipe//mediapipe/graphs/face_detection:desktop_tflite_calculators", + "@com_google_mediapipe//mediapipe/graphs/face_detection:desktop_live_calculators", "@com_google_mediapipe//mediapipe/graphs/face_mesh:desktop_live_calculators", - "@com_google_mediapipe//mediapipe/graphs/iris_tracking:iris_tracking_cpu_deps", "@com_google_mediapipe//mediapipe/graphs/hand_tracking:desktop_tflite_calculators", - "@com_google_mediapipe//mediapipe/graphs/hand_tracking:multi_hand_desktop_tflite_calculators", + "@com_google_mediapipe//mediapipe/graphs/iris_tracking:iris_tracking_cpu_deps", "@com_google_mediapipe//mediapipe/graphs/pose_tracking:upper_body_pose_tracking_cpu_deps", - # "@com_google_mediapipe//mediapipe/graphs/hair_segmentation:desktop_calculators", "@com_google_mediapipe//mediapipe/graphs/object_detection:desktop_tflite_calculators", ], "//conditions:default": [ - "@com_google_mediapipe//mediapipe/graphs/face_detection:mobile_calculators", + "@com_google_mediapipe//mediapipe/graphs/face_detection:desktop_live_gpu_calculators", "@com_google_mediapipe//mediapipe/graphs/face_mesh:desktop_live_gpu_calculators", - "@com_google_mediapipe//mediapipe/graphs/iris_tracking:iris_tracking_gpu_deps", + "@com_google_mediapipe//mediapipe/graphs/hair_segmentation:mobile_calculators", "@com_google_mediapipe//mediapipe/graphs/hand_tracking:mobile_calculators", - "@com_google_mediapipe//mediapipe/graphs/hand_tracking:multi_hand_mobile_calculators", + "@com_google_mediapipe//mediapipe/graphs/iris_tracking:iris_tracking_gpu_deps", "@com_google_mediapipe//mediapipe/graphs/pose_tracking:upper_body_pose_tracking_gpu_deps", - "@com_google_mediapipe//mediapipe/graphs/hair_segmentation:mobile_calculators", "@com_google_mediapipe//mediapipe/graphs/object_detection:mobile_calculators", ], }), @@ -90,13 +87,12 @@ pkg_model( "@com_google_mediapipe//mediapipe/models:face_detection_front_labelmap.txt", "@com_google_mediapipe//mediapipe/models:face_landmark.tflite", "@com_google_mediapipe//mediapipe/models:hair_segmentation.tflite", - "@com_google_mediapipe//mediapipe/models:hand_landmark.tflite", - "@com_google_mediapipe//mediapipe/models:handedness.txt", - "@com_google_mediapipe//mediapipe/models:iris_landmark.tflite", - "@com_google_mediapipe//mediapipe/models:palm_detection.tflite", - "@com_google_mediapipe//mediapipe/models:palm_detection_labelmap.txt", "@com_google_mediapipe//mediapipe/models:ssdlite_object_detection.tflite", "@com_google_mediapipe//mediapipe/models:ssdlite_object_detection_labelmap.txt", + "@com_google_mediapipe//mediapipe/modules/hand_landmark:hand_landmark.tflite", + "@com_google_mediapipe//mediapipe/modules/hand_landmark:handedness.txt", + "@com_google_mediapipe//mediapipe/modules/iris_landmark:iris_landmark.tflite", + "@com_google_mediapipe//mediapipe/modules/palm_detection:palm_detection.tflite", "@com_google_mediapipe//mediapipe/modules/pose_detection:pose_detection.tflite", "@com_google_mediapipe//mediapipe/modules/pose_landmark:pose_landmark_upper_body.tflite", ], diff --git a/C/mediapipe_api/framework/formats/classification.cc b/C/mediapipe_api/framework/formats/classification.cc index f481c00fe..eb66d5d4d 100644 --- a/C/mediapipe_api/framework/formats/classification.cc +++ b/C/mediapipe_api/framework/formats/classification.cc @@ -3,3 +3,7 @@ MpReturnCode mp_Packet__GetClassificationList(mediapipe::Packet* packet, mp_api::SerializedProto** value_out) { return mp_Packet__GetSerializedProto(packet, value_out); } + +MpReturnCode mp_Packet__GetClassificationListVector(mediapipe::Packet* packet, mp_api::SerializedProtoVector** value_out) { + return mp_Packet__GetSerializedProtoVector(packet, value_out); +} diff --git a/C/mediapipe_api/framework/formats/classification.h b/C/mediapipe_api/framework/formats/classification.h index 0a54fdecb..d94fe9c41 100644 --- a/C/mediapipe_api/framework/formats/classification.h +++ b/C/mediapipe_api/framework/formats/classification.h @@ -9,6 +9,7 @@ extern "C" { MP_CAPI(MpReturnCode) mp_Packet__GetClassificationList(mediapipe::Packet* packet, mp_api::SerializedProto** value_out); +MP_CAPI(MpReturnCode) mp_Packet__GetClassificationListVector(mediapipe::Packet* packet, mp_api::SerializedProtoVector** value_out); } // extern "C" diff --git a/C/mediapipe_api/java/com/google/mediapipe/mediapipe_aar.bzl b/C/mediapipe_api/java/com/google/mediapipe/mediapipe_aar.bzl index b17111eeb..25bf7e67b 100644 --- a/C/mediapipe_api/java/com/google/mediapipe/mediapipe_aar.bzl +++ b/C/mediapipe_api/java/com/google/mediapipe/mediapipe_aar.bzl @@ -94,7 +94,8 @@ cat > $(OUTS) <