diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
new file mode 100644
index 00000000..16d41246
--- /dev/null
+++ b/.github/workflows/docs.yml
@@ -0,0 +1,18 @@
+name: Docs WorkFlow
+
+on:
+ push:
+ branches:
+ - master
+ - main
+jobs:
+ deploy:
+ runs-on: ubuntu-latest
+ steps:
+ - uses: actions/checkout@v2
+ - uses: actions/setup-python@v2
+ with:
+ python-version: 3.x
+ - run: pip install mkdocs-material
+ - run: pip install "mkdocstrings[python]"
+ - run: mkdocs gh-deploy --force
\ No newline at end of file
diff --git a/.github/workflows/welcome.yml b/.github/workflows/welcome.yml
index c9bb3f01..a993236c 100644
--- a/.github/workflows/welcome.yml
+++ b/.github/workflows/welcome.yml
@@ -1,3 +1,5 @@
+name: Welcome WorkFlow
+
on:
issues:
types: [opened]
diff --git a/README.md b/README.md
index eb98fb2e..8d73eff3 100644
--- a/README.md
+++ b/README.md
@@ -61,18 +61,6 @@ A set of easy-to-use utils that will come in handy in any Computer Vision projec
pre-release stage. ๐ง Keep your eyes open for potential bugs and be aware that at this stage our API is still fluid
and may change.
-## ๐ฌ videos
-
-Learn how to use YOLOv8, ByteTrack and **Supervision** to detect, track and count objects. ๐ฅ
-[Subscribe](https://www.youtube.com/@Roboflow), and stay up to date with our latest YouTube videos!
-
-
-
-
-
-
-
-
## ๐ป install
Pip install the supervision package in a
@@ -100,9 +88,18 @@ pip install -e ".[dev]"
+## ๐ฌ videos
+Learn how to use YOLOv8, ByteTrack and **Supervision** to detect, track and count objects. ๐ฅ
+[Subscribe](https://www.youtube.com/@Roboflow), and stay up to date with our latest YouTube videos!
-## ๐งน Code Quality
+
+
+
+
+
+
+## ๐งน code quality
We provide two handy commands inside the `Makefile`, namely:
@@ -111,6 +108,10 @@ We provide two handy commands inside the `Makefile`, namely:
So far, **there is no types checking with mypy**. See [issue](https://github.com/roboflow-ai/template-python/issues/4).
-## ๐งช Tests
+## ๐งช tests
[`pytests`](https://docs.pytest.org/en/7.1.x/) is used to run our tests.
+
+## ๐ชช
+
+Supervision is available under the MIT license - see the [LICENSE](https://github.com/roboflow/supervision/blob/main/LICENSE.md) file for details.
\ No newline at end of file
diff --git a/docs/index.md b/docs/index.md
index e69de29b..3f1233af 100644
--- a/docs/index.md
+++ b/docs/index.md
@@ -0,0 +1,36 @@
+
+
+## ๐ hello
+
+A set of easy-to-use utils that will come in handy in any Computer Vision project. **Supervision** is still in
+pre-release stage. ๐ง Keep your eyes open for potential bugs and be aware that at this stage our API is still fluid
+and may change.
+
+## ๐ป install
+
+Pip install the supervision package in a
+[**3.10>=Python>=3.7**](https://www.python.org/) environment.
+
+!!! example "Pip install method (recommended)"
+
+ ```bash
+ pip install subervision
+ ```
+
+!!! example "Git clone method (for development)"
+
+ ```bash
+ git https://github.com/roboflow/supervision.git
+ cd supervision
+ pip install -e '.[dev]'
+ ```
+ See contributing section to know more about contributing to the project
\ No newline at end of file
diff --git a/docs/video.md b/docs/video.md
new file mode 100644
index 00000000..baf61541
--- /dev/null
+++ b/docs/video.md
@@ -0,0 +1,15 @@
+## VideoInfo
+
+:::supervision.video.VideoInfo
+
+## VideoSink
+
+:::supervision.video.VideoSink
+
+## get_video_frames_generator
+
+:::supervision.video.get_video_frames_generator
+
+## process_video
+
+:::supervision.video.process_video
\ No newline at end of file
diff --git a/mkdocs.yml b/mkdocs.yml
index 254462a3..46c257de 100644
--- a/mkdocs.yml
+++ b/mkdocs.yml
@@ -1,4 +1,4 @@
-site_name: supervision
+site_name: Supervision
site_url: https://roboflow.github.io/supervision
site_author: Roboflow
site_description: A set of easy-to-use utils that will come in handy in any Computer Vision project
@@ -9,17 +9,35 @@ copyright: Roboflow 2023. All rights reserved.
extra:
social:
+ - icon: fontawesome/brands/github
+ link: https://github.com/roboflow
- icon: fontawesome/brands/youtube
link: https://www.youtube.com/roboflow
+ - icon: fontawesome/brands/linkedin
+ link: https://www.linkedin.com/company/roboflow-ai/mycompany/
+ - icon: fontawesome/brands/twitter
+ link: https://twitter.com/roboflow
nav:
- Home: index.md
+ - Video: video.md
theme:
name: 'material'
+ logo: https://raw.githubusercontent.com/roboflow/supervision/main/docs/assets/roboflow_logomark_white.svg
+ favicon: https://raw.githubusercontent.com/roboflow/supervision/main/docs/assets/roboflow_logomark_color.svg
palette:
primary: 'deep purple'
accent: 'teal'
font:
text: Roboto
code: Roboto Mono
+
+plugins:
+ - mkdocstrings
+ - search
+
+markdown_extensions:
+ - admonition
+ - pymdownx.details
+ - pymdownx.superfences
diff --git a/setup.py b/setup.py
index fa3a8824..6afc4eaa 100644
--- a/setup.py
+++ b/setup.py
@@ -37,7 +37,8 @@ setuptools.setup(
'pytest',
'wheel',
'notebook',
- 'mkdocs-material'
+ 'mkdocs-material',
+ 'mkdocstrings[python]'
],
},
classifiers=[
diff --git a/supervision/video.py b/supervision/video.py
new file mode 100644
index 00000000..20046535
--- /dev/null
+++ b/supervision/video.py
@@ -0,0 +1,151 @@
+from __future__ import annotations
+
+from typing import Callable, Generator, Optional, Tuple
+
+import cv2
+import numpy as np
+
+
+class VideoInfo:
+ """
+ A class to store video information, including width, height, fps and total number of frames.
+
+ Attributes:
+ width (int): width of the video in pixels
+ height (int): height of the video in pixels
+ fps (int): frames per second of the video
+ total_frames (int, optional): total number of frames in the video, default is None
+
+ Examples:
+ ```python
+ >>> from supervision.video import VideoInfo
+
+ >>> video_info = VideoInfo.from_video_path(video_path='video.mp4')
+
+ >>> video_info
+ VideoInfo(width=3840, height=2160, fps=25, total_frames=538)
+ ```
+ """
+ def __init__(self, width: int, height: int, fps: int, total_frames: Optional[int] = None):
+ self.width = width
+ self.height = height
+ self.fps = fps
+ self.total_frames = total_frames
+
+ @classmethod
+ def from_video_path(cls, video_path: str) -> VideoInfo:
+ video = cv2.VideoCapture(video_path)
+ if not video.isOpened():
+ raise Exception(f"Could not open video at {video_path}")
+
+ width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
+ height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
+ fps = int(video.get(cv2.CAP_PROP_FPS))
+ total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
+ video.release()
+ return VideoInfo(width, height, fps, total_frames)
+
+ @property
+ def resolution(self) -> Tuple[int, int]:
+ return self.width, self.height
+
+
+class VideoSink:
+ """
+ Context manager that saves video frames to a file using OpenCV.
+
+ Attributes:
+ target_path (str): The path to the output file where the video will be saved.
+ video_info (VideoInfo): Information about the video resolution, fps, and total frame count.
+
+ Examples:
+ ```python
+ >>> from supervision.video import VideoInfo
+ >>> from supervision.video import VideoSink
+
+ >>> video_info = VideoInfo.from_video_path(video_path='source_video.mp4')
+
+ >>> with VideoSink(target_path='target_video.mp4', video_info=video_info) as s:
+ ... frame = ...
+ ... s.write_frame(frame=frame)
+ ```
+ """
+
+ def __init__(self, target_path: str, video_info: VideoInfo):
+ self.target_path = target_path
+ self.video_info = video_info
+ self.__fourcc = cv2.VideoWriter_fourcc(*"mp4v")
+ self.__writer = None
+
+ def __enter__(self):
+ self.__writer = cv2.VideoWriter(
+ self.target_path,
+ self.__fourcc,
+ self.video_info.fps,
+ self.video_info.resolution,
+ )
+ return self
+
+ def write_frame(self, frame: np.ndarray):
+ self.__writer.write(frame)
+
+ def __exit__(self, exc_type, exc_val, exc_tb):
+ self.__writer.release()
+
+
+def get_video_frames_generator(source_path: str) -> Generator[np.ndarray, None, None]:
+ """
+ Get a generator that yields the frames of the video.
+
+ Args:
+ source_path (str): The path of the video file.
+
+ Returns:
+ (Generator[np.ndarray, None, None]): A generator that yields the frames of the video.
+
+ Examples:
+ ```python
+ >>> from supervision.video import get_video_frames_generator
+
+ >>> for frame in get_video_frames_generator(source_path='source_video.mp4'):
+ ... ...
+ ```
+ """
+ video = cv2.VideoCapture(source_path)
+ if not video.isOpened():
+ raise Exception(f"Could not open video at {source_path}")
+ success, frame = video.read()
+ while success:
+ yield frame
+ success, frame = video.read()
+ video.release()
+
+
+def process_video(source_path: str, target_path: str, callback: Callable[[np.ndarray, int], np.ndarray]) -> None:
+ """
+ Process a video file by applying a callback function on each frame and saving the result to a target video file.
+
+ Args:
+ source_path (str): The path to the source video file.
+ target_path (str): The path to the target video file.
+ callback (Callable[[np.ndarray, int], np.ndarray]): A function that takes in a numpy ndarray representation of a video frame and an int index of the frame and returns a processed numpy ndarray representation of the frame.
+
+ Examples:
+ ```python
+ >>> from supervision.video import process_video
+
+ >>> def process_frame(frame: np.ndarray) -> np.ndarray:
+ ... ...
+
+ >>> process_video(
+ ... source_path='source_video.mp4',
+ ... target_path='target_video.mp4',
+ ... callback=process_frame
+ ... )
+ ```
+ """
+ source_video_info = VideoInfo.from_video_path(video_path=source_path)
+ with VideoSink(target_path=target_path, video_info=source_video_info) as sink:
+ for index, frame in enumerate(get_video_frames_generator(source_path=source_path)):
+ result_frame = callback(frame, index)
+ sink.write_frame(frame=result_frame)
diff --git a/supervision/video/__init__.py b/supervision/video/__init__.py
deleted file mode 100644
index e69de29b..00000000
diff --git a/supervision/video/dataclasses.py b/supervision/video/dataclasses.py
deleted file mode 100644
index 32fd492d..00000000
--- a/supervision/video/dataclasses.py
+++ /dev/null
@@ -1,46 +0,0 @@
-from __future__ import annotations
-
-from dataclasses import dataclass
-from typing import Optional, Tuple
-
-import cv2
-
-
-@dataclass
-class VideoInfo:
- """
- Data class containing information about the video resolution, fps, and total frame count.
-
- :param width: int : The width of the video frames in pixels.
- :param height: int : The height of the video frames in pixels.
- :param fps: int : The frames per second of the video.
- :param total_frames: int : The total number of frames in the video.
- """
-
- width: int
- height: int
- fps: int
- total_frames: Optional[int] = None
-
- @classmethod
- def from_video_path(cls, video_path: str) -> VideoInfo:
- """
- Returns a VideoInfo data class containing information about the video resolution, fps, and total frame count.
-
- :param video_path: str : The path of the video file.
- :return: VideoInfo : A data class containing information about the video resolution, fps, and total frame count.
- """
- video = cv2.VideoCapture(video_path)
- if not video.isOpened():
- raise Exception(f"Could not open video at {video_path}")
-
- width = int(video.get(cv2.CAP_PROP_FRAME_WIDTH))
- height = int(video.get(cv2.CAP_PROP_FRAME_HEIGHT))
- fps = int(video.get(cv2.CAP_PROP_FPS))
- total_frames = int(video.get(cv2.CAP_PROP_FRAME_COUNT))
- video.release()
- return VideoInfo(width, height, fps, total_frames)
-
- @property
- def resolution(self) -> Tuple[int, int]:
- return self.width, self.height
diff --git a/supervision/video/sink.py b/supervision/video/sink.py
deleted file mode 100644
index c70ad2f1..00000000
--- a/supervision/video/sink.py
+++ /dev/null
@@ -1,48 +0,0 @@
-import cv2
-import numpy as np
-
-from supervision.video.dataclasses import VideoInfo
-
-
-class VideoSink:
- """
- A context manager that uses OpenCV to save video frames to a file.
-
- :param output_path: str : The path to the output file where the video will be saved.
- :param video_info: VideoInfo : An instance of VideoInfo containing information about the video resolution, fps, and total frame count.
- """
-
- def __init__(self, output_path: str, video_info: VideoInfo):
- """
- Initializes the VideoSink with the specified output path and video information.
- """
- self.output_path = output_path
- self.video_info = video_info
- self.fourcc = cv2.VideoWriter_fourcc(*"mp4v")
- self.writer = None
-
- def __enter__(self):
- """
- Opens the output file and returns the VideoSink instance.
- """
- self.writer = cv2.VideoWriter(
- self.output_path,
- self.fourcc,
- self.video_info.fps,
- self.video_info.resolution,
- )
- return self
-
- def write_frame(self, frame: np.ndarray):
- """
- Writes a frame to the output video file.
-
- :param frame: np.ndarray : The frame to be written.
- """
- self.writer.write(frame)
-
- def __exit__(self, exc_type, exc_val, exc_tb):
- """
- Closes the output file.
- """
- self.writer.release()
diff --git a/supervision/video/source.py b/supervision/video/source.py
deleted file mode 100644
index f3679cd7..00000000
--- a/supervision/video/source.py
+++ /dev/null
@@ -1,20 +0,0 @@
-from typing import Generator
-
-import cv2
-
-
-def get_video_frames_generator(video_path: str) -> Generator[int, None, None]:
- """
- Returns a generator that yields the frames of the video.
-
- :param video_path: str : The path of the video file.
- :return: Generator[int, None, None] : Generator that yields the frames of the video.
- """
- video = cv2.VideoCapture(video_path)
- if not video.isOpened():
- raise Exception(f"Could not open video at {video_path}")
- success, frame = video.read()
- while success:
- yield frame
- success, frame = video.read()
- video.release()