Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 3 additions & 2 deletions WORKSPACE
Original file line number Diff line number Diff line change
Expand Up @@ -176,8 +176,9 @@ http_archive(
#### Will be used on feature release
git_repository(
name = "mediapipe",
remote = "https://github.com/openvinotoolkit/mediapipe",
commit = "12e8d511cfbc5f471c498278a65a02dd250963e8", # top of mediapipe main branch as of 26.11.2025
remote = "https://github.com/Vishwa2684/mediapipe_ovms",
# commit = "12e8d511cfbc5f471c498278a65a02dd250963e8", # top of mediapipe main branch as of 26.11.2025
branch = "custom_bytetrack_graph"
)

# DEV mediapipe 1 source - adjust local repository path for build
Expand Down
107 changes: 107 additions & 0 deletions demos/mediapipe/bytetrack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
# ByteTrack Demo Setup

## 1. Download the YOLOX Tiny ONNX Model

Download the YOLOX Tiny ONNX model from the official release:

https://github.com/Megvii-BaseDetection/YOLOX/releases/download/0.1.1rc0/yolox_tiny.onnx

---

## 2. Convert the ONNX Model to TensorFlow Lite

Open a Google Colab notebook and:

1. Install `onnx2tf`.
2. Upload `yolox_tiny.onnx` to the notebook.
3. Run:

```bash
!onnx2tf -i yolox_tiny.onnx -o yolox_tiny
```

This generates the TensorFlow Lite model.

---

## 3. Download COCO Class Labels

Download the COCO 80-class label file:

https://raw.githubusercontent.com/openvinotoolkit/open_model_zoo/master/data/dataset_classes/coco_80cl.txt

---

# Running the Demo

## 1. Start the OpenVINO Model Server

```bash
docker run -d \
-v $PWD:/demo \
-p 9000:9000 \
openvino/model_server:latest \
--config_path /demo/config.json \
--port 9000
```

---

## 2. Create an RTSP Input Stream

Use FFmpeg to publish your webcam as an RTSP stream.

```bash
ffmpeg -f dshow -video_size 1280x720 \
-i video="HP True Vision FHD Camera" \
-f rtsp -rtsp_transport tcp \
rtsp://localhost:8554/channel1
```

> **Work in Progress:** The following H.264-based streaming command is still being evaluated and may not work correctly in all setups.

```bash
ffmpeg -f dshow \
-video_size 1280x720 \
-framerate 30 \
-i video="HP True Vision FHD Camera" \
-c:v libx264 \
-crf 18 \
-preset veryfast \
-f rtsp \
-rtsp_transport tcp \
rtsp://localhost:8554/channel1
```

---

## 3. Run the Real-Time Stream Analysis Client

```bash
python client.py \
--grpc_address localhost:9000 \
--input_stream rtsp://localhost:8554/channel1 \
--output_stream rtsp://localhost:8554/channel2 \
--model_name ByteTrack \
--input_name input_video
```

---

## 4. View the Output Stream

**Option 1 (recommended):**

```bash
ffplay -rtsp_transport tcp \
-vf "scale=704:704,format=yuv420p" \
rtsp://localhost:8554/channel2
```

**Option 2 (verbose logging):**

```bash
ffplay -loglevel verbose \
-rtsp_transport tcp \
rtsp://localhost:8554/channel2
```
127 changes: 127 additions & 0 deletions demos/mediapipe/bytetrack/bytetrack_ovms.pbtxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
input_stream: "IMAGE:input_video"
output_stream: "IMAGE:output"

node: {
calculator: "ImageTransformationCalculator"
input_stream: "IMAGE:input_video"
output_stream: "IMAGE:transformed_input_video"
node_options: {
[type.googleapis.com/mediapipe.ImageTransformationCalculatorOptions] {
output_width: 416
output_height: 416
}
}
}

node {
calculator: "OpenVINOConverterCalculator"
input_stream: "IMAGE:transformed_input_video"
output_stream: "TENSORS:image_tensor"
node_options: {
[type.googleapis.com/mediapipe.OpenVINOConverterCalculatorOptions] {
enable_normalization: true
use_custom_normalization: true
custom_div: 1.0
custom_sub: 0.0
}
}
}
# 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: "OpenVINOModelServerSessionCalculator"
output_side_packet: "SESSION:session"
node_options: {
[type.googleapis.com/mediapipe.OpenVINOModelServerSessionCalculatorOptions]: {
servable_name: "yoloxt_float32" # servable name inside OVMS
servable_version: "1"
}
}
}

node {
calculator: "OpenVINOInferenceCalculator"
input_side_packet: "SESSION:session"
input_stream: "OVTENSORS:image_tensor"
output_stream: "OVTENSORS2:detection_tensors"
node_options: {
[type.googleapis.com/mediapipe.OpenVINOInferenceCalculatorOptions]: {
input_order_list :["images"]
output_order_list :["output"]
}
}
}

