Skip to content

filtering

BoxFilter

A class composes multiple filtering functions.

Source code in t4_devkit/filtering/compose.py
class BoxFilter:
    """A class composes multiple filtering functions."""

    def __init__(self, params: FilterParams, tf_buffer: TransformBuffer) -> None:
        """Construct a new object.

        Args:
            params (FilterParams): Filtering parameters.
            tf_buffer (TransformBuffer): Transformation buffer.
        """
        self.filters: list[BoxFilterFunction] = [
            FilterByLabel.from_params(params),
            FilterByUUID.from_params(params),
            FilterByDistance.from_params(params),
            FilterByRegion.from_params(params),
            FilterBySpeed.from_params(params),
            FilterByNumPoints.from_params(params),
            FilterByVisibility.from_params(params),
        ]

        self.tf_buffer = tf_buffer

    def __call__(self, boxes: Sequence[BoxLike]) -> list[BoxLike]:
        output: list[BoxLike] = []

        for box in boxes:
            tf_matrix = self.tf_buffer.lookup_transform(box.frame_id, "base_link")

            is_ok = all(func(box, tf_matrix) for func in self.filters)

            if is_ok:
                output.append(box)

        return output

__init__(params, tf_buffer)

Construct a new object.

Parameters:

Name Type Description Default
params FilterParams

Filtering parameters.

required
tf_buffer TransformBuffer

Transformation buffer.

required
Source code in t4_devkit/filtering/compose.py
def __init__(self, params: FilterParams, tf_buffer: TransformBuffer) -> None:
    """Construct a new object.

    Args:
        params (FilterParams): Filtering parameters.
        tf_buffer (TransformBuffer): Transformation buffer.
    """
    self.filters: list[BoxFilterFunction] = [
        FilterByLabel.from_params(params),
        FilterByUUID.from_params(params),
        FilterByDistance.from_params(params),
        FilterByRegion.from_params(params),
        FilterBySpeed.from_params(params),
        FilterByNumPoints.from_params(params),
        FilterByVisibility.from_params(params),
    ]

    self.tf_buffer = tf_buffer

FilterByDistance

Filter a box by checking if the box is within the specified distance.

Note that, the type box is Box2D and its position is None, these boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterByDistance(BaseBoxFilter):
    """Filter a box by checking if the box is within the specified distance.

    Note that, the type box is `Box2D` and its `position` is None,
    these boxes pass through this filter.
    """

    def __init__(self, min_distance: float, max_distance: float) -> None:
        """Construct a new object.

        Args:
            min_distance (float): Minimum distance from the ego [m].
            max_distance (float): Maximum distance from the ego [m].
        """
        super().__init__()
        self.min_distance = min_distance
        self.max_distance = max_distance

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.min_distance, params.max_distance)

    def __call__(self, box: BoxLike, tf_matrix: HomogeneousMatrix) -> bool:
        box_distance = distance_box(box, tf_matrix)

        # box_distance is None, only if the box is 2D and its position is None.
        if box_distance is None:
            return True
        else:
            return self.min_distance < box_distance and box_distance < self.max_distance

__init__(min_distance, max_distance)

Construct a new object.

Parameters:

Name Type Description Default
min_distance float

Minimum distance from the ego [m].

required
max_distance float

Maximum distance from the ego [m].

required
Source code in t4_devkit/filtering/functional.py
def __init__(self, min_distance: float, max_distance: float) -> None:
    """Construct a new object.

    Args:
        min_distance (float): Minimum distance from the ego [m].
        max_distance (float): Maximum distance from the ego [m].
    """
    super().__init__()
    self.min_distance = min_distance
    self.max_distance = max_distance

FilterByLabel

Filter a box by checking if the label of the box is included in specified labels.

