

# Generated by the protocol buffer compiler.  DO NOT EDIT!
# sources: blickfeld/percept_pipeline/config/background_subtraction.proto, blickfeld/percept_pipeline/config/classification.proto, blickfeld/percept_pipeline/config/clustering.proto, blickfeld/percept_pipeline/config/data_source.proto, blickfeld/percept_pipeline/config/object_size.proto, blickfeld/percept_pipeline/config/perception.proto, blickfeld/percept_pipeline/config/point_cloud_filter.proto, blickfeld/percept_pipeline/config/tracking.proto, blickfeld/percept_pipeline/config/zone_algorithm.proto
# plugin: python-betterproto
from dataclasses import dataclass
from typing import List

import blickfeld_qb2.betterproto as betterproto
import blickfeld_qb2.betterproto.lib.google.protobuf as betterproto_lib_google_protobuf

from ...base import (
    config as __base_config__,
    geometry as __base_geometry__,
)


class ObjectSize(betterproto.Enum):
    """The size of an object"""

    OBJECT_SIZE_UNSPECIFIED = 0
    """The zero value should not be used"""

    OBJECT_SIZE_SMALL = 1
    """Small object size: small animals, birds, etc"""

    OBJECT_SIZE_MEDIUM = 2
    """Medium object size: free standing human, single human, etc"""

    OBJECT_SIZE_LARGE = 3
    """Large object size: cars, group of people, large animals, etc"""


@dataclass(eq=False, repr=False)
class BackgroundSubtraction(betterproto.Message):
    """
    Algorithms seperating the input point cloud into foreground and background.
    """

    mixture_of_gaussians: "BackgroundSubtractionMixtureOfGaussians" = (
        betterproto.message_field(1, group="background_subtraction_type")
    )
    """Use mixture of gaussians for foreground/background detection"""

    static: "BackgroundSubtractionStatic" = betterproto.message_field(
        3, group="background_subtraction_type"
    )
    """Use a static tree structure for foreground/background detection."""


@dataclass(eq=False, repr=False)
class BackgroundSubtractionMixtureOfGaussians(betterproto.Message):
    """
    Dynamic background subtraction using a mixture of gaussians. The algorithm
    automatically slowly updates the background model if the scene changes. The
    update rate is controlled via 'exponential_decay'.
    """

    num_initialization_frames: int = betterproto.uint32_field(1)
    """
    How many frames of the first received frames are used to build the
    background Reasonable default: 10
    """

    exponential_decay: float = betterproto.float_field(2)
    """
    Controls how fast objects switch between foreground and background.
    Exponential decay factor. Reasonable default: 0.005
    """

    min_weight_threshold_for_background: float = betterproto.float_field(3)
    """
    Controls how much noise the background/foreground is expected to have.
    Reasonable default: 0.25
    """


@dataclass(eq=False, repr=False)
class BackgroundSubtractionStatic(betterproto.Message):
    """
    Uses the first received frames to build a static background map of the
    environment. The algorithm requires the scene to only contain the static
    parts of the scene on the start of the processing. The background model is
    not updated automatically afterwards. The ResetBackground grpc method
    allows to update the static map of the environment.
    """

    num_initialization_frames: int = betterproto.uint32_field(1)
    """
    How many frames of the first received frames are used to build the
    background Reasonable default: 10
    """

    voxel_size: float = betterproto.float_field(3)
    """
    Size of voxels used for voxelization of the background during
    initialization. Default: 0.05 m
    """

    min_distance: float = betterproto.float_field(4)
    """
    Minimum spatial distance to background to detect points as foreground
    Default: 0.15 m
    """


@dataclass(eq=False, repr=False)
class Classification(betterproto.Message):
    """Algorithms for classifying object into small, medium, large."""

    size: "ClassificationSize" = betterproto.message_field(1)
    """Use object size for object classification."""


@dataclass(eq=False, repr=False)
class ClassificationSize(betterproto.Message):
    """
    The minimum size limits of the bounding box area used for classification.
    """

    bounding_box_surface: "ClassificationSizeBoundingBoxSurface" = (
        betterproto.message_field(1, group="type")
    )
    """Use object surface size for object classification."""


