Merge pull request #8 from roboflow/documentation-improvements

Refactor documentation for Supervision
This commit is contained in:
Piotr Skalski 2023-02-01 16:07:37 +01:00 committed by GitHub
commit ae84cdeb02
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 194 additions and 87 deletions

9
docs/draw.md Normal file
View File

@ -0,0 +1,9 @@
Utilities for drawing on images.
## Draw Line
:::supervision.draw.utils.draw_line
## Draw Rectangle
:::supervision.draw.utils.draw_rectangle

0
docs/geometry.md Normal file
View File

View File

@ -9,21 +9,22 @@
</p>
</div>
## 👋 hello
## 👋 Welcome
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.
Supervision is a set of easy-to-use utilities that will come in handy in any computer vision project.
## 💻 install
**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.
Pip install the supervision package in a
## 💻 How to Install
You can install `supervision` with pip in a
[**3.10>=Python>=3.7**](https://www.python.org/) environment.
!!! example "Pip install method (recommended)"
```bash
pip install subervision
pip install supervision
```
!!! example "Git clone method (for development)"

3
docs/notebook.md Normal file
View File

@ -0,0 +1,3 @@
Utilities to help you build computer vision projects in notebook environments.
:::supervision.notebook.utils.show_frame_in_notebook

9
docs/tools.md Normal file
View File

@ -0,0 +1,9 @@
Useful utilities for common computer vision tasks.
## Helper for Processing Model Detections
:::supervision.tools.detections.Detections
## Count Objects That Pass a Line
:::supervision.tools.line_counter.LineCounter

View File

@ -19,8 +19,12 @@ extra:
link: https://twitter.com/roboflow
nav:
- Home: index.md
- Video: video.md
- Home 🏠: index.md
- Video 📷: video.md
- Notebook Helpers 📓: notebook.md
- Draw 🎨: draw.md
- Geometry 📐: geometry.md
- Tools 🛠: tools.md
theme:
name: 'material'

30
requirements.txt Normal file
View File

@ -0,0 +1,30 @@
certifi==2022.12.7
charset-normalizer==3.0.1
click==8.1.3
colorama==0.4.6
ghp-import==2.1.0
griffe==0.25.4
idna==3.4
importlib-metadata==6.0.0
Jinja2==3.1.2
Markdown==3.3.7
MarkupSafe==2.1.2
mergedeep==1.3.4
mkdocs==1.4.2
mkdocs-autorefs==0.4.1
mkdocs-material==9.0.9
mkdocs-material-extensions==1.1.1
mkdocstrings==0.20.0
mkdocstrings-python==0.8.3
packaging==23.0
Pygments==2.14.0
pymdown-extensions==9.9.2
python-dateutil==2.8.2
PyYAML==6.0
pyyaml_env_tag==0.1
regex==2022.10.31
requests==2.28.2
six==1.16.0
urllib3==1.26.14
watchdog==2.2.1
zipp==3.12.0

View File

@ -11,12 +11,16 @@ def draw_line(
"""
Draws a line on a given scene.
:param scene: np.ndarray : The scene on which the line will be drawn
:param start: Point : The starting point of the line
:param end: Point : The end point of the line
:param color: Color : The color of the line
:param thickness: int : The thickness of the line
:return: np.ndarray : The scene with the line drawn on it
Attributes:
scene (np.ndarray): The scene on which the line will be drawn
start (Point): The starting point of the line
end (Point): The end point of the line
color (Color): The color of the line
thickness (int): The thickness of the line
Returns:
np.ndarray: The scene with the line drawn on it
"""
cv2.line(
scene,
@ -34,11 +38,19 @@ def draw_rectangle(
"""
Draws a rectangle on an image.
:param scene: np.ndarray : The image on which to draw the rectangle.
:param rect: Rect : The rectangle to draw.
:param color: Color : The color of the rectangle.
:param thickness: int : The thickness of the rectangle border.
:return: np.ndarray : The image with the rectangle drawn on it.
Attributes:
scene (np.ndarray): The scene on which the rectangle will be drawn
rect (Rect): The rectangle to be drawn
color (Color): The color of the rectangle
thickness (int): The thickness of the rectangle border
Returns:
np.ndarray: The scene with the rectangle drawn on it
Example:
```python
>>> # TODO: Add example
```
"""
cv2.rectangle(
scene,
@ -58,6 +70,20 @@ def draw_filled_rectangle(scene: np.ndarray, rect: Rect, color: Color) -> np.nda
:param rect: Rect : The rectangle to be drawn.
:param color: Color : The color of the rectangle.
:return: np.ndarray : The updated scene with the filled rectangle drawn on it.
Attributes:
scene (np.ndarray): The scene on which the rectangle will be drawn
rect (Rect): The rectangle to be drawn
color (Color): The color of the rectangle
Returns:
np.ndarray: The scene with the rectangle drawn on it
Example:
```python
>>> # TODO: Add example
```
"""
cv2.rectangle(
scene,

View File

@ -11,9 +11,16 @@ def show_frame_in_notebook(
"""
Display a frame in Jupyter Notebook using Matplotlib
:param frame: np.ndarray : The frame to be displayed.
:param size: Tuple[int, int] : The size of the plot. default:(10,10)
:param cmap: str : the colormap to use for single channel images. default:gray
Attributes:
frame (np.ndarray): The frame to be displayed.
size (Tuple[int, int]): The size of the plot. default:(10,10)
cmap (str): the colormap to use for single channel images. default:gray
Examples:
```python
>>> from supervision.notebook import show_frame_in_notebook
```
"""
if frame.ndim == 2:
plt.figure(figsize=size)

View File

@ -17,10 +17,11 @@ class Detections:
"""
Data class containing information about the detections in a video frame.
:param xyxy: np.ndarray : An array of shape (n, 4) containing the bounding boxes coordinates in format [x1, y1, x2, y2]
:param confidence: np.ndarray : An array of shape (n,) containing the confidence scores of the detections.
:param class_id: np.ndarray : An array of shape (n,) containing the class ids of the detections.
:param tracker_id: Optional[np.ndarray] : An array of shape (n,) containing the tracker ids of the detections.
Attributes:
xyxy (np.ndarray): An array of shape (n, 4) containing the bounding boxes coordinates in format [x1, y1, x2, y2]
confidence (np.ndarray): An array of shape (n,) containing the confidence scores of the detections.
class_id (np.ndarray): An array of shape (n,) containing the class ids of the detections.
tracker_id (Optional[np.ndarray]): An array of shape (n,) containing the tracker ids of the detections.
"""
self.xyxy: np.ndarray = xyxy
self.confidence: np.ndarray = confidence
@ -69,11 +70,17 @@ class Detections:
"""
Creates a Detections instance from a YOLOv5 output tensor
:param yolov5_output: np.ndarray : The output tensor from YOLOv5
:return: Detections : A Detections instance representing the detections in the frame
Attributes:
yolov5_output (np.ndarray): The output tensor from YOLOv5
Returns:
Example:
detections = Detections.from_yolov5(yolov5_output)
```python
>>> from supervision.tools.detections import Detections
>>> detections = Detections.from_yolov5(yolov5_output)
```
"""
xyxy = yolov5_output[:, :4]
confidence = yolov5_output[:, 4]
@ -82,11 +89,14 @@ class Detections:
def filter(self, mask: np.ndarray, inplace: bool = False) -> Optional[np.ndarray]:
"""
Filter the detections by applying a mask
Filter the detections by applying a mask.
:param mask: np.ndarray : A mask of shape (n,) containing a boolean value for each detection indicating if it should be included in the filtered detections
:param inplace: bool : If True, the original data will be modified and self will be returned.
:return: Optional[np.ndarray] : A new instance of Detections with the filtered detections, if inplace is set to False. None otherwise.
Attributes:
mask (np.ndarray): A mask of shape (n,) containing a boolean value for each detection indicating if it should be included in the filtered detections
inplace (bool): If True, the original data will be modified and self will be returned.
Returns:
Optional[np.ndarray]: A new instance of Detections with the filtered detections, if inplace is set to False. None otherwise.
"""
if inplace:
self.xyxy = self.xyxy[mask]
@ -120,12 +130,14 @@ class BoxAnnotator:
"""
A class for drawing bounding boxes on an image using detections provided.
:param color: Union[Color, ColorPalette] : The color to draw the bounding box, can be a single color or a color palette
:param thickness: int : The thickness of the bounding box lines, default is 2
:param text_color: Color : The color of the text on the bounding box, default is white
:param text_scale: float : The scale of the text on the bounding box, default is 0.5
:param text_thickness: int : The thickness of the text on the bounding box, default is 1
:param text_padding: int : The padding around the text on the bounding box, default is 5
Attributes:
color (Union[Color, ColorPalette]): The color to draw the bounding box, can be a single color or a color palette
thickness (int): The thickness of the bounding box lines, default is 2
text_color (Color): The color of the text on the bounding box, default is white
text_scale (float): The scale of the text on the bounding box, default is 0.5
text_thickness (int): The thickness of the text on the bounding box, default is 1
text_padding (int): The padding around the text on the bounding box, default is 5
"""
self.color: Union[Color, ColorPalette] = color
self.thickness: int = thickness
@ -143,10 +155,13 @@ class BoxAnnotator:
"""
Draws bounding boxes on the frame using the detections provided.
:param frame: np.ndarray : The image on which the bounding boxes will be drawn
:param detections: Detections : The detections for which the bounding boxes will be drawn
:param labels: Optional[List[str]] : An optional list of labels corresponding to each detection. If labels is provided, the confidence score of the detection will be replaced with the label.
:return: np.ndarray : The image with the bounding boxes drawn on it
Attributes:
frame (np.ndarray): The image on which the bounding boxes will be drawn
detections (Detections): The detections for which the bounding boxes will be drawn
labels (Optional[List[str]]): An optional list of labels corresponding to each detection. If labels is provided, the confidence score of the detection will be replaced with the label.
Returns:
np.ndarray: The image with the bounding boxes drawn on it
"""
font = cv2.FONT_HERSHEY_SIMPLEX
for i, (xyxy, confidence, class_id, tracker_id) in enumerate(detections):

View File

@ -9,12 +9,18 @@ from supervision.tools.detections import Detections
class LineCounter:
"""
Count the number of objects that cross a line.
"""
def __init__(self, start: Point, end: Point):
"""
Initialize a LineCounter object.
:param start: Point : The starting point of the line.
:param end: Point : The ending point of the line.
Attributes:
start (Point): The starting point of the line.
end (Point): The ending point of the line.
"""
self.vector = Vector(start=start, end=end)
self.tracker_state: Dict[str, bool] = {}
@ -25,7 +31,9 @@ class LineCounter:
"""
Update the in_count and out_count for the detections that cross the line.
:param detections: Detections : The detections for which to update the counts.
Attributes:
detections (Detections): The detections for which to update the counts.
"""
for xyxy, confidence, class_id, tracker_id in detections:
# handle detections with no tracker_id
@ -77,13 +85,15 @@ class LineCounterAnnotator:
"""
Initialize the LineCounterAnnotator object with default values.
:param thickness: float : The thickness of the line that will be drawn.
:param color: Color : The color of the line that will be drawn.
:param text_thickness: float : The thickness of the text that will be drawn.
:param text_color: Color : The color of the text that will be drawn.
:param text_scale: float : The scale of the text that will be drawn.
:param text_offset: float : The offset of the text that will be drawn.
:param text_padding: int : The padding of the text that will be drawn.
Attributes:
thickness (float): The thickness of the line that will be drawn.
color (Color): The color of the line that will be drawn.
text_thickness (float): The thickness of the text that will be drawn.
text_color (Color): The color of the text that will be drawn.
text_scale (float): The scale of the text that will be drawn.
text_offset (float): The offset of the text that will be drawn.
text_padding (int): The padding of the text that will be drawn.
"""
self.thickness: float = thickness
self.color: Color = color
@ -97,9 +107,13 @@ class LineCounterAnnotator:
"""
Draws the line on the frame using the line_counter provided.
:param frame: np.ndarray : The image on which the line will be drawn
:param line_counter: LineCounter : The line counter that will be used to draw the line
:return: np.ndarray : The image with the line drawn on it
Attributes:
frame (np.ndarray): The image on which the line will be drawn.
line_counter (LineCounter): The line counter that will be used to draw the line.
Returns:
np.ndarray: The image with the line drawn on it.
"""
cv2.line(
frame,

View File

@ -7,27 +7,25 @@ from supervision.draw.color import Color
@pytest.mark.parametrize(
'color_hex, expected_result, exception',
"color_hex, expected_result, exception",
[
('fff', Color.white(), DoesNotRaise()),
('#fff', Color.white(), DoesNotRaise()),
('ffffff', Color.white(), DoesNotRaise()),
('#ffffff', Color.white(), DoesNotRaise()),
('f00', Color.red(), DoesNotRaise()),
('0f0', Color.green(), DoesNotRaise()),
('00f', Color.blue(), DoesNotRaise()),
('#808000', Color(r=128, g=128, b=0), DoesNotRaise()),
('', None, pytest.raises(ValueError)),
('00', None, pytest.raises(ValueError)),
('0000', None, pytest.raises(ValueError)),
('0000000', None, pytest.raises(ValueError)),
('ffg', None, pytest.raises(ValueError)),
]
("fff", Color.white(), DoesNotRaise()),
("#fff", Color.white(), DoesNotRaise()),
("ffffff", Color.white(), DoesNotRaise()),
("#ffffff", Color.white(), DoesNotRaise()),
("f00", Color.red(), DoesNotRaise()),
("0f0", Color.green(), DoesNotRaise()),
("00f", Color.blue(), DoesNotRaise()),
("#808000", Color(r=128, g=128, b=0), DoesNotRaise()),
("", None, pytest.raises(ValueError)),
("00", None, pytest.raises(ValueError)),
("0000", None, pytest.raises(ValueError)),
("0000000", None, pytest.raises(ValueError)),
("ffg", None, pytest.raises(ValueError)),
],
)
def test_color_from_hex(
color_hex,
expected_result: Optional[Color],
exception: Exception
color_hex, expected_result: Optional[Color], exception: Exception
) -> None:
with exception:
result = Color.from_hex(color_hex=color_hex)

View File

@ -4,37 +4,28 @@ from supervision.geometry.dataclasses import Vector, Point
@pytest.mark.parametrize(
'vector, point, expected_result',
"vector, point, expected_result",
[
(Vector(start=Point(x=0, y=0), end=Point(x=5, y=5)), Point(x=-1, y=1), False),
(Vector(start=Point(x=0, y=0), end=Point(x=5, y=5)), Point(x=6, y=6), False),
(Vector(start=Point(x=0, y=0), end=Point(x=5, y=5)), Point(x=3, y=6), False),
(Vector(start=Point(x=5, y=5), end=Point(x=0, y=0)), Point(x=-1, y=1), True),
(Vector(start=Point(x=5, y=5), end=Point(x=0, y=0)), Point(x=6, y=6), False),
(Vector(start=Point(x=5, y=5), end=Point(x=0, y=0)), Point(x=3, y=6), True),
(Vector(start=Point(x=0, y=0), end=Point(x=1, y=0)), Point(x=0, y=0), False),
(Vector(start=Point(x=0, y=0), end=Point(x=1, y=0)), Point(x=0, y=-1), True),
(Vector(start=Point(x=0, y=0), end=Point(x=1, y=0)), Point(x=0, y=1), False),
(Vector(start=Point(x=1, y=0), end=Point(x=0, y=0)), Point(x=0, y=0), False),
(Vector(start=Point(x=1, y=0), end=Point(x=0, y=0)), Point(x=0, y=-1), False),
(Vector(start=Point(x=1, y=0), end=Point(x=0, y=0)), Point(x=0, y=1), True),
(Vector(start=Point(x=1, y=1), end=Point(x=1, y=3)), Point(x=0, y=0), False),
(Vector(start=Point(x=1, y=1), end=Point(x=1, y=3)), Point(x=1, y=4), False),
(Vector(start=Point(x=1, y=1), end=Point(x=1, y=3)), Point(x=2, y=4), True),
(Vector(start=Point(x=1, y=3), end=Point(x=1, y=1)), Point(x=0, y=0), True),
(Vector(start=Point(x=1, y=3), end=Point(x=1, y=1)), Point(x=1, y=4), False),
(Vector(start=Point(x=1, y=3), end=Point(x=1, y=1)), Point(x=2, y=4), False),
]
],
)
def test_vector_is_in(
vector: Vector,
point: Point,
expected_result: bool
) -> None:
def test_vector_is_in(vector: Vector, point: Point, expected_result: bool) -> None:
result = vector.is_in(point=point)
assert result == expected_result