129 lines
4.6 KiB
Protocol Buffer Text Format
129 lines
4.6 KiB
Protocol Buffer Text Format
# MediaPipe graph that performs hand tracking on desktop with TensorFlow Lite
|
|
# on CPU.
|
|
# Used in the example in
|
|
# mediapipe/examples/desktop/hand_tracking:hand_tracking_tflite.
|
|
|
|
# max_queue_size limits the number of packets enqueued on any input stream
|
|
# by throttling inputs to the graph. This makes the graph only process one
|
|
# frame per time.
|
|
max_queue_size: 1
|
|
|
|
# Decodes an input video file into images and a video header.
|
|
node {
|
|
calculator: "OpenCvVideoDecoderCalculator"
|
|
input_side_packet: "INPUT_FILE_PATH:input_video_path"
|
|
output_stream: "VIDEO:input_video"
|
|
output_stream: "VIDEO_PRESTREAM:input_video_header"
|
|
}
|
|
|
|
# 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).
|
|
node {
|
|
calculator: "HandLandmarkSubgraph"
|
|
input_stream: "IMAGE:input_video"
|
|
input_stream: "NORM_RECT:hand_rect"
|
|
output_stream: "LANDMARKS:hand_landmarks"
|
|
output_stream: "NORM_RECT:hand_rect_from_landmarks"
|
|
output_stream: "HANDEDNESS:handedness"
|
|
output_stream: "PRESENCE:hand_presence"
|
|
}
|
|
|
|
# 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"
|
|
}
|
|
|
|
# Subgraph that renders annotations and overlays them on top of the input
|
|
# images (see renderer_cpu.pbtxt).
|
|
node {
|
|
calculator: "RendererSubgraph"
|
|
input_stream: "IMAGE:input_video"
|
|
input_stream: "LANDMARKS:hand_landmarks"
|
|
input_stream: "NORM_RECT:hand_rect"
|
|
input_stream: "DETECTIONS:palm_detections"
|
|
input_stream: "HANDEDNESS:handedness"
|
|
output_stream: "IMAGE:output_video"
|
|
}
|
|
|
|
# Encodes the annotated images into a video file, adopting properties specified
|
|
# in the input video header, e.g., video framerate.
|
|
node {
|
|
calculator: "OpenCvVideoEncoderCalculator"
|
|
input_stream: "VIDEO:output_video"
|
|
input_stream: "VIDEO_PRESTREAM:input_video_header"
|
|
input_side_packet: "OUTPUT_FILE_PATH:output_video_path"
|
|
node_options: {
|
|
[type.googleapis.com/mediapipe.OpenCvVideoEncoderCalculatorOptions]: {
|
|
codec: "avc1"
|
|
video_format: "mp4"
|
|
}
|
|
}
|
|
}
|