@dataclass(eq=False, repr=False)
class ClassificationSizeBoundingBoxSurface(betterproto.Message):
    """
    The maximum surface area between the bounding box's OXZ and OYZ planes is
    used to classify objects based on the limits specified in this message.
    """

    small_min_size: float = betterproto.float_field(1)
    """
    The surface area of the objects bounding box should be larger than this
    value to be considered a small object.
    """

    medium_min_size: float = betterproto.float_field(2)
    """
    The surface area of the objects bounding box should be larger than this
    value to be considered a medium object.
    """

    large_min_size: float = betterproto.float_field(3)
    """
    The surface area of the objects bounding box should be larger than this
    value to be considered a large object.
    """


@dataclass(eq=False, repr=False)
class Clustering(betterproto.Message):
    """
    Algorithms for detecting objects as clustered points in the foreground
    scene.
    """

    db_scan: "ClusteringDbScan" = betterproto.message_field(1, group="clustering_type")
    """Use db-scan for clustering the foreground"""


@dataclass(eq=False, repr=False)
class ClusteringDbScan(betterproto.Message):
    """
    Density-based spatial clustering algorithm using the euclidean distance
    between points
    """

    min_points: int = betterproto.uint32_field(1)
    """
    Minimum amount of points required to define an object-cluster Reasonable
    default: 10
    """

    radius: float = betterproto.float_field(2)
    """
    Controls how far away points belonging to the same object-cluster can be.
    Reasonable default: 0.2
    """

    distance_dependent_radius: float = betterproto.float_field(3)
    """
    Multiply the given radius with the range of a point and add it to the
    radius. This significantly improves the clustering for close-range scenes.
    Reasonable default: 0.025
    """


@dataclass(eq=False, repr=False)
class PointCloudFilter(betterproto.Message):
    """Algorithm for filtering point clouds"""

    radius_outlier: "PointCloudFilterRadiusOutlier" = betterproto.message_field(
        1, group="point_cloud_filter_type"
    )
    """Use radius outlier filter for noise reduction on point clouds"""


@dataclass(eq=False, repr=False)
class PointCloudFilterRadiusOutlier(betterproto.Message):
    """Filter points based on the number of neighbors in a certain radius"""

    min_neighbor_points: int = betterproto.uint32_field(1)
    """Minimum number of neighbors a point has to have to be retained"""

    neighbor_radius: float = betterproto.double_field(2)
    """All points within this radius are considered neighbors of a point"""


@dataclass(eq=False, repr=False)
class Tracking(betterproto.Message):
    """Algorithms for tracking the objects generated from the clustering"""

    disable: bool = betterproto.bool_field(4)
    """Disable tracking. On by default."""

    sensitivity: float = betterproto.float_field(1)
    """
    Higher sensitivity will make the tracker confirm the object faster
    Reasonale default: 0.85
    """

    acceleration_noise: float = betterproto.float_field(2)
    """
    The acceptance range of accelerations for the object to be tracked
    Reasonable default: 0.5
    """

    survival_probability: float = betterproto.float_field(3)
    """
    Higher probability will allow the object to be followed longer in the
    absence of observations Reasonable default: 1
    """


@dataclass(eq=False, repr=False)
class Perception(betterproto.Message):
    """
    The configuration of perception algorithms used to run e.g. security zones
    """

    background_subtraction: "BackgroundSubtraction" = betterproto.message_field(1)
    """Extract the foreground point cloud of the scene"""

    foreground_point_cloud_filters: List["PointCloudFilter"] = (
        betterproto.message_field(2)
    )
    """Filter the foreground point cloud"""

    clustering: "Clustering" = betterproto.message_field(8)
    """Segment the foreground point cloud into clusters"""

    tracking: "Tracking" = betterproto.message_field(9)
    """Track the objects generated from the clustering"""

    classification: "Classification" = betterproto.message_field(10)
    """Classify object into small, medium and large objects"""


