Skip to content

Commit

Permalink
Restructure as package of tools (with pyproject) (#31)
Browse files Browse the repository at this point in the history
* Add standard python ignore and Mac system files

* Update description and instructions in README for package formulation

* Restructure as package of tools with pyproject

Co-authored-by: Alison Zhong <[email protected]>

---------

Co-authored-by: Alison Zhong <[email protected]>
  • Loading branch information
egrace479 and zhong-al authored Aug 26, 2024
1 parent 4a11bbb commit ce173b4
Show file tree
Hide file tree
Showing 17 changed files with 288 additions and 26 deletions.
168 changes: 166 additions & 2 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
.idea/*
__pycache__/*
mini-scenes/*
leaderboard.png
statistics_giraffes.png
Expand All @@ -8,4 +7,169 @@ statistics_all.png
statistics_g.png
statistics_zg.png
statistics_zp.png
yolov8x.pt
yolov8x.pt

# Standard python ignore files
# Byte-compiled / optimized / DLL files
__pycache__/
*.py[cod]
*$py.class

# C extensions
*.so

# Distribution / packaging
.Python
build/
develop-eggs/
dist/
downloads/
eggs/
.eggs/
lib/
lib64/
parts/
sdist/
var/
wheels/
share/python-wheels/
*.egg-info/
.installed.cfg
*.egg
MANIFEST

# PyInstaller
# Usually these files are written by a python script from a template
# before PyInstaller builds the exe, so as to inject date/other infos into it.
*.manifest
*.spec

# Installer logs
pip-log.txt
pip-delete-this-directory.txt

# Unit test / coverage reports
htmlcov/
.tox/
.nox/
.coverage
.coverage.*
.cache
nosetests.xml
coverage.xml
*.cover
*.py,cover
.hypothesis/
.pytest_cache/
cover/

# Translations
*.mo
*.pot

# Django stuff:
*.log
local_settings.py
db.sqlite3
db.sqlite3-journal

# Flask stuff:
instance/
.webassets-cache

# Scrapy stuff:
.scrapy

# Sphinx documentation
docs/_build/

# PyBuilder
.pybuilder/
target/

# Jupyter Notebook
.ipynb_checkpoints

# IPython
profile_default/
ipython_config.py

# pyenv
# For a library or package, you might want to ignore these files since the code is
# intended to run in multiple environments; otherwise, check them in:
# .python-version

# pipenv
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
# However, in case of collaboration, if having platform-specific dependencies or dependencies
# having no cross-platform support, pipenv may install dependencies that don't work, or not
# install all needed dependencies.
#Pipfile.lock

# poetry
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
# This is especially recommended for binary packages to ensure reproducibility, and is more
# commonly ignored for libraries.
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
#poetry.lock

# pdm
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
#pdm.lock
# pdm stores project-wide configurations in .pdm.toml, but it is recommended to not include it
# in version control.
# https://pdm.fming.dev/#use-with-ide
.pdm.toml

# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
__pypackages__/

# Celery stuff
celerybeat-schedule
celerybeat.pid

# SageMath parsed files
*.sage.py

# Environments
.env
.venv
env/
venv/
ENV/
env.bak/
venv.bak/

# Spyder project settings
.spyderproject
.spyproject

# Rope project settings
.ropeproject

# mkdocs documentation
/site

# mypy
.mypy_cache/
.dmypy.json
dmypy.json

# Pyre type checker
.pyre/

# pytype static type analyzer
.pytype/

# Cython debug symbols
cython_debug/

# PyCharm
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/

# Mac System
.DS_Store
28 changes: 18 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,38 +4,46 @@ This repository contains tools for the KABR dataset preparation.

![](https://user-images.githubusercontent.com/11778655/236357196-c09547fc-0e6b-4b2e-a7a5-18683dc944e5.png)

detector2cvat.py:\

These tools can be installed with:
```
pip install git+https://github.com/Imageomics/kabr-tools
```

Each KABR tool can be run through the command line (as described below) or imported as a python module. They each have help information which can be accessed on the command line through `<tool-name> -h`.

**detector2cvat:**\
Detect objects with Ultralytics YOLO detections, apply SORT tracking and convert tracks to CVAT format.

```
python detector2cvat.py --video path_to_videos --save path_to_save
detector2cvat --video path_to_videos --save path_to_save
```

cvat2ultralytics.py:\
**cvat2ultralytics:**\
Convert CVAT annotations to Ultralytics YOLO dataset.

```
python cvat2ultralytics.py --video path_to_videos --annotation path_to_annotations --dataset dataset_name [--skip skip_frames]
cvat2ultralytics --video path_to_videos --annotation path_to_annotations --dataset dataset_name [--skip skip_frames]
```

tracks_extractor.py:\
**tracks_extractor:**\
Extract mini-scenes from CVAT tracks.

```
python tracks_extractor.py --video path_to_videos --annotation path_to_annotations [--tracking]
tracks_extractor --video path_to_videos --annotation path_to_annotations [--tracking]
```

player.py:\
**player:**\
Player for track and behavior observation.

```
python player.py --folder path_to_folder [--save]
player --folder path_to_folder [--save]
```


cvat2slowfast.py:\
**cvat2slowfast:**\
Convert CVAT annotations to the dataset in Charades format.

```
python cvat2slowfast.py --miniscene path_to_mini_scenes --dataset dataset_name --classes path_to_classes_json --old2new path_to_old2new_json
cvat2slowfast --miniscene path_to_mini_scenes --dataset dataset_name --classes path_to_classes_json --old2new path_to_old2new_json
```
66 changes: 66 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[tool.hatch.build.targets.wheel]
packages = ["src/kabr_tools"]

[tool.hatch.metadata]
allow-direct-references = true

[project]
name = "kabr_tools"
dynamic = ["version"]
authors = [
{ name="Maksim Kholiavchenko", email="[email protected]" },
{ name="Alison Zhong", email="[email protected]" },
{ name="Elizabeth Campolongo", email="[email protected]" },
{ name="Jenna Kline", email="[email protected]" },
]
description = "Tools for working with data for annotating animal behavior. These were specifically designed during construction of the KABR dataset."
readme = "README.md"
requires-python = ">=3.8"
classifiers = [
"Programming Language :: Python :: 3",
"License :: OSI Approved :: MIT License",
]
dependencies = [
"numpy",
"opencv-python",
"scipy",
"lxml",
"tqdm",
"torch",
"natsort",
"ruamel.yaml",
"ultralytics",
"pandas",
]
keywords = [
"annotation",
"cv",
"cvat",
"videos",
"drone videos",
"video classification",
"behavior recognition",
"animal behavior recognition",
"animal behavior",
"mini-scenes",
]

[project.urls]
Documentation = "https://github.com/Imageomics/kabr-tools/blob/master/README.md"
Issues = "https://github.com/Imageomics/kabr-tools/issues"
Source = "https://github.com/Imageomics/kabr-tools"

[project.scripts]
cvat2slowfast = "kabr_tools.cvat2slowfast:main"
cvat2ultralytics = "kabr_tools.cvat2ultralytics:main"
detector2cvat = "kabr_tools.detector2cvat:main"
player = "kabr_tools.player:main"
tracks_extractor = "kabr_tools.tracks_extractor:main"


[tool.hatch.version]
path = "src/kabr_tools/__about__.py"
1 change: 1 addition & 0 deletions src/kabr_tools/__about__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
__version__ = "0.1.0"
3 changes: 3 additions & 0 deletions src/kabr_tools/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from kabr_tools import cvat2slowfast, cvat2ultralytics, detector2cvat, player, tracks_extractor

__all__ = ["cvat2slowfast", "cvat2ultralytics", "detector2cvat", "player", "tracks_extractor"]
6 changes: 5 additions & 1 deletion cvat2slowfast.py → src/kabr_tools/cvat2slowfast.py
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,10 @@ def parse_args():
return local_parser.parse_args()


if __name__ == "__main__":
def main():
args = parse_args()
cvat2slowfast(args.miniscene, args.dataset, args.classes, args.old2new)


if __name__ == "__main__":
main()
6 changes: 5 additions & 1 deletion cvat2ultralytics.py → src/kabr_tools/cvat2ultralytics.py
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,10 @@ def parse_args():
return local_parser.parse_args()


if __name__ == "__main__":
def main():
args = parse_args()
cvat2ultralytics(args.video, args.annotation, args.dataset, args.skip)


if __name__ == "__main__":
main()
15 changes: 10 additions & 5 deletions detector2cvat.py → src/kabr_tools/detector2cvat.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
import argparse
import cv2
from tqdm import tqdm
from src.yolo import YOLOv8
from src.tracker import Tracker, Tracks
from src.object import Object
from src.draw import Draw
from kabr_tools.utils.yolo import YOLOv8
from kabr_tools.utils.tracker import Tracker, Tracks
from kabr_tools.utils.object import Object
from kabr_tools.utils.draw import Draw



def detector2cvat(path_to_videos, path_to_save):
Expand Down Expand Up @@ -113,6 +114,10 @@ def parse_args():
return local_parser.parse_args()


if __name__ == "__main__":
def main():
args = parse_args()
detector2cvat(args.video, args.save)


if __name__ == "__main__":
main()
6 changes: 5 additions & 1 deletion player.py → src/kabr_tools/player.py
Original file line number Diff line number Diff line change
Expand Up @@ -285,6 +285,10 @@ def parse_args():
return local_parser.parse_args()


if __name__ == "__main__":
def main():
args = parse_args()
player(args.folder, args.save)


if __name__ == "__main__":
main()
Loading

0 comments on commit ce173b4

Please sign in to comment.