Note that, if labels is None all boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterByLabel(BaseBoxFilter):
    """Filter a box by checking if the label of the box is included in specified labels.

    Note that, if `labels` is None all boxes pass through this filter.
    """

    def __init__(self, labels: Sequence[str | SemanticLabel] | None = None) -> None:
        """Construct a new object.

        Args:
            labels (Sequence[str | SemanticLabel] | None, optional): Sequence of target labels.
                If `None`, this filter always returns `True`.
        """
        super().__init__()
        self.labels = labels

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.labels)

    def __call__(self, box: BoxLike, _tf_matrix: HomogeneousMatrix | None = None) -> bool:
        if self.labels is None:
            return True

        return box.semantic_label in self.labels

__init__(labels=None)

Construct a new object.

Parameters:

Name Type Description Default
labels Sequence[str | SemanticLabel] | None

Sequence of target labels. If None, this filter always returns True.

None
Source code in t4_devkit/filtering/functional.py
def __init__(self, labels: Sequence[str | SemanticLabel] | None = None) -> None:
    """Construct a new object.

    Args:
        labels (Sequence[str | SemanticLabel] | None, optional): Sequence of target labels.
            If `None`, this filter always returns `True`.
    """
    super().__init__()
    self.labels = labels

FilterByNumPoints

Filter a 3D box by checking if the box includes points greater than the specified one.

Note that, the type box is Box2D, or Box3D and its num_points is None, these boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterByNumPoints(BaseBoxFilter):
    """Filter a 3D box by checking if the box includes points greater than the specified one.

    Note that, the type box is `Box2D`, or `Box3D` and its `num_points` is None,
    these boxes pass through this filter.
    """

    def __init__(self, min_num_points: int = 0) -> None:
        """Construct a new object.

        Args:
            min_num_points (int, optional): The minimum number of points that a box should include.
        """
        super().__init__()
        self.min_num_points = min_num_points

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.min_num_points)

    def __call__(self, box: BoxLike, _tf_matrix: HomogeneousMatrix | None = None) -> bool:
        if isinstance(box, Box2D):
            return True
        elif isinstance(box, Box3D) and box.num_points is None:
            return True
        else:
            return self.min_num_points <= box.num_points

__init__(min_num_points=0)

Construct a new object.

Parameters:

Name Type Description Default
min_num_points int

The minimum number of points that a box should include.

0
Source code in t4_devkit/filtering/functional.py
def __init__(self, min_num_points: int = 0) -> None:
    """Construct a new object.

    Args:
        min_num_points (int, optional): The minimum number of points that a box should include.
    """
    super().__init__()
    self.min_num_points = min_num_points

FilterByRegion

Filter a box by checking if the box xy position is within the specified xy region.

Note that, the type box is Box2D and its position is None, these boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterByRegion(BaseBoxFilter):
    """Filter a box by checking if the box xy position is within the specified xy region.

    Note that, the type box is `Box2D` and its `position` is None,
    these boxes pass through this filter.
    """

    def __init__(self, min_xy: tuple[float, float], max_xy: tuple[float, float]) -> None:
        """Construct a new object.

        Args:
            min_xy (tuple[float, float]): Minimum xy position [m].
            max_xy (tuple[float, float]): Maximum xy position [m].
        """
        super().__init__()
        self.min_xy = min_xy
        self.max_xy = max_xy

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.min_xy, params.max_xy)

    def __call__(self, box: BoxLike, tf_matrix: HomogeneousMatrix) -> bool:
        if isinstance(box, Box2D) and box.position is None:
            return True

        if isinstance(box, Box2D):
            position = tf_matrix.transform(box.position)
        elif isinstance(box, Box3D):
            position, _ = tf_matrix.transform(box.position, box.rotation)
        else:
            raise TypeError(f"Unexpected box type: {type(box)}")

        return np.all((self.min_xy < position[:2]) & (position[:2] < self.max_xy))

__init__(min_xy, max_xy)

Construct a new object.

Parameters:

Name Type Description Default
min_xy tuple[float, float]

Minimum xy position [m].

required
max_xy tuple[float, float]

Maximum xy position [m].

required
Source code in t4_devkit/filtering/functional.py
def __init__(self, min_xy: tuple[float, float], max_xy: tuple[float, float]) -> None:
    """Construct a new object.

    Args:
        min_xy (tuple[float, float]): Minimum xy position [m].
        max_xy (tuple[float, float]): Maximum xy position [m].
    """
    super().__init__()
    self.min_xy = min_xy
    self.max_xy = max_xy

