From 99f45a7a7963a7be41f098e5ca1914e00fff45fe Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Mon, 29 Jan 2024 15:36:33 +0100 Subject: Removing use of marker size. Enabling context management for PipelineStepObject. --- src/argaze/ArFeatures.py | 6 ++--- src/argaze/ArUcoMarkers/ArUcoDetector.py | 27 +++++------------------ src/argaze/ArUcoMarkers/ArUcoMarker.py | 18 +++++++++++---- src/argaze/DataFeatures.py | 38 ++++++++++++++++++++++++++++++-- 4 files changed, 58 insertions(+), 31 deletions(-) (limited to 'src') diff --git a/src/argaze/ArFeatures.py b/src/argaze/ArFeatures.py index 0062c53..5951c95 100644 --- a/src/argaze/ArFeatures.py +++ b/src/argaze/ArFeatures.py @@ -163,7 +163,7 @@ class ArLayer(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): for name, analyzer in self.__aoi_scan_path_analyzers.items(): analyzer.parent = self - + @property def aoi_scene(self) -> AOIFeatures.AOIScene: """Get layer's aoi scene object.""" @@ -574,7 +574,7 @@ class ArFrame(DataFeatures.SharedObject, DataFeatures.PipelineStepObject): for name, layer in self.__layers.items(): layer.parent = self - + @property def size(self) -> tuple[int]: """Get frame's size.""" @@ -1111,7 +1111,7 @@ class ArScene(DataFeatures.PipelineStepObject): for name, frame in self.__frames.items(): frame.parent = self - + @property def layers(self) -> dict: """Get scene's layers dictionary.""" diff --git a/src/argaze/ArUcoMarkers/ArUcoDetector.py b/src/argaze/ArUcoMarkers/ArUcoDetector.py index d326aaa..8c843ae 100644 --- a/src/argaze/ArUcoMarkers/ArUcoDetector.py +++ b/src/argaze/ArUcoMarkers/ArUcoDetector.py @@ -131,21 +131,13 @@ class DetectorParameters(): return self.__parameters class ArUcoDetector(DataFeatures.PipelineStepObject): - """ArUco markers detector. + """OpenCV ArUco library wrapper.""" - Parameters: - dictionary: ArUco markers dictionary to detect. - marker_size: Size of ArUco markers to detect in centimeter. - optic_parameters: Optic parameters to use for ArUco detection into image. - parameters: ArUco detector parameters. - """ - - def __init__(self, dictionary: ArUcoMarkersDictionary.ArUcoMarkersDictionary = None, marker_size: float = 0., optic_parameters: ArUcoOpticCalibrator.OpticParameters = None, parameters: DetectorParameters = None): - """ Initialize ArUcoDetector. + def __init__(self, dictionary: ArUcoMarkersDictionary.ArUcoMarkersDictionary = None, optic_parameters: ArUcoOpticCalibrator.OpticParameters = None, parameters: DetectorParameters = None): + """Initialize ArUcoDetector. Parameters: dictionary: ArUco markers dictionary to detect. - marker_size: Size of ArUco markers to detect in centimeter. optic_parameters: Optic parameters to use for ArUco detection into image. parameters: ArUco detector parameters. """ @@ -155,7 +147,6 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): # Init private attributes self.__dictionary = dictionary - self.__marker_size = marker_size self.__optic_parameters = optic_parameters self.__parameters = parameters @@ -178,11 +169,6 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): return self.__dictionary @property - def marker_size(self) -> float: - """Get aruco detector's marker size.""" - return self.__marker_size - - @property def optic_parameters(self) -> ArUcoOpticCalibrator.OpticParameters: """Get aruco detector's opetic parameters object.""" return self.__optic_parameters @@ -224,9 +210,6 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): new_dictionary = ArUcoMarkersDictionary.ArUcoMarkersDictionary(**dictionary_value) - # Load ArUco marker size - new_marker_size = aruco_detector_data.pop('marker_size') - # Load optic parameters try: optic_parameters_value = aruco_detector_data.pop('optic_parameters') @@ -268,7 +251,7 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): new_parameters = DetectorParameters() # Create aruco detector - return ArUcoDetector(new_dictionary, new_marker_size, new_optic_parameters, new_parameters) + return ArUcoDetector(new_dictionary, new_optic_parameters, new_parameters) @classmethod def from_json(self, json_filepath: str) -> ArUcoDetectorType: @@ -323,7 +306,7 @@ class ArUcoDetector(DataFeatures.PipelineStepObject): for i, marker_id in enumerate(detected_markers_ids): - marker = ArUcoMarker.ArUcoMarker(self.__dictionary, marker_id, self.__marker_size) + marker = ArUcoMarker.ArUcoMarker(self.__dictionary, marker_id) marker.corners = detected_markers_corners[i][0] # No pose estimation: call estimate_markers_pose to get one diff --git a/src/argaze/ArUcoMarkers/ArUcoMarker.py b/src/argaze/ArUcoMarkers/ArUcoMarker.py index 0f368f6..b626ea4 100644 --- a/src/argaze/ArUcoMarkers/ArUcoMarker.py +++ b/src/argaze/ArUcoMarkers/ArUcoMarker.py @@ -8,6 +8,7 @@ __copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" __license__ = "BSD" from dataclasses import dataclass, field +import math from argaze.ArUcoMarkers import ArUcoMarkersDictionary @@ -25,7 +26,7 @@ class ArUcoMarker(): identifier: int """Index into dictionary""" - size: float + size: float = field(default=math.nan) """Size of marker in centimeters.""" corners: numpy.array = field(init=False, repr=False) @@ -47,7 +48,13 @@ class ArUcoMarker(): return self.corners[0].mean(axis=0) def image(self, dpi) -> numpy.array: - """Create marker matrix image at a given resolution.""" + """Create marker matrix image at a given resolution. + + !!! warning + Marker size have to be setup before. + """ + + assert(not math.isnan(self.size)) dimension = round(self.size * dpi / 2.54) # 1 cm = 2.54 inches matrix = numpy.zeros((dimension, dimension, 1), dtype="uint8") @@ -63,6 +70,9 @@ class ArUcoMarker(): image: image where to draw color: marker color (if None, no marker drawn) draw_axes: enable marker axes drawing + + !!! warning + draw_axes needs marker size and pose estimation. """ # Draw marker if required @@ -70,8 +80,8 @@ class ArUcoMarker(): aruco.drawDetectedMarkers(image, [numpy.array([list(self.corners)])], numpy.array([self.identifier]), color) - # Draw marker axes if pose has been estimated and if required - if self.translation.size == 3 and self.rotation.size == 9 and draw_axes is not None: + # Draw marker axes if pose has been estimated, marker have a size and if required + if self.translation.size == 3 and self.rotation.size == 9 and not math.isnan(self.size) and draw_axes is not None: cv2.drawFrameAxes(image, numpy.array(K), numpy.array(D), self.rotation, self.translation, self.size, **draw_axes) diff --git a/src/argaze/DataFeatures.py b/src/argaze/DataFeatures.py index 688ad4a..a3b7034 100644 --- a/src/argaze/DataFeatures.py +++ b/src/argaze/DataFeatures.py @@ -218,7 +218,6 @@ class TimeStampedBuffer(collections.OrderedDict): raise KeyError(f'No data stored before {ts} timestamp.') - def get_last_until(self, ts) -> Tuple[TimeStampType, DataType]: """Retreive last item timestamp until a given timestamp value.""" @@ -410,6 +409,24 @@ class PipelineStepObject(): # parent attribute will be setup later by parent it self self.__parent = None + def __enter__(self): + """At with statement start.""" + + # Start observers + for observer_name, observer in self.__observers.items(): + + observer.__enter__() + + return self + + def __exit__(self, type, value, traceback): + """At with statement end.""" + + # End observers + for observer_name, observer in self.__observers.items(): + + observer.__exit__(type, value, traceback) + @property def name(self) -> str: """Get layer's name.""" @@ -441,7 +458,6 @@ class PipelineStepObject(): Returns: object_data: dictionary with pipeline step object attributes values. """ - return { "name": self.__name, "observers": self.__observers @@ -655,3 +671,21 @@ class PipelineStepObserver(): !!! note To subscribe to a method call, the inherited class simply needs to define 'on_' functions with timestamp and object argument. """ + + def __enter__(self): + """ + Define abstract __enter__ method to use observer as a context. + + !!! warning + This method is called provided that the observed PipelineStepObject is created as a context using a with statement. + """ + return self + + def __exit__(self, type, value, traceback): + """ + Define abstract __exit__ method to use observer as a context. + + !!! warning + This method is called provided that the observed PipelineStepObject is created as a context using a with statement. + """ + pass \ No newline at end of file -- cgit v1.1