SORT in one file, and an output folder named two ways
YOLOv7 Object Tracking Using PyTorch, OpenCV and Sort Tracking
At a glance
- What is it?
- yolov7-object-tracking is a two-script wrapper that runs YOLOv7 or YOLOv8 detection through a vendored SORT tracker kept in sort.py at the repository root, with Ultralytics-style flags plus tracking-specific ones, a single --source argument that accepts a webcam index, a camera index or a stream URL, and a contradiction about the output folder that the same page names two different ways.
- Who is it for?
- It fits someone who wants a detection-plus-tracking script they can read in an afternoon, with no framework to install beyond the requirements file and a tracker you can inspect in a single module. Check three things first.
- Can I use it commercially?
- Yes, with strict conditions. AGPL-3.0 is a network copyleft licence: if people use a modified version over a network, for example as a hosted service, you must offer them its source code under the same licence.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 2, 2026, and from our analysis. They are not legal advice.
Editorial analysis
Two entry points and a tracker vendored in the tree
The repository is small enough to describe completely. Two scripts sit at the root, detect.py for detection alone and detect_and_track.py for detection with tracking. The tracker itself is sort.py, in the repository rather than installed from a package, which means the association step is a file you can open and read.
Around those sit models/, utils/, tests/, notebooks/ and requirements.txt, with continuous integration in .github/ and coverage reported through a codecov badge. The notebooks directory is what the Colab, Kaggle and SageMaker Studio import badges point at, so the hosted-notebook path runs the same code rather than a simplified copy.
Keeping the tracker in-tree is the decision worth noticing. It removes a dependency and pins the algorithm to the version in the file, and the price is that improvements to SORT upstream arrive only if someone updates the copy. For a research script that is a reasonable trade; for anything long-lived it is a maintenance decision you inherit.
The tracking dependencies for that file are filterpy and scikit-image, both unpinned in the requirements file.
The output folder is named two different ways
There is a small contradiction on the same page, and it will bite anyone scripting around the output.
The instructions say output files are saved in runs/detect/obj-tracking with the original filename. The argument table, further down, gives the default for --name as runs/detect/object_tracking. Those are different directory names: obj-tracking with a hyphen in one place, object_tracking with underscores in the other.
Since --project defaults to runs/detect and --name is what completes the path, the table's value is the one a reader would expect to find on disk. The instruction's shorter spelling is either stale text or a different default that was never updated.
It matters more than it looks. Anything downstream that globs runs/detect/obj-tracking, a shell script, a notebook, a cleanup job, will silently match nothing, and nothing in the output will tell you the run happened. Pass --name explicitly if you depend on the path.
The behaviour either way is to keep the original input filename, which is helpful when you run the same source twice and want to compare.
Ultralytics flags first, tracking flags appended
The argument table is mostly inherited from the Ultralytics training and detection scripts, and the defaults are recognisable: --weights at yolov7.pt, --img-size at 640, --conf-thres at 0.25, --iou-thres at 0.45, --device defaulting to an empty string that accepts a CUDA index such as 0 or 0,1,2,3 or the literal cpu, and --project defaulting to runs/detect.
Two exclusions are worth noticing in the requirements rather than the arguments: torch is required at or above 1.7.0 with 1.12.0 excluded, and torchvision at or above 0.8.1 with 0.13.0 excluded. Both exclusions exist because those specific releases broke compatibility with the model code, which is the kind of knowledge that is easy to lose and expensive to rediscover.
Four flags exist for tracking rather than detection: --colored-trk assigns a unique colour per track for visualisation, --save-bbox-dim saves bounding box dimensions in the text output, --save-with-object-id writes the object ID into the .txt files, and --save-txt writes results as text at all.
The combination is what turns a detection run into a tracking dataset: --save-txt with --save-bbox-dim and --save-with-object-id gives centroids, IDs and box sizes in one pass.
One --source argument carrying four different things
The source parameter is a single string field with four documented uses, and the type is str in every case.
A file path works. So does a folder. The integer 0 selects the webcam, and the integer 1 selects an external camera, both written as bare numbers after --source rather than in a separate flag. Finally a stream URL is passed as a quoted string, and that example also carries --device 0 to pin the compute device.
The webcam and camera cases are the elegant part: one argument means local camera index, so adding a second camera needs no new code. The cost is that --source has no declared type that covers its uses, since an int and a URL share the field, and validation has to happen at runtime rather than at parse time.
For streams there is one documented example and no further detail, so the URL format, the transport and the reconnection behaviour are whatever the underlying library accepts. Anyone planning a long-running stream should assume that part needs testing rather than reading.
Class filtering takes indices, so you need the label numbers
Filtering by class is done with --classes, typed as a list of integers, with the documented forms being a single value such as --classes 0 or several at once such as --classes 0 2 3.
Zero is given as the worked example, with a person named as the intended target, which pins the convention to the standard COCO ordering where zero is the first class. That is a reasonable default but it means the flag speaks in dataset indices, not in names.
So to track cars and nothing else you need to know which number that is in this particular ordering, and if you later change models the mapping is not guaranteed to be the same across variants. The value is also shared with detection, so a class filter that makes sense for a detection run is the same filter your tracker inherits.
The complement is --agnostic-nms, which switches off class-aware suppression during non-maximum suppression. That is a real knob for crowded scenes where overlapping boxes of the same class suppress each other, and it is worth knowing about because its absence changes results without changing any visible setting.
protobuf is pinned exactly, and it is the old constraint
The requirements file is organised in commented sections, base, tracking, logging, plotting and extras, which makes it readable. Almost everything is a lower bound: matplotlib, numpy, opencv-python, Pillow, PyYAML, requests, scipy, tqdm, tensorboard, pandas and seaborn, with torch and torchvision as above.
Two lines behave differently. protobuf is pinned to exactly 4.25.8, the only hard equality in the file, and setuptools is capped at 81.0.0 with a ceiling rather than a floor. Everything else in the file, including filterpy and scikit-image, is unpinned, so a fresh install resolves to whatever is current.
That combination is worth thinking about. An old exact protobuf pin alongside open-ended torch is a compatibility surface: the pinned version has to work with whatever torch and torchvision a fresh resolve picks, and nothing in the file coordinates that.
Two optional pieces of the requirements are present but inactive: Weights and Biases is listed as a comment in the logging section, and the extras carry ipython for notebooks, psutil for system utilisation and thop for FLOPs computation, none of which the tracking path needs.
One release from 2022, and a roadmap written in the future tense
The release history has one entry, dated 21 August 2022. The last push to the main branch is dated 11 September 2026, so there is a large amount of work that no tag covers, and there is no version to install.
What the current documentation claims is narrower than the roadmap. Ultralytics YOLOv8 support is stated as added, and the mechanism is simply passing different weights to the detection script:
python detect.py --weights yolov8n.ptThen a single line promises YOLOv9, YOLOv10, YOLO11, YOLO12 and YOLO13 support coming soon. Five model generations are promised in one sentence, which is the kind of statement that ages badly, and nothing in the tree says how much of it exists.
The licence is AGPL-3.0, which is the fact to weigh before anything else here. This repository is a working script you can study and adapt, and if you deploy a modified version as a service you are dealing with the copyleft obligations that licence imposes.
For a tracking example to learn from, the in-tree sort.py and the flag list are the parts worth the time.
Editorial conclusion
It fits someone who wants a detection-plus-tracking script they can read in an afternoon, with no framework to install beyond the requirements file and a tracker you can inspect in a single module. Check three things first. The licence is AGPL-3.0, which is the decision to make before anything else, because a tracking script is easy to drop into a product and hard to unlink later. The output directory is named inconsistently in the documentation, so check what actually appears under runs/detect. And there has been exactly one release, dated 21 August 2022, against a last push on 11 September 2026, so the newest model support in the tree is untagged work.
Frequently asked questions
Can YOLO be used for object tracking?
Yes, and this repository is an example of the arrangement. Detection comes from YOLOv7 or YOLOv8 weights, and the association step is SORT, kept in sort.py at the repository root rather than installed as a package. Tracking-specific flags include --colored-trk, --save-with-object-id and --save-bbox-dim.
What is yolov7-object-tracking?
It is a pair of Python scripts, detect.py for detection and detect_and_track.py for detection with tracking, plus a vendored sort.py, models/, utils/, tests/ and notebooks/. The project is written in Python and released under AGPL-3.0, with one release dated 21 August 2022.
How do I run webcam tracking with yolov7-object-tracking?
Pass the camera index as the source, so 0 is the webcam and 1 is an external camera. An IP camera stream URL can be passed the same way together with a device selector, for example a --source URL with --device 0. Output files are written under the runs/detect directory.
Which YOLO versions does yolov7-object-tracking support?
YOLOv7 weights are the default, and YOLOv8 inference is supported by passing Ultralytics weights to the detection script, for example python detect.py --weights yolov8n.pt. The documentation also states that YOLOv9, YOLOv10, YOLO11, YOLO12 and YOLO13 support is coming soon, without indicating how much of it exists.
How do I save track IDs and bounding boxes in yolov7-object-tracking?
Combine --save-txt with --save-bbox-dim and --save-with-object-id, which saves results as text, includes bounding box dimensions, and writes the object ID into those files. Centroids, IDs and box coordinates then come out of a single run.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/rizwanmunawar-yolov7-object-tracking)