FilterBySpeed

Filter a 3D box by checking if the box speed is within the specified one.

Note that, the type box is Box2D, or Box3D and its velocity is None, these boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterBySpeed(BaseBoxFilter):
    """Filter a 3D box by checking if the box speed is within the specified one.

    Note that, the type box is `Box2D`, or `Box3D` and its `velocity` is None,
    these boxes pass through this filter.
    """

    def __init__(self, min_speed: float, max_speed: float) -> None:
        """Construct a new object.

        Args:
            min_speed (float): Minimum speed [m/s].
            max_speed (float): Maximum speed [m/s].
        """
        super().__init__()
        self.min_speed = min_speed
        self.max_speed = max_speed

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.min_speed, params.max_speed)

    def __call__(self, box: BoxLike, _tf_matrix: HomogeneousMatrix | None = None) -> bool:
        if isinstance(box, Box2D):
            return True
        elif isinstance(box, Box3D) and box.velocity is None:
            return True
        else:
            speed = np.linalg.norm(box.velocity)
            return self.min_speed < speed and speed < self.max_speed

__init__(min_speed, max_speed)

Construct a new object.

Parameters:

Name Type Description Default
min_speed float

Minimum speed [m/s].

required
max_speed float

Maximum speed [m/s].

required
Source code in t4_devkit/filtering/functional.py
def __init__(self, min_speed: float, max_speed: float) -> None:
    """Construct a new object.

    Args:
        min_speed (float): Minimum speed [m/s].
        max_speed (float): Maximum speed [m/s].
    """
    super().__init__()
    self.min_speed = min_speed
    self.max_speed = max_speed

FilterByUUID

Filter a box by checking if the uuid of the box is included in specified uuids.

Note that, if uuids is None all boxes pass through this filter.

Source code in t4_devkit/filtering/functional.py
class FilterByUUID(BaseBoxFilter):
    """Filter a box by checking if the uuid of the box is included in specified uuids.

    Note that, if `uuids` is None all boxes pass through this filter.
    """

    def __init__(self, uuids: Sequence[str] | None = None) -> None:
        """Construct a new object.

        Args:
            uuids (Sequence[str] | None, optional): Sequence of target uuids.
                If `None`, this filter always returns `True`.
        """
        super().__init__()
        self.uuids = uuids

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.uuids)

    def __call__(self, box: BoxLike, _tf_matrix: HomogeneousMatrix | None = None) -> bool:
        if self.uuids is None:
            return True

        return box.uuid in self.uuids

__init__(uuids=None)

Construct a new object.

Parameters:

Name Type Description Default
uuids Sequence[str] | None

Sequence of target uuids. If None, this filter always returns True.

None
Source code in t4_devkit/filtering/functional.py
def __init__(self, uuids: Sequence[str] | None = None) -> None:
    """Construct a new object.

    Args:
        uuids (Sequence[str] | None, optional): Sequence of target uuids.
            If `None`, this filter always returns `True`.
    """
    super().__init__()
    self.uuids = uuids

FilterByVisibility

A filter that excludes 3D boxes with lower visibility than a specified threshold.

Boxes with UNAVAILABLE visibility are always passed through (i.e., not filtered).

Source code in t4_devkit/filtering/functional.py
class FilterByVisibility(BaseBoxFilter):
    """A filter that excludes 3D boxes with lower visibility than a specified threshold.

    Boxes with `UNAVAILABLE` visibility are always passed through (i.e., not filtered).
    """

    def __init__(self, visibility: VisibilityLevel = VisibilityLevel.NONE) -> None:
        """
        Initialize the filter with a visibility threshold.

        Args:
            visibility (VisibilityLevel): The minimum visibility level for a box to pass the filter.

        Raises:
            ValueError: If the given visibility is not comparable (e.g., UNAVAILABLE).
        """
        super().__init__()
        if not visibility.is_comparable():
            raise ValueError(f"Comparable visibility must be set as threshold: {visibility}")

        self.visibility = visibility

    @classmethod
    def from_params(cls, params: FilterParams) -> Self:
        return cls(params.visibility)

    def __call__(self, box: BoxLike, _tf_matrix: HomogeneousMatrix | None = None) -> bool:
        if not isinstance(box, Box3D):
            return True
        else:
            return self.visibility <= box.visibility if box.visibility.is_comparable() else True

