Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
58ae1cc
Use Vishwa2684/mediapipe_ovms for bytetrack demo
Vishwa2684 Jul 14, 2026
ed27dc3
Add ffmpeg_output width and height as client params for rtsp sink
Vishwa2684 Jul 14, 2026
1ad498f
Added bytetrack demo which can be used with RTSP
Vishwa2684 Jul 14, 2026
dc02a3a
Merge branch 'openvinotoolkit:main' into gsoc_bytetrack
Vishwa2684 Jul 14, 2026
4ec3459
Using input_video instead of transformed_input_video for overlay
Vishwa2684 Jul 23, 2026
89e096e
Update docs
Vishwa2684 Jul 23, 2026
f1615da
add logic to check timestamps
Vishwa2684 Aug 6, 2026
155f27e
formatting in client.py
Vishwa2684 Aug 11, 2026
fdb2dac
Write a custom calculator to process yolox tiny's ov tensors
Vishwa2684 Aug 12, 2026
a7a25d9
Move bytetrack logic from seperate mediapipe repo to OVMS
Vishwa2684 Aug 13, 2026
7524ee6
Add license headers to files
Vishwa2684 Aug 13, 2026
d2d0703
Updated spelling-whitelist.txt
Vishwa2684 Aug 19, 2026
a845c7b
Merge branch 'main' into gsoc_bytetrack
Vishwa2684 Aug 20, 2026
0369140
Update README
Vishwa2684 Aug 20, 2026
0610240
Add ByteTrack calculators to WhitelistRegistered.MediapipeCalculators…
Vishwa2684 Aug 24, 2026
cc871ad
Merge branch 'main' into gsoc_bytetrack
Vishwa2684 Aug 24, 2026
6e96f00
Merge branch 'main' into gsoc_bytetrack
Vishwa2684 Aug 26, 2026
d8f82c5
add os.makedirs to create directory
Vishwa2684 Aug 26, 2026
8edaf6d
Merge branch 'gsoc_bytetrack' of https://github.com/Vishwa2684/model_…
Vishwa2684 Aug 26, 2026
edde13f
Minor change in README
Vishwa2684 Aug 26, 2026
c3eb6af
Remove removed_stracks_ in ByteTrackCalculator
Vishwa2684 Aug 26, 2026
76e1bbf
use atomic variable for counter to prevent data race
Vishwa2684 Aug 27, 2026
d413dd6
Refactor LinearAssignment to improve condition checks for column assi…
Vishwa2684 Aug 29, 2026
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
1 change: 1 addition & 0 deletions ci/lib_search.py
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ def check_dir(start_dir):
'ovms-c/dist',
'requirements.txt',
'requirements_win.txt',
'bytetrack_ovms.pbtxt',
'resnet_images.txt',
"resnet_labels.txt",
'rest_sdk_v2.10.16.patch',
Expand Down
70 changes: 70 additions & 0 deletions demos/mediapipe/bytetrack/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
# ByteTrack Demo Setup

End-to-end demo: video source (webcam / file) → OpenVINO Model Server (YOLOX Tiny + ByteTrack) → output (screen / file).

---

## Steps

### 1. Clone the repository

Clone the repository, switch to the `gsoc_bytetrack` branch, and move into the demo directory:

```bash
git clone https://github.com/Vishwa2684/model_server
cd model_server
git checkout gsoc_bytetrack
cd demos/mediapipe/bytetrack
```

### 2. Install requirements

Install all the Python dependencies needed by the client and the model download script. Run this from inside the `demos/mediapipe/bytetrack` directory:

```bash
pip install -r requirements.txt
```

### 3. Download a model

Download the detector model that the OpenVINO Model Server will use. This same command also fetches the COCO class list used for labeling detections:

```bash
python download_models.py --model OpenVINO/yolox_tiny-fp16-ov
```

> Swap `--model-repo` for any of the repo IDs listed below to use a different YOLOX size.

| Model | HuggingFace Repo |
|---|---|
| YOLOX-Tiny (fp16 precision)| `OpenVINO/yolox_tiny-fp16-ov` |
| YOLOX-Tiny (int8 precision)| `OpenVINO/yolox_tiny-int8-ov` |
Comment thread
Vishwa2684 marked this conversation as resolved.

`yolox_tiny-fp16-ov` is the default used in this demo.

This step populates the local model directory that `config.json` (used by the OpenVINO Model Server in step 4) points to, and that ByteTrack consumes downstream for tracking.

### 4. Start the OpenVINO Model Server

Bring up the OpenVINO Model Server as a Docker container. This mounts your current directory into the container so it can read `config.json`, and exposes port 9000 for the client to connect to:

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

Leave this container running in the background — the client in the next step connects to it over gRPC.

### 5. Run the demo — local webcam → screen

With the model server running, run the client script. This reads directly from your local webcam, runs it through detection + ByteTrack tracking, and renders the annotated output live in a window on your screen:

```bash
cd ../../real_time_stream_analysis/python
python client.py --grpc_address localhost:9000 --input_stream 0 --output_stream screen --model_name ByteTrack --input_name input_video
```

- `--grpc_address localhost:9000` — address of the OpenVINO Model Server started in step 4.
- `--input_stream 0` — camera device ID `0` (use `1`, `2`, etc. if you have multiple cameras and want a different one).
- `--output_stream screen` — opens a live preview window instead of writing to a file or stream.

A window should open showing your webcam feed with tracked bounding boxes drawn on it in real time. To use different input and output streams for real time. Read the documentation on [real time stream analysis](../../real_time_stream_analysis/python/README.md)
138 changes: 138 additions & 0 deletions demos/mediapipe/bytetrack/bytetrack_ovms.pbtxt
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
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
}
}
}

