From 6a013382d316a64bd02a58e7937c0f80505c3ab8 Mon Sep 17 00:00:00 2001 From: SkalskiP Date: Thu, 4 May 2023 00:33:17 +0200 Subject: [PATCH] =?UTF-8?q?-=20=F0=9F=93=9A=20`Detections`=20documentation?= =?UTF-8?q?=20improvements=20-=20`list=5Ffiles=5Fwith=5Fextensions`=20docu?= =?UTF-8?q?mentation=20improvements=20-=20internal=20`deprecated`=20functi?= =?UTF-8?q?on=20added=20-=20`plot=5Fimage`=20and=20`plot=5Fimages=5Fgrid`?= =?UTF-8?q?=20documentation=20improvements?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- supervision/detection/core.py | 85 ++++++++++++++++++++++++++++++++--- supervision/file.py | 26 ++++++++--- supervision/internal.py | 18 ++++++++ supervision/notebook/utils.py | 4 +- 4 files changed, 121 insertions(+), 12 deletions(-) create mode 100644 supervision/internal.py diff --git a/supervision/detection/core.py b/supervision/detection/core.py index e51ebc5e..824fa69c 100644 --- a/supervision/detection/core.py +++ b/supervision/detection/core.py @@ -7,6 +7,7 @@ import numpy as np from supervision.detection.utils import non_max_suppression, xywh_to_xyxy from supervision.geometry.core import Position +from supervision.internal import deprecated def _validate_xyxy(xyxy: Any, n: int) -> None: @@ -136,7 +137,7 @@ class Detections: @classmethod def from_yolov5(cls, yolov5_results) -> Detections: """ - Creates a Detections instance from a YOLOv5 output Detections + Creates a Detections instance from a [YOLOv5](https://github.com/ultralytics/yolov5) inference result. Args: yolov5_results (yolov5.models.common.Detections): The output Detections instance from YOLOv5 @@ -164,7 +165,7 @@ class Detections: @classmethod def from_yolov8(cls, yolov8_results) -> Detections: """ - Creates a Detections instance from a YOLOv8 output Results + Creates a Detections instance from a [YOLOv8](https://github.com/ultralytics/ultralytics) inference result. Args: yolov8_results (ultralytics.yolo.engine.results.Results): The output Results instance from YOLOv8 @@ -191,7 +192,7 @@ class Detections: @classmethod def from_transformers(cls, transformers_results: dict) -> Detections: """ - Creates a Detections instance from Object Detection Transformer output Results + Creates a Detections instance from object detection [transformer](https://github.com/huggingface/transformers) inference result. Returns: Detections: A new Detections object. @@ -204,6 +205,32 @@ class Detections: @classmethod def from_detectron2(cls, detectron2_results) -> Detections: + """ + Create a Detections object from the [Detectron2](https://github.com/facebookresearch/detectron2) inference result. + + Args: + detectron2_results: The output of a Detectron2 model containing instances with prediction data. + + Returns: + (Detections): A Detections object containing the bounding boxes, class IDs, and confidences of the predictions. + + Example: + ```python + >>> from supervision import Detections + >>> from detectron2.engine import DefaultPredictor + >>> from detectron2.config import get_cfg + + >>> cfg = get_cfg() + >>> cfg.merge_from_file("path/to/config.yaml") + >>> cfg.MODEL.WEIGHTS = "path/to/model_weights.pth" + >>> predictor = DefaultPredictor(cfg) + + >>> image = ... + >>> detectron2_results = predictor(image) + + >>> detections = Detections.from_detectron2(detectron2_results) + ``` + """ return cls( xyxy=detectron2_results["instances"].pred_boxes.tensor.cpu().numpy(), confidence=detectron2_results["instances"].scores.cpu().numpy(), @@ -215,6 +242,38 @@ class Detections: @classmethod def from_roboflow(cls, roboflow_result: dict, class_list: List[str]) -> Detections: + """ + Create a Detections object from the [Roboflow](https://roboflow.com/) API inference result. + + Args: + roboflow_result (dict): The result from the Roboflow API containing predictions. + class_list (List[str]): A list of class names corresponding to the class IDs in the API result. + + Returns: + (Detections): A Detections object containing the bounding boxes, class IDs, and confidences of the predictions. + + Example: + ```python + >>> from supervision import Detections + + >>> roboflow_result = { + ... "predictions": [ + ... { + ... "x": 0.5, + ... "y": 0.5, + ... "width": 0.2, + ... "height": 0.3, + ... "class": "person", + ... "confidence": 0.9 + ... }, + ... # ... more predictions ... + ... ] + ... } + >>> class_list = ["person", "car", "dog"] + + >>> detections = Detections.from_roboflow(roboflow_result, class_list) + ``` + """ xyxy = [] confidence = [] class_id = [] @@ -241,7 +300,7 @@ class Detections: @classmethod def from_sam(cls, sam_result: List[dict]) -> Detections: """ - Creates a Detections instance from Segment Anything Model (SAM) by Meta AI. + Creates a Detections instance from [Segment Anything Model](https://github.com/facebookresearch/segment-anything) inference result. Args: sam_result (List[dict]): The output Results instance from SAM @@ -251,8 +310,8 @@ class Detections: Example: ```python - >>> from segment_anything import sam_model_registry, SamAutomaticMaskGenerator >>> import supervision as sv + >>> from segment_anything import sam_model_registry, SamAutomaticMaskGenerator >>> sam = sam_model_registry[MODEL_TYPE](checkpoint=CHECKPOINT_PATH).to(device=DEVICE) >>> mask_generator = SamAutomaticMaskGenerator(sam) @@ -270,6 +329,9 @@ class Detections: return Detections(xyxy=xywh_to_xyxy(boxes_xywh=xywh), mask=mask) @classmethod + @deprecated( + "Dataset loading and saving is going to be executed by supervision.dataset.core.Dataset" + ) def from_coco_annotations(cls, coco_annotation: dict) -> Detections: xyxy, class_id = [], [] @@ -282,6 +344,19 @@ class Detections: @classmethod def empty(cls) -> Detections: + """ + Create an empty Detections object with no bounding boxes, confidences, or class IDs. + + Returns: + (Detections): An empty Detections object. + + Example: + ```python + >>> from supervision import Detections + + >>> empty_detections = Detections.empty() + ``` + """ return cls( xyxy=np.empty((0, 4), dtype=np.float32), confidence=np.array([], dtype=np.float32), diff --git a/supervision/file.py b/supervision/file.py index e10f6bc7..ab47e822 100644 --- a/supervision/file.py +++ b/supervision/file.py @@ -2,14 +2,30 @@ from pathlib import Path from typing import List, Optional, Union -def write_text_to_file(content: str, output_path: str) -> None: - with open(output_path, "w") as file: - file.write(content) - - def list_files_with_extensions( directory: Union[str, Path], extensions: Optional[List[str]] = None ) -> List[Path]: + """ + List files in a directory with specified extensions or all files if no extensions are provided. + + Args: + directory (Union[str, Path]): The directory path as a string or Path object. + extensions (Optional[List[str]]): A list of file extensions to filter. Default is None, which lists all files. + + Returns: + (List[Path]): A list of Path objects for the matching files. + + Examples: + ```python + >>> from supervision import list_files_with_extensions + + >>> # List all files in the directory + >>> files = list_files_with_extensions(directory='my_directory') + + >>> # List only files with '.txt' and '.md' extensions + >>> files = list_files_with_extensions(directory='my_directory', extensions=['txt', 'md']) + ``` + """ directory = Path(directory) files_with_extensions = [] diff --git a/supervision/internal.py b/supervision/internal.py new file mode 100644 index 00000000..eb84588e --- /dev/null +++ b/supervision/internal.py @@ -0,0 +1,18 @@ +import functools +import warnings + + +def deprecated(reason: str): + def decorator(func): + @functools.wraps(func) + def wrapper(*args, **kwargs): + warnings.warn( + f"{func.__name__} is deprecated: {reason}", + category=DeprecationWarning, + stacklevel=2, + ) + return func(*args, **kwargs) + + return wrapper + + return decorator diff --git a/supervision/notebook/utils.py b/supervision/notebook/utils.py index 79434ca7..87c27197 100644 --- a/supervision/notebook/utils.py +++ b/supervision/notebook/utils.py @@ -24,7 +24,7 @@ def plot_image( >>> image = cv2.imread("path/to/image.jpg") %matplotlib inline - >>> sv.plot_image(image, (16, 16)) + >>> sv.plot_image(image=image, size=(16, 16)) ``` """ plt.figure(figsize=size) @@ -71,7 +71,7 @@ def plot_images_grid( >>> titles = ["Image 1", "Image 2", "Image 3"] %matplotlib inline - >>> plot_images_grid(images, grid_size=(2, 2), titles=titles, figsize=(16, 16)) + >>> plot_images_grid(images, grid_size=(2, 2), titles=titles, size=(16, 16)) ``` """ nrows, ncols = grid_size