@dataclass(eq=False, repr=False)
class ZoneAlgorithm(betterproto.Message):
    """An algorithm that monitors the area within and around a zone."""

    name: str = betterproto.string_field(1)
    """The user readable zone algorithm name"""

    uuid: str = betterproto.string_field(2)
    """The uuid of the zone algorithm (uuid4)"""

    shape: "__base_geometry__.Shape" = betterproto.message_field(3)
    """
    Geometric shape (usually a Box) in which the algorithm detects certain
    behaviors/scenarios
    """

    disabled: bool = betterproto.bool_field(13)
    """
    Disable this zone, setting this flag to `true` disables the evaluation of
    the zone
    """

    metadata: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(100)
    """Arbitrary metadata storage for client applications"""

    volume: "ZoneAlgorithmVolume" = betterproto.message_field(9, group="algorithm_type")
    """Run volume monitoring within the zone"""

    security: "ZoneAlgorithmSecurity" = betterproto.message_field(
        7, group="algorithm_type"
    )
    """Run alarm detection within the zone"""

    exclusion: "ZoneAlgorithmExclusion" = betterproto.message_field(
        10, group="algorithm_type"
    )
    """Run exclusion zone"""

    object_based_security: "ZoneAlgorithmObjectBasedSecurity" = (
        betterproto.message_field(11, group="algorithm_type")
    )
    """Run object-based alarm detection within the zone"""

    occupancy: "ZoneAlgorithmOccupancy" = betterproto.message_field(
        12, group="algorithm_type"
    )
    """Run occupancy zone"""


@dataclass(eq=False, repr=False)
class ZoneAlgorithmVolume(betterproto.Message):
    """
    Algorithm that measure the volume of a zone The volume of a zone is
    approximated by computing a 'volume map' from the input point clouds. The
    volume map discretize the zone into 'tiles' in the xy-plane with a side-
    length of 'resolution'. Each tile contains the height information about the
    points that fall into this tile. The volume of the volume map can be
    calculated by adding up the volumes of the tiles in the volume map.
    """

    resolution: float = betterproto.float_field(1)
    """
    Grid resolution per tile used to measure the volume. Reasonable default:
    0.1
    """

    empty_volume: float = betterproto.float_field(2)
    """
    The measured volume while area covered by the zone is considered 'empty'.
    The value can be set using TareVolume method while the area of the zone is
    empty. Reasonable default: 0
    """

    disable_when_occupied_zone_uuids: List[str] = betterproto.string_field(4)
    """
    Link volume zone to occupancy zones (by uuid). Disables the volume zone
    state when one of the occupancy zones is occupied.
    """


@dataclass(eq=False, repr=False)
class ZoneAlgorithmSecurity(betterproto.Message):
    """
    Algorithm that triggers an alarm if movement was detected in the zone
    """

    min_points: int = betterproto.uint32_field(1)
    """
    Minimum number of (foreground) points in the security zone to trigger the
    alarm. Reasonable default: 10
    """

    max_points: int = betterproto.uint32_field(2)
    """
    Maximum number of (foreground) points in the security zone that still
    triggers an alarm. More points will disable the alarm. This logic can be
    disabled by setting max_points to '0'. Default: 0
    """


@dataclass(eq=False, repr=False)
class ZoneAlgorithmObjectBasedSecurity(betterproto.Message):
    """
    Algorithm that triggers an alarm when an object of one of the selected
    sizes is in the zone
    """

    alarm_sizes: List["ObjectSize"] = betterproto.enum_field(1)
    """
    Selection of sizes which trigger an alarm. Each size in the array will only
    trigger an alarm for the interval of that size.
    """

    minimum_intruder_lifetime: float = betterproto.float_field(6)
    """Minimum lifetime of object before alarm is triggered. Default: 0"""

    minimum_intruder_track_length: float = betterproto.float_field(7)
    """Minimum track length of object before alarm is triggered. Default: 0"""

    minimum_intruding_duration: float = betterproto.float_field(8)
    """
    Minimum active intrusion duration of object before alarm is triggered.
    Default: 0
    """

    objects_in_background: bool = betterproto.bool_field(4)
    """
    Trigger alarm for objects with the "in_background" property. Enabling this
    might increase the false alarm rate.
    """


@dataclass(eq=False, repr=False)
class ZoneAlgorithmExclusion(betterproto.Message):
    """Algorithm that excludes points from the input point cloud"""

    pass


@dataclass(eq=False, repr=False)
class ZoneAlgorithmOccupancy(betterproto.Message):
    """Algorithm that detects if a zone is occupied"""

    min_points: int = betterproto.uint32_field(1)
    """
    Minimum number of points to mark the zone as occupied. Reasonable default:
    10
    """

    adaptive_baseline_time_constant: float = betterproto.float_field(2)
    """
    If set, the min_points is not compared against zero but against an adaptive
    baseline. The baseline is calculated with an exponential filter with the
    zone point count as input. The given time constant is used to calculate the
    alpha for the exponential filter. After a restart, the baseline is
    initialized with the current zone point count. Reasonable default: 3600s (1
    hour)
    """

    voxel_size: float = betterproto.float_field(3)
    """
    The point cloud inside the zone is down sampled with a voxel grid. This is
    done to achieve a distance-independent parametrization. The size of a voxel
    cell can be configured with this parameter. Default: 0.05m
    """

    invert: bool = betterproto.bool_field(4)
    """
    Invert the state of the zone This might be useful in situations where e.g.
    a static crane should be detected in its home position.
    """