node {
calculator: "OpenVINOModelServerSessionCalculator"
output_side_packet: "SESSION:session"
node_options: {
[type.googleapis.com/mediapipe.OpenVINOModelServerSessionCalculatorOptions]: {
servable_name: "yolox_tiny-fp16-ov" # 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 :["image"]
output_order_list :["boxes","labels"]
}
}
}

### OpenVINOYoloXTensorsToDetectionsCalculator was developed for TFLite specific model, but we can use OVYoloXTensorsToDetectionsCalculator for OpenVINO model.

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

node {
calculator: "OVYoloXTensorsToDetectionsCalculator"
input_stream: "TENSORS:detection_tensors"
output_stream: "DETECTIONS:detections"

node_options: {
[type.googleapis.com/mediapipe.OVYoloXTensorsToDetectionsCalculatorOptions] {
conf_thresh: 0.1
input_size: 416.0
}
}
}

# 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": "yolox_tiny-fp16-ov",
"base_path": "yolox_tiny-fp16-ov"
}
}
],
"mediapipe_config_list": [
{
"name":"ByteTrack",
"base_path":"./",
"graph_path":"bytetrack_ovms.pbtxt"
}
]
}
120 changes: 120 additions & 0 deletions demos/mediapipe/bytetrack/download_models.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
#
# Copyright (c) 2026 Intel Corporation
#
# 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.
#

import glob
import json
import argparse
import os
import openvino as ov
from huggingface_hub import snapshot_download

os.environ["HF_HUB_DISABLE_SYMLINKS_WARNING"] = "1"

parser = argparse.ArgumentParser()
parser.add_argument(
"--model-repo",
default="OpenVINO/yolox_tiny-fp16-ov",
help="Hugging Face model repository",
)
args = parser.parse_args()

MODEL_REPO = args.model_repo
MODEL_NAME = MODEL_REPO.split("/")[-1]
# ---------------------------------------------------------
# 1. Download model
# ---------------------------------------------------------

model_dir = snapshot_download(repo_id=MODEL_REPO)

xml_path = glob.glob(os.path.join(model_dir, "*.xml"))[0]
config_path = os.path.join(model_dir, "config.json")

print("Found IR :", xml_path)
print("Found config:", config_path)


# ---------------------------------------------------------
# 2. Read config.json
# ---------------------------------------------------------

with open(config_path, "r") as f:
config = json.load(f)

print("\nModel config:")
print("model_name :", config.get("model_name"))
print("model_type :", config.get("model_type"))
print("input_type :", config.get("input_dtype"))
print("mean_values:", config.get("mean_values"))
print("scale_values:", config.get("scale_values"))
print("classes:", config.get("labels"))

# ---------------------------------------------------------
# 3. Prepare classes list
# ---------------------------------------------------------
classes = config.get("labels").split(" ")

# ---------------------------------------------------------
# 4. Parse mean and scale values
# ---------------------------------------------------------
mean_values = [float(x) for x in config["mean_values"].split()]
scale_values = [float(x) for x in config["scale_values"].split()]

print("\nParsed preprocessing:")
print("mean :", mean_values)
print("scale:", scale_values)

# ---------------------------------------------------------
# 5. Load OpenVINO model
# ---------------------------------------------------------
core = ov.Core()
model = core.read_model(xml_path)
# ---------------------------------------------------------
# 6. Configure preprocessing
# ---------------------------------------------------------
ppp = ov.preprocess.PrePostProcessor(model)
inp = ppp.input(0)

# Input coming from user/image:
# f32 NHWC
inp.tensor().set_element_type(ov.Type.f32).set_layout(ov.Layout("NHWC"))

# Model expects:
# float32 NCHW
inp.model().set_layout(ov.Layout("NCHW"))

# Preprocessing:

inp.preprocess().convert_element_type(ov.Type.f32).convert_layout(
ov.Layout("NCHW")
).scale(255.0).mean(mean_values).scale(scale_values)
# ---------------------------------------------------------
# 7. Build and save
# ---------------------------------------------------------

model = ppp.build()

output_path = f"{MODEL_NAME}/1/{MODEL_NAME}.xml"
os.makedirs(os.path.dirname(output_path), exist_ok=True)
ov.save_model(model, output_path)

print("\nSaved:", os.path.abspath(output_path))

with open("coco_80cl.txt", "w") as f:
n = len(classes)
for i, c in enumerate(classes):
f.write(c + ("\n" if i < n - 1 else ""))

print("Downloaded successfully")
Binary file added demos/mediapipe/bytetrack/requirements.txt
Binary file not shown.
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)

4 changes: 4 additions & 0 deletions spelling-whitelist.txt
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,10 @@ windows_parse_tests.bat:136: SEH ==> SHE
windows_parse_tests.bat:141: SEH ==> SHE
windows_parse_tests.bat:144: SEH ==> SHE
src/test/llm/output_parsers/gemma4_output_parser_test.cpp
src/test/llm/output_parsers/qwen3_output_parser_test.cpp:719: thi ==> the, this
STrack
strack
nd
src/test/llm/output_parsers/qwen3_output_parser_test.cpp:697: thi ==> the, this
extras/chat_template_examples/chat_template_onyx.jinja
src/test/llm/chat_templates/chat_template_onyx.jinja
2 changes: 2 additions & 0 deletions src/BUILD
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,8 @@ ovms_cc_library(
"//src/image_gen:image_gen_calculator",
"//src/audio/speech_to_text:s2t_calculator",
"//src/audio/text_to_speech:t2s_calculator",
"//src/yolox:ov_yolox_tensors_to_detections_calculator",
"//src/bytetrack/calculators:bytetrack_calculators",
"//src/audio:audio_utils",
"//src/image_gen:imagegen_init",
"//src/llm:openai_responses_handler",
Expand Down
Loading