{"id":18352495,"url":"https://github.com/stelynx/sofot","last_synced_at":"2025-07-20T22:32:45.647Z","repository":{"id":103097625,"uuid":"339812067","full_name":"stelynx/sofot","owner":"stelynx","description":"Stelynx Optical Flow-based Object Tracker","archived":false,"fork":false,"pushed_at":"2021-02-21T20:21:25.000Z","size":12199,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-10T00:47:09.459Z","etag":null,"topics":["object-detection","object-tracker","object-tracking","opencv","opencv-python","optical-flow"],"latest_commit_sha":null,"homepage":"","language":"TeX","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/stelynx.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-02-17T18:04:00.000Z","updated_at":"2022-01-20T21:24:43.000Z","dependencies_parsed_at":null,"dependency_job_id":"c7644247-0db7-4d01-9f72-f26f61bedcfa","html_url":"https://github.com/stelynx/sofot","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/stelynx/sofot","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stelynx%2Fsofot","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stelynx%2Fsofot/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stelynx%2Fsofot/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stelynx%2Fsofot/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/stelynx","download_url":"https://codeload.github.com/stelynx/sofot/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/stelynx%2Fsofot/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266210835,"owners_count":23893337,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["object-detection","object-tracker","object-tracking","opencv","opencv-python","optical-flow"],"created_at":"2024-11-05T21:36:09.983Z","updated_at":"2025-07-20T22:32:45.629Z","avatar_url":"https://github.com/stelynx.png","language":"TeX","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SOFOT\n\nSOFOT (Stelynx Optical Flow-based Object Tracker) is a simple object\ntracker implemented by Stelynx in Python.\n\n## Table of Contents\n\n- [Setup](#setup)\n- [Datasets](#datasets)\n- [Running](#running)\n- [Algorithm](#algorithm)\n- [License](#license)\n\n## Setup\n\n*SOFOT was developed and tested for Python 3.7.9 on MacBook Pro (16-inch,\n2019), however it should work with any operating system and any Python\n3.x (at least above 3.6). No GPU is required.*\n\nUsage of Python virtual environment is recommended to mitigate version\nconflicts of packages.\n\n```\nvirtualenv venv\nsource venv/bin/activate\n```\n\nSOFOT depends on `numpy`, `scipy`, and `opencv-python`. You can install\nthem via `pip` or your preferred package manager. Mine is `pip`, so you\ncan just run\n\n```\npip install -r requirements.txt\n```\n\n## Datasets\n\nThis projects was initially built for object detection on [MODD1 dataset](https://vision.fe.uni-lj.si/RESEARCH/modd/),\ntherefore the dataset you want to use should follow the same directory\nstructure for you to be able to use it out of the box. The directory\nstructure should be the following:\n\n```\ndata\n  |- dataset_1\n  |    |- video_1\n  |    |    |- images\n  |    |    |    |- 00001.jpg\n  |    |    |    |- 00002.jpg\n  |    |    |    |- ...\n  |    |    |    |- 0000N.jpg\n  |    |    |- gt.mat\n  |    |- video_2\n  |    |    |- images\n  |    |    |- gt.mat\n  |    ...\n  |    |- video_N\n  |    |    |- images\n  |    |    |- gt.mat\n  |- dataset_2\n  ...\nsofot\n```\n\nwhere `gt.mat` is MATLAB file containing `largeobjects` and `smallojects`\nvalues that are `N_FRAMES x 1` cell. Each value in the cell should be `4 x N_OBJECTS`\nmatrix, containing `[x1; y1; x2; y2]` columns for top left and lower\nright corner of bounding box for each object.\n\nFor any other directory structure or annotations file, you must write a\nfunction similar to `get_modd1_data()` in `util.py` and change `get_data(dataset)` to call your function.\n\n### Using MODD1 for testing\n\nYou can use MODD1 for testing or for verification of installation.\nThere is a script `/data/download_datasets.sh` that downloads and prepares\nMODD1 dataset for it to be used by SOFOT. From root of the project execute the following.\n\n```\ncd data\nbash download_datasets.sh\ncd ..\npython sofot/main.py --dataset modd1\n```\n\n## Running\n\nSOFOT's main script is `sofot/main.py`. Bare in mind that SOFOT is meant\nto be run from project root directory!\n\nSOFOT has the following command-line arguments, which can also be printed\nto command line using `python sofot/main.py -h`.\n\n\u003ctable\u003e\n  \u003ctr\u003e\n    \u003cth\u003eArgument\u003c/th\u003e\n    \u003cth\u003eDescription\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e-h\u003c/code\u003e, \u003ccode\u003e--help\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003ePrints help.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--dataset\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003e\u003cb\u003eRequired.\u003c/b\u003e Folder name in \"data\" folder to be used.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--video\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eRun only on this video.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--benchmark\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eRun in benchmark mode, rendering, saving, and debugging is disabled.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--render\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eRender video of frames with bounding boxes.\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--save-bbox\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eSave bounding boxes in files for each frame. Format of bounding box is \"x1 y1 x2 y2\" (upper left and lower right corner).\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd\u003e\u003ccode\u003e--debug\u003c/code\u003e\u003c/td\u003e\n    \u003ctd\u003eRun in debug mode. Stops after each frame is presented and prints debugging information to stdout.\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\nTo run benchmark on all videos in a dataset called `my_dataset`, you would run\n\n```\npython sofot/main.py --dataset my_dataset --benchmark\n```\n\nTo generate a video of frames with bounding boxes and corresponding\nannotations file, but only for video `video_14`, you would run\n\n```\npython sofot/main.py --dataset my_dataset --video video_14 --render --save-bbox\n```\n\n## Algorithm\n\nAlthough the algorithm might seem trivial, it performs marvelously. The\nalgorithm behind SOFOT consists of two phases, **optical flow** for direct\nobject tracking and **enhanced IoU** for mapping of the detections.\nIn the following paragraphs the algorithm is described in greater detail.\n\n### Initialisation\n\nSOFOT starts with given bounding boxes for first frame. Using [Shi-Tomasi\ncorner detection algorithm](https://en.wikipedia.org/wiki/Corner_detection#The_Harris_\u0026_Stephens_/_Shi–Tomasi_corner_detection_algorithms) it extracts good features for tracking inside\nof each bounding box.\n\n### Main loop\n\nOn each iteration, new set of feature points for each object is calculated\nbased on optical flow estimation. This is done using [Lucas-Kanade method](https://en.wikipedia.org/wiki/Lucas–Kanade_method).\n\nAfter all new points have been calculated, new bounding boxes are\ngenerated. Bounding boxes are generated from points simply by taking the\nsmallest rectangle enclosing all the points of the object. For each pair\nin cartesian product of old bounding boxes and new bounding boxes, an\nIoU (intersection over union) is calculated. Every old bounding box is\npaired with a new bounding box so that their IoU is the highest.\n\nWhen IoU matching is over and there are still some unmatched old bounding\nboxes, that means that that old bounding box has IoU = 0 with all the\nnew bounding boxes, which means it either\nexited the frame (in this case it is ignored from hereon), or it has\nmoved so much that it does not overlap with its new bounding box. If it\ndid not exit the frame, the closest bounding box from unmatched new ones\nis found. For steady and slow moving environments like maritime this is\na completely justifiable and on-point assumption, because it is highly\nunlikely that many of the objects being tracked would change their\nposition so drastically inside of one-frame time period that the change\nin detected identity would occur.\n\nOn each iteration, calculated bounding boxes are also compared with\nground-truth ones. An error is reported on screen if there is a detected\nbounding box that does not overlap with any bounding box in annotations.\n\n## Benchmarks\n\nAlgorithm was benchmarked on [MODD1 dataset](https://vision.fe.uni-lj.si/RESEARCH/modd/)\nand it produced extremely good results. We benchmarked frames-per-second processed and errors made and results are in the following table.\n\n\u003ctable style=\"margin: 0 auto\"\u003e\n  \u003ctr\u003e\n    \u003cth style=\"text-align: center\"\u003eVideo\u003c/th\u003e\n    \u003cth style=\"text-align: center\"\u003eFPS\u003c/th\u003e\n    \u003cth style=\"text-align: center\"\u003eerrors (at frame)\u003c/th\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e01\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e144\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e02\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e233\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e03\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e162\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e04\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e240\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e05\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e233\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e06\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e227\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e07\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e245\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e08\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e238\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e09\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e180\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e1 (108/108)\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e10\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e186\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e11\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e238\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n  \u003ctr\u003e\n    \u003ctd style=\"text-align: center\"\u003e12\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e233\u003c/td\u003e\n    \u003ctd style=\"text-align: center\"\u003e0\u003c/td\u003e\n  \u003c/tr\u003e\n\u003c/table\u003e\n\n## License\n\nSOFOT was implemented as a final project for MSc course *Imaging technologies*\n(Advanced Computer Vision) at University of Ljubljana, Faculty of\nElectrical Engineering. It is licensed under [MIT License](LICENSE) and\ntherefore you are free to use this code. If you use it for research,\nplease cite as\n\n```\n@misc{Stelynx_SOFOT,\n  author = {GitHub / Stelynx},\n  title = {{SOFOT - Stelynx Optical Flow-based Object Tracker}},\n  howpublished = {\\url{https://github.com/stelynx/sofot}},\n  note = {Accessed: 2020-02-21}\n}\n```\n\nand for any other project, mentions would be highly appreciated.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstelynx%2Fsofot","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fstelynx%2Fsofot","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fstelynx%2Fsofot/lists"}