__init__(visibility=VisibilityLevel.NONE)

Initialize the filter with a visibility threshold.

Parameters:

Name Type Description Default
visibility VisibilityLevel

The minimum visibility level for a box to pass the filter.

NONE

Raises:

Type Description
ValueError

If the given visibility is not comparable (e.g., UNAVAILABLE).

Source code in t4_devkit/filtering/functional.py
def __init__(self, visibility: VisibilityLevel = VisibilityLevel.NONE) -> None:
    """
    Initialize the filter with a visibility threshold.

    Args:
        visibility (VisibilityLevel): The minimum visibility level for a box to pass the filter.

    Raises:
        ValueError: If the given visibility is not comparable (e.g., UNAVAILABLE).
    """
    super().__init__()
    if not visibility.is_comparable():
        raise ValueError(f"Comparable visibility must be set as threshold: {visibility}")

    self.visibility = visibility

FilterParams

A dataclass to represent filtering parameters.

Attributes:

Name Type Description
labels Sequence[str | SemanticLabel] | None

Sequence of target labels.

uuids Sequence[str] | None

Sequence of target uuids.

min_distance float

Minimum distance from the ego [m].

max_distance float

Maximum distance from the ego [m].

min_xy tuple[float, float]

Minimum xy position from the ego [m].

min_xy tuple[float, float]

Maximum xy position from the ego [m].

min_speed float

Minimum speed [m/s].

max_speed float

Maximum speed [m/s].

min_num_points int

The minimum number of points which the 3D box should include.

visibility str | VisibilityLevel

Visibility threshold.

Source code in t4_devkit/filtering/parameter.py
@define
class FilterParams:
    """A dataclass to represent filtering parameters.

    Attributes:
        labels (Sequence[str | SemanticLabel] | None, optional): Sequence of target labels.
        uuids (Sequence[str] | None, optional): Sequence of target uuids.
        min_distance (float, optional): Minimum distance from the ego [m].
        max_distance (float, optional): Maximum distance from the ego [m].
        min_xy (tuple[float, float], optional): Minimum xy position from the ego [m].
        min_xy (tuple[float, float], optional): Maximum xy position from the ego [m].
        min_speed (float, optional): Minimum speed [m/s].
        max_speed (float, optional): Maximum speed [m/s].
        min_num_points (int): The minimum number of points which the 3D box should include.
        visibility (str | VisibilityLevel, optional): Visibility threshold.
    """

    labels: Sequence[str | SemanticLabel] | None = field(
        default=None,
        validator=validators.deep_iterable(
            validators.or_(validators.instance_of(str), validators.instance_of(SemanticLabel))
        ),
    )
    uuids: Sequence[str] | None = field(
        default=None,
        validator=validators.optional(validators.deep_iterable(validators.instance_of(str))),
    )
    min_distance: float = field(default=0.0, validator=validators.ge(0.0))
    max_distance: float = field(default=np.inf, validator=validators.ge(0.0))
    min_xy: tuple[float, float] = field(default=(-np.inf, -np.inf))
    max_xy: tuple[float, float] = field(default=(np.inf, np.inf))
    min_speed: float = field(default=0.0, validator=validators.ge(0.0))
    max_speed: float = field(default=np.inf, validator=validators.ge(0.0))
    min_num_points: int = field(
        default=0,
        validator=[validators.instance_of(int), validators.ge(0)],
    )
    visibility: VisibilityLevel = field(
        default=VisibilityLevel.NONE,
        converter=VisibilityLevel,
        validator=validators.instance_of(VisibilityLevel),
    )