Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix/restructure #173

Merged
merged 12 commits into from
Mar 5, 2025
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ The `depthai_nodes` package requires Python 3.8 or later and `depthai v3` instal
While the `depthai v3` is not yet released on PyPI, you can install it with the following command:

```bash
pip install --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-release-local/ depthai==3.0.0a11
pip install --extra-index-url https://artifacts.luxonis.com/artifactory/luxonis-python-release-local/ depthai==3.0.0a12
```

The `depthai_nodes` package is hosted on PyPI, so you can install it with `pip`.
Expand Down
7 changes: 3 additions & 4 deletions depthai_nodes/__init__.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
from .ml.parsers import *
from .parser_generator import ParserGenerator # noqa: F401
from .parsing_neural_network import ParsingNeuralNetwork # noqa: F401
from .utils import setup_logging
from .constants import *
from .logging import setup_logging
from .message import *

__version__ = "0.1.2"

Expand Down
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
import numpy as np
from numpy.typing import NDArray

from depthai_nodes.ml.helpers.constants import (
from depthai_nodes.constants import (
BACKGROUND_COLOR,
TEXT_COLOR,
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
from .clusters import create_cluster_message
from .detection import (
create_detection_message,
create_line_detection_message,
)
from .image import create_image_message
from .keypoints import create_keypoints_message
from .line import create_line_detection_message
from .map import create_map_message
from .regression import create_regression_message
from .segmentation import create_segmentation_message
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
from typing import List, Union
from typing import List, Optional, Union

import numpy as np

from depthai_nodes.ml.messages import Classifications
from depthai_nodes import Classifications


def create_classification_message(
classes: List, scores: Union[np.ndarray, List]
classes: List[str], scores: Union[np.ndarray, List]
) -> Classifications:
"""Create a message for classification. The message contains the class names and
their respective scores, sorted in descending order of scores.

@param classes: A list containing class names.
@type classes: List
@type classes: List[str]
@param scores: A numpy array of shape (n_classes,) containing the probability score of each class.
@type scores: np.ndarray

Expand All @@ -39,7 +39,7 @@ def create_classification_message(
if len(classes) == 0:
raise ValueError("Classes should not be empty.")

if type(scores) == type(None):
if scores is None:
raise ValueError("Scores should not be None.")

if not isinstance(scores, np.ndarray) and not isinstance(scores, list):
Expand Down Expand Up @@ -89,7 +89,7 @@ def create_classification_message(
def create_classification_sequence_message(
classes: List[str],
scores: Union[np.ndarray, List],
ignored_indexes: List[int] = None,
ignored_indexes: Optional[List[int]] = None,
remove_duplicates: bool = False,
concatenate_classes: bool = False,
) -> Classifications:
Expand All @@ -102,11 +102,11 @@ def create_classification_sequence_message(
@type classes: List
@param scores: A numpy array of shape (sequence_length, n_classes) containing the (row-wise) probability distributions over the classes.
@type scores: np.ndarray
@param ignored_indexes: A list of indexes to ignore during classification generation (e.g., background class, padding class)
@type ignored_indexes: List[int]
@param remove_duplicates: If True, removes consecutive duplicates from the sequence.
@param ignored_indexes: A list of indexes to ignore during classification generation (e.g., background class, padding class). Defaults to None.
@type ignored_indexes: Optional[List[int]]
@param remove_duplicates: If True, removes consecutive duplicates from the sequence. Defaults to False.
@type remove_duplicates: bool
@param concatenate_classes: If True, concatenates consecutive classes based on the space character.
@param concatenate_classes: If True, concatenates consecutive classes based on the space character. Defaults to False.
@type concatenate_classes: bool
@return: A Classification message with attributes `classes` and `scores`, where `classes` is a list of class names and `scores` is a list of corresponding scores.
@rtype: Classifications
Expand Down Expand Up @@ -165,7 +165,7 @@ def create_classification_sequence_message(
if ignored_indexes is not None:
selection &= np.array([index not in ignored_indexes for index in indexes])

class_list = [classes[i] for i in indexes[selection]]
class_list: List[str] = [classes[i] for i in indexes[selection]]
score_list = np.max(scores, axis=1)[selection]

if (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import depthai as dai

from depthai_nodes.ml.messages import Cluster, Clusters
from depthai_nodes import Cluster, Clusters


def create_cluster_message(clusters: List[List[List[Union[float, int]]]]) -> Clusters:
Expand Down
Original file line number Diff line number Diff line change
@@ -1,23 +1,23 @@
import depthai as dai
from typing import Optional

import numpy as np

from depthai_nodes.ml.messages import (
from depthai_nodes import (
ImgDetectionExtended,
ImgDetectionsExtended,
Line,
Lines,
)
from depthai_nodes.ml.parsers.utils import transform_to_keypoints

from .keypoints import create_keypoints_message


def create_detection_message(
bboxes: np.ndarray,
scores: np.ndarray,
angles: np.ndarray = None,
labels: np.ndarray = None,
keypoints: np.ndarray = None,
keypoints_scores: np.ndarray = None,
masks: np.ndarray = None,
angles: Optional[np.ndarray] = None,
labels: Optional[np.ndarray] = None,
keypoints: Optional[np.ndarray] = None,
keypoints_scores: Optional[np.ndarray] = None,
masks: Optional[np.ndarray] = None,
) -> ImgDetectionsExtended:
"""Create a DepthAI message for object detection. The message contains the bounding
boxes in X_center, Y_center, Width, Height format with optional angles, labels and
Expand All @@ -28,17 +28,17 @@ def create_detection_message(
@type bbox: np.ndarray
@param scores: Confidence scores of the detected objects of shape (N,).
@type scores: np.ndarray
@param angles: Angles of detected objects expressed in degrees.
@param angles: Angles of detected objects expressed in degrees. Defaults to None.
@type angles: Optional[np.ndarray]
@param labels: Labels of detected objects of shape (N,).
@param labels: Labels of detected objects of shape (N,). Defaults to None.
@type labels: Optional[np.ndarray]
@param keypoints: Keypoints of detected objects of shape (N, n_keypoints, dim) where
dim is 2 or 3.
dim is 2 or 3. Defaults to None.
@type keypoints: Optional[np.array]
@param keypoints_scores: Confidence scores of detected keypoints of shape (N,
n_keypoints, 1).
n_keypoints, 1). Defaults to None.
@type keypoints_scores: Optional[np.ndarray]
@param masks: Masks of detected objects of shape (H, W).
@param masks: Masks of detected objects of shape (H, W). Defaults to None.
@type masks: Optional[np.ndarray]
@return: Message containing the bounding boxes, labels, confidence scores, and
keypoints of detected objects.
Expand Down Expand Up @@ -185,12 +185,29 @@ def create_detection_message(
if labels is not None:
detection.label = int(labels[detection_idx])
if keypoints is not None:
if keypoints_scores is not None:
detection.keypoints = transform_to_keypoints(
keypoints[detection_idx], keypoints_scores[detection_idx]
)
else:
detection.keypoints = transform_to_keypoints(keypoints[detection_idx])
# if keypoints_scores is not None:
# # detection.keypoints = transform_to_keypoints(
# # keypoints[detection_idx], keypoints_scores[detection_idx]
# # )
# keypoints_msg = create_keypoints_message(
# keypoints=keypoints[detection_idx],
# scores=keypoints_scores[detection_idx],
# )
# else:
# keypoints_msg = create_keypoints_message(
# keypoints=keypoints[detection_idx],
# scores=keypoints_scores[detection_idx]
# if keypoints_scores is not None
# else None,
# )
# detection.keypoints = transform_to_keypoints(keypoints[detection_idx])
keypoints_msg = create_keypoints_message(
keypoints=keypoints[detection_idx],
scores=None
if keypoints_scores is None
else keypoints_scores[detection_idx],
)
detection.keypoints = keypoints_msg.keypoints

detections.append(detection)

Expand All @@ -201,67 +218,3 @@ def create_detection_message(
detections_msg.masks = masks

return detections_msg


def create_line_detection_message(lines: np.ndarray, scores: np.ndarray):
"""Create a DepthAI message for a line detection.

@param lines: Detected lines of shape (N,4) meaning [...,[x_start, y_start, x_end, y_end],...].
@type lines: np.ndarray
@param scores: Confidence scores of detected lines of shape (N,).
@type scores: np.ndarray

@return: Message containing the lines and confidence scores of detected lines.
@rtype: Lines

@raise ValueError: If the lines are not a numpy array.
@raise ValueError: If the lines are not of shape (N,4).
@raise ValueError: If the lines 2nd dimension is not of size E{4}.
@raise ValueError: If the scores are not a numpy array.
@raise ValueError: If the scores are not of shape (N,).
@raise ValueError: If the scores do not have the same length as lines.
"""

# checks for lines
if not isinstance(lines, np.ndarray):
raise ValueError(f"Lines should be numpy array, got {type(lines)}.")
if len(lines) != 0:
if len(lines.shape) != 2:
raise ValueError(
f"Lines should be of shape (N,4) meaning [...,[x_start, y_start, x_end, y_end],...], got {lines.shape}."
)
if lines.shape[1] != 4:
raise ValueError(
f"Lines 2nd dimension should be of size 4 e.g. [x_start, y_start, x_end, y_end] got {lines.shape[1]}."
)

# checks for scores
if not isinstance(scores, np.ndarray):
raise ValueError(f"Scores should be numpy array, got {type(scores)}.")

if len(scores) != 0:
if len(scores.shape) != 1:
raise ValueError(
f"Scores should be of shape (N,) meaning, got {scores.shape}."
)

for score in scores:
if not isinstance(score, (float, np.floating)):
raise ValueError(f"Scores should be of type float, got {type(score)}.")

if scores.shape[0] != lines.shape[0]:
raise ValueError(
f"Scores should have same length as lines, got {scores.shape[0]} and {lines.shape[0]}."
)

line_detections = []
for i, line in enumerate(lines):
line_detection = Line()
line_detection.start_point = dai.Point2f(line[0], line[1])
line_detection.end_point = dai.Point2f(line[2], line[3])
line_detection.confidence = float(scores[i])
line_detections.append(line_detection)

lines_msg = Lines()
lines_msg.lines = line_detections
return lines_msg
Original file line number Diff line number Diff line change
@@ -1,22 +1,22 @@
from typing import List, Union
from typing import List, Optional, Union

import numpy as np

from depthai_nodes.ml.messages import Keypoint, Keypoints
from depthai_nodes import Keypoint, Keypoints


def create_keypoints_message(
keypoints: Union[np.ndarray, List[List[float]]],
scores: Union[np.ndarray, List[float]] = None,
confidence_threshold: float = None,
scores: Union[np.ndarray, List[float], None] = None,
confidence_threshold: Optional[float] = None,
) -> Keypoints:
"""Create a DepthAI message for the keypoints.

@param keypoints: Detected 2D or 3D keypoints of shape (N,2 or 3) meaning [...,[x, y],...] or [...,[x, y, z],...].
@type keypoints: np.ndarray or List[List[float]]
@param scores: Confidence scores of the detected keypoints.
@type scores: Optional[np.ndarray or List[float]]
@param confidence_threshold: Confidence threshold of keypoint detections.
@param scores: Confidence scores of the detected keypoints. Defaults to None.
@type scores: Union[np.ndarray, List[float], None]
@param confidence_threshold: Confidence threshold of keypoint detections. Defaults to None.
@type confidence_threshold: Optional[float]

@return: Keypoints message containing the detected keypoints.
Expand Down
68 changes: 68 additions & 0 deletions depthai_nodes/message/creators/line.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
import depthai as dai
import numpy as np

from depthai_nodes import Line, Lines


def create_line_detection_message(lines: np.ndarray, scores: np.ndarray):
"""Create a DepthAI message for a line detection.

@param lines: Detected lines of shape (N,4) meaning [...,[x_start, y_start, x_end, y_end],...].
@type lines: np.ndarray
@param scores: Confidence scores of detected lines of shape (N,).
@type scores: np.ndarray

@return: Message containing the lines and confidence scores of detected lines.
@rtype: Lines

@raise ValueError: If the lines are not a numpy array.
@raise ValueError: If the lines are not of shape (N,4).
@raise ValueError: If the lines 2nd dimension is not of size E{4}.
@raise ValueError: If the scores are not a numpy array.
@raise ValueError: If the scores are not of shape (N,).
@raise ValueError: If the scores do not have the same length as lines.
"""

# checks for lines
if not isinstance(lines, np.ndarray):
raise ValueError(f"Lines should be numpy array, got {type(lines)}.")
if len(lines) != 0:
if len(lines.shape) != 2:
raise ValueError(
f"Lines should be of shape (N,4) meaning [...,[x_start, y_start, x_end, y_end],...], got {lines.shape}."
)
if lines.shape[1] != 4:
raise ValueError(
f"Lines 2nd dimension should be of size 4 e.g. [x_start, y_start, x_end, y_end] got {lines.shape[1]}."
)

# checks for scores
if not isinstance(scores, np.ndarray):
raise ValueError(f"Scores should be numpy array, got {type(scores)}.")

if len(scores) != 0:
if len(scores.shape) != 1:
raise ValueError(
f"Scores should be of shape (N,) meaning, got {scores.shape}."
)

for score in scores:
if not isinstance(score, (float, np.floating)):
raise ValueError(f"Scores should be of type float, got {type(score)}.")

if scores.shape[0] != lines.shape[0]:
raise ValueError(
f"Scores should have same length as lines, got {scores.shape[0]} and {lines.shape[0]}."
)

line_detections = []
for i, line in enumerate(lines):
line_detection = Line()
line_detection.start_point = dai.Point2f(line[0], line[1])
line_detection.end_point = dai.Point2f(line[2], line[3])
line_detection.confidence = float(scores[i])
line_detections.append(line_detection)

lines_msg = Lines()
lines_msg.lines = line_detections
return lines_msg
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import numpy as np

from depthai_nodes.ml.messages import Map2D
from depthai_nodes import Map2D


def create_map_message(map: np.ndarray, min_max_scaling: bool = False) -> Map2D:
Expand All @@ -9,7 +9,8 @@ def create_map_message(map: np.ndarray, min_max_scaling: bool = False) -> Map2D:
@param map: A NumPy array representing the map with shape HW or NHW/HWN. Here N
stands for batch dimension.
@type map: np.array
@param min_max_scaling: If True, the map is scaled to the range [0, 1].
@param min_max_scaling: If True, the map is scaled to the range [0, 1]. Defaults to
False.
@type min_max_scaling: bool
@return: An Map2D object containing the density information.
@rtype: Map2D
Expand Down
Loading
Loading