### WRITE YOLO SPECIFIC CALCULATORS

node{
calculator: "OpenVINOYoloXTensorsToDetectionsCalculator"
input_stream: "TENSORS:detection_tensors"
output_stream: "DETECTIONS:detections"
node_options: {
[type.googleapis.com/mediapipe.OpenVINOYoloXTensorsToDetectionsCalculatorOptions] {
conf_thresh: 0.1
}
}
}

# 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.45
max_num_detections: 100
overlap_type: INTERSECTION_OVER_UNION
return_empty_detections: true
}
}
}


# Maps detection label IDs to the corresponding label text. The label map is
# provided in the label_map_path option.
node {
calculator: "DetectionLabelIdToTextCalculator"
input_stream: "filtered_detections"
output_stream: "output_detections"
node_options: {
[type.googleapis.com/mediapipe.DetectionLabelIdToTextCalculatorOptions] {
label_map_path: "/demo/coco_80cl.txt"
}
}
}

node {
calculator: "ByteTrackCalculator"
input_stream: "DETECTIONS:output_detections"
output_stream: "DETECTIONS:tracked_detections"
options: {
[mediapipe.ByteTrackCalculatorOptions.ext] {
track_high_threshold:0.7
track_low_threshold:0.55
new_track_threshold:0.35
matching_threshold: 0.8
track_buffer: 60
fuse_score: false
}
}
}

# Converts the detections to drawing primitives for annotation overlay.
node {
calculator: "DetectionColorByIdCalculator"
input_stream: "DETECTIONS:tracked_detections"
output_stream: "RENDER_DATA:detections_render_data"
}

# Draws annotations and overlays them on top of the input images.
node {
calculator: "AnnotationOverlayCalculator"
input_stream: "IMAGE:input_video"
input_stream: "detections_render_data"
output_stream: "IMAGE:output"
}
16 changes: 16 additions & 0 deletions demos/mediapipe/bytetrack/config.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
{
"model_config_list": [
{"config": {
"name": "yoloxt_float32",
"base_path": "yolox_tiny_float32"
}
}
],
"mediapipe_config_list": [
{
"name":"ByteTrack",
"base_path":"./",
"graph_path":"bytetrack_ovms.pbtxt"
}
]
}
4 changes: 3 additions & 1 deletion demos/real_time_stream_analysis/python/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@

parser = argparse.ArgumentParser()
parser.add_argument('--grpc_address', required=False, default='localhost:9022', help='Specify url to grpc service')
parser.add_argument('--ffmpeg_output_width', required=False, default=None, type=int, help='Width of the output video')
parser.add_argument('--ffmpeg_output_height', required=False, default=None, type=int, help='Height of the output video')
parser.add_argument('--input_stream', required=False, default="rtsp://localhost:8080/channel1", type=str, help='Url of input rtsp stream')
parser.add_argument('--output_stream', required=False, default="rtsp://localhost:8080/channel2", type=str, help='Url of output rtsp stream')
parser.add_argument('--model_name', required=False, default="holisticTracking", type=str, help='Name of the model')
Expand Down Expand Up @@ -54,6 +56,6 @@ def postprocess(frame, result):
backend = StreamClient.OutputBackends.cv2
exact = True

client = StreamClient(postprocess_callback = postprocess, preprocess_callback=preprocess, output_backend=backend, source=args.input_stream, sink=args.output_stream, exact=exact, benchmark=args.benchmark, verbose=args.verbose)
client = StreamClient(postprocess_callback = postprocess, preprocess_callback=preprocess, output_backend=backend, source=args.input_stream, sink=args.output_stream, exact=exact, benchmark=args.benchmark, verbose=args.verbose,ffmpeg_output_width=args.ffmpeg_output_width, ffmpeg_output_height=args.ffmpeg_output_height)
client.start(ovms_address=args.grpc_address, input_name=args.input_name, model_name=args.model_name, datatype = StreamClient.Datatypes.uint8, batch = False, limit_stream_duration = args.limit_stream_duration, limit_frames = args.limit_frames, streaming_api=True)

2 changes: 2 additions & 0 deletions third_party/mediapipe_calculators/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,8 @@ cc_library(
"@mediapipe//mediapipe/calculators/video:box_detector_calculator",
"@mediapipe//mediapipe/calculators/video:tracked_detection_manager_calculator",
"@mediapipe//mediapipe/calculators/video:video_pre_stream_calculator",
#BYTETRACK CALCULATORS (GSoC'2026 - Vishwa2684)
"@mediapipe//mediapipe/graphs/bytetrack/calculators:bytetrack_calculators",
] + select({
"//conditions:default": [
"@mediapipe//mediapipe/calculators/core:packet_cloner_calculator", # TODO windows: stdc++20 required
Expand Down