@dataclass(eq=False, repr=False)
class DataSource(betterproto.Message):
    """
    The configuration storing the sources to retrieve the point cloud data for
    further processing.
    """

    qb2_setup: "DataSourceQb2Setup" = betterproto.message_field(
        3, group="data_source_type"
    )
    """Use Qb2 lidars to retrieve point clouds"""

    geolocation_of_map: "__base_config__.Geolocation" = betterproto.message_field(4)
    """
    Geolocation of data source. This references the map coordinate system of
    this data source to the world. Individual lidars are referenced to the map
    coordinate system via their `map_from_lidar` transform. [NOTE] If the
    map_from_lidar transform is not an identity transformation, this is not the
    geolocation of an individual sensor.
    """

    swarm: bool = betterproto.bool_field(5)
    """
    Experimental mode which enables configuration synchronization and
    distributed processing. All processing-related configuration, e.g. scan
    pattern and zones, are automatically synchronized between all members in
    the sensor setup. Also the sensor setup itself is replicated on all
    sensors. The object lists of all sensors are fused and tracked on every
    member in the swarm. Thus, also all object-based security zones are
    evaluated on every sensor. This leads to a high availablity and redundancy
    without requiring a master processing unit would be a single point of
    failure.
    """


@dataclass(eq=False, repr=False)
class DataSourceQb2(betterproto.Message):
    """Configuration for retrieving point clouds from a Qb2"""

    fqdn: str = betterproto.string_field(1)
    """
    The fully qualified domain name of the Qb2 device. For on-device
    processing/configuration, 'fqdn' can be set to an empty string to request
    the data of the current device.
    """

    port: int = betterproto.uint32_field(5)
    """
    The gRPC port of the Qb2 device. If unset the default gRPC ports 50051
    (unencrypted) or 55551 (TLS) will be used.
    """

    map_from_lidar: "__base_geometry__.Transform" = betterproto.message_field(2)
    """
    Transformation from the lidar frame to the map frame. If this transform is
    not set, this will be interpreted as identify transformation. Transforming
    all point cloud topics into the map frame results in a globally consistent
    combined point cloud in map frame.
    """

    application_key: str = betterproto.string_field(3)
    """
    Application key with authorized access level. If set, the field
    serial_number has to be set as well. This field is required if user-
    management is enabled on externally connected devices.
    """

    serial_number: str = betterproto.string_field(4)
    """
    Serial number. If set, the connection will be secured with TLS. This field
    is required if user-management is enabled on externally connected devices.
    """

    disabled: bool = betterproto.bool_field(6)
    """
    Disable fetching data from this sensor, setting this flag to `true`
    disables the evaluation of the entire sensor point cloud
    """

    metadata: "betterproto_lib_google_protobuf.Struct" = betterproto.message_field(100)
    """Arbitrary metadata storage for client applications"""


@dataclass(eq=False, repr=False)
class DataSourceTrigger(betterproto.Message):
    """
    Configuration of Trigger Mode. In trigger mode the processing pipeline will
    reduce the frequency at which point clouds and state lists are getting
    computed to reduce the amount of data transmitted between the processing
    device and configured 'lidars'.
    """

    frequency: float = betterproto.float_field(1)
    """
    The frequency at which data is getting requested from the lidars and
    outputs are generated.
    """


@dataclass(eq=False, repr=False)
class DataSourceQb2Setup(betterproto.Message):
    """The configuration of a Qb2 setup of the LiDAR devices"""

    lidars: List["DataSourceQb2"] = betterproto.message_field(1)
    """the qb2 lidars to get the point clouds from"""

    trigger: "DataSourceTrigger" = betterproto.message_field(2)
    """
    If the field is set trigger mode is enabled. If the field is not set, the
    pipeline outputs are computed with the frequency of configured lidars, i.e.
    the scan pattern configured on those.
    """
