aboutsummaryrefslogtreecommitdiff
path: root/src/argaze/ArUcoMarkers/ArUcoDetector.py
diff options
context:
space:
mode:
Diffstat (limited to 'src/argaze/ArUcoMarkers/ArUcoDetector.py')
-rw-r--r--src/argaze/ArUcoMarkers/ArUcoDetector.py108
1 files changed, 60 insertions, 48 deletions
diff --git a/src/argaze/ArUcoMarkers/ArUcoDetector.py b/src/argaze/ArUcoMarkers/ArUcoDetector.py
index 82c9394..e62a42e 100644
--- a/src/argaze/ArUcoMarkers/ArUcoDetector.py
+++ b/src/argaze/ArUcoMarkers/ArUcoDetector.py
@@ -38,7 +38,8 @@ ArUcoDetectorType = TypeVar('ArUcoDetector', bound="ArUcoDetector")
class DetectorParameters():
"""Wrapper class around ArUco marker detector parameters.
- .. note:: More details on [opencv page](https://docs.opencv.org/4.x/d1/dcd/structcv_1_1aruco_1_1DetectorParameters.html)
+ !!! note
+ More details on [opencv page](https://docs.opencv.org/4.x/d1/dcd/structcv_1_1aruco_1_1DetectorParameters.html)
"""
__parameters = aruco.DetectorParameters()
@@ -71,7 +72,8 @@ class DetectorParameters():
'minOtsuStdDev',
'perspectiveRemoveIgnoredMarginPerCell',
'perspectiveRemovePixelPerCell',
- 'polygonalApproxAccuracyRate'
+ 'polygonalApproxAccuracyRate',
+ 'useAruco3Detection'
]
def __init__(self, **kwargs):
@@ -98,8 +100,17 @@ class DetectorParameters():
return DetectorParameters(**json.load(configuration_file))
- def __str__(self, print_all=False) -> str:
- """Detector paremeters string representation."""
+ def __str__(self) -> str:
+ """Detector parameters string representation."""
+
+ return f'{self}'
+
+ def __format__(self, spec: str) -> str:
+ """Formated detector parameters string representation.
+
+ Parameters:
+ spec: 'modified' to get only modified parameters.
+ """
output = ''
@@ -109,7 +120,7 @@ class DetectorParameters():
output += f'\t*{parameter}: {getattr(self.__parameters, parameter)}\n'
- elif print_all:
+ elif spec == "":
output += f'\t{parameter}: {getattr(self.__parameters, parameter)}\n'
@@ -121,26 +132,24 @@ class DetectorParameters():
@dataclass
class ArUcoDetector():
- """ArUco markers detector."""
+ """ArUco markers detector.
- dictionary: ArUcoMarkersDictionary.ArUcoMarkersDictionary = field(default_factory=ArUcoMarkersDictionary.ArUcoMarkersDictionary)
- """ArUco markers dictionary to detect."""
+ 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.
+ """
+ dictionary: ArUcoMarkersDictionary.ArUcoMarkersDictionary = field(default_factory=ArUcoMarkersDictionary.ArUcoMarkersDictionary)
marker_size: float = field(default=0.)
- """Size of ArUco markers to detect in centimeter."""
-
optic_parameters: ArUcoOpticCalibrator.OpticParameters = field(default_factory=ArUcoOpticCalibrator.OpticParameters)
- """Optic parameters to use for ArUco detection into image."""
-
parameters: DetectorParameters = field(default_factory=DetectorParameters)
- """ArUco detector parameters."""
def __post_init__(self):
# Init detected markers data
self.__detected_markers = {}
- self.__detected_markers_corners = []
- self.__detected_markers_ids = []
# Init detected board data
self.__board = None
@@ -249,39 +258,41 @@ class ArUcoDetector():
def detect_markers(self, image: numpy.array) -> float:
"""Detect all ArUco markers into an image.
- .. danger:: DON'T MIRROR IMAGE
- It makes the markers detection to fail.
+ !!! danger "DON'T MIRROR IMAGE"
+ It makes the markers detection to fail.
+
+ !!! danger "DON'T UNDISTORED IMAGE"
+ Camera intrisic parameters and distorsion coefficients are used later during pose estimation.
Returns:
- - detection time: marker detection time in ms
+ detection time: marker detection time in ms.
"""
# Reset detected markers data
- self.__detected_markers, self.__detected_markers_corners, self.__detected_markers_ids = {}, [], []
+ self.__detected_markers, detected_markers_corners, detected_markers_ids = {}, [], []
# Store marker detection start date
detection_start = time.perf_counter()
# Detect markers into gray picture
- self.__detected_markers_corners, self.__detected_markers_ids, _ = aruco.detectMarkers(cv.cvtColor(image, cv.COLOR_BGR2GRAY), self.dictionary.markers, parameters = self.parameters.internal)
+ detected_markers_corners, detected_markers_ids, _ = aruco.detectMarkers(cv.cvtColor(image, cv.COLOR_BGR2GRAY), self.dictionary.markers, parameters = self.parameters.internal)
# Assess marker detection time in ms
detection_time = (time.perf_counter() - detection_start) * 1e3
# Is there detected markers ?
- if len(self.__detected_markers_corners) > 0:
+ if len(detected_markers_corners) > 0:
# Transform markers ids array into list
- self.__detected_markers_ids = self.__detected_markers_ids.T[0]
+ detected_markers_ids = detected_markers_ids.T[0]
# Gather detected markers data and update metrics
self.__detection_count += 1
- for i, marker_id in enumerate(self.__detected_markers_ids):
+ for i, marker_id in enumerate(detected_markers_ids):
marker = ArUcoMarker.ArUcoMarker(self.dictionary, marker_id, self.marker_size)
-
- marker.corners = self.__detected_markers_corners[i]
+ marker.corners = detected_markers_corners[i][0]
# No pose estimation: call estimate_markers_pose to get one
marker.translation = numpy.empty([0])
@@ -290,6 +301,7 @@ class ArUcoDetector():
self.__detected_markers[marker_id] = marker
+ # Update metrics
self.__detected_ids.append(marker_id)
return detection_time
@@ -298,31 +310,28 @@ class ArUcoDetector():
"""Estimate pose of current detected markers or of given markers id list."""
# Is there detected markers ?
- if len(self.__detected_markers_corners) > 0:
+ if len(self.__detected_markers) > 0:
- # Is there a marker selection ?
- if len(markers_ids) > 0:
+ # Select all markers by default
+ if len(markers_ids) == 0:
- selected_markers_corners = tuple()
- selected_markers_ids = []
+ markers_ids = self.__detected_markers.keys()
- for i, marker_id in enumerate(self.__detected_markers_ids):
+ # Prepare data for aruco.estimatePoseSingleMarkers function
+ selected_markers_corners = tuple()
+ selected_markers_ids = []
- if marker_id in markers_ids:
+ for marker_id, marker in self.__detected_markers.items():
- selected_markers_corners += (self.__detected_markers_corners[i],)
- selected_markers_ids.append(marker_id)
+ if marker_id in markers_ids:
- # Otherwise, estimate pose of all markers
- else:
-
- selected_markers_corners = self.__detected_markers_corners
- selected_markers_ids = self.__detected_markers_ids
+ selected_markers_corners += (marker.corners,)
+ selected_markers_ids.append(marker_id)
# Estimate pose of selected markers
if len(selected_markers_corners) > 0:
- markers_rvecs, markers_tvecs, markers_points = aruco.estimatePoseSingleMarkers(selected_markers_corners, self.marker_size, numpy.array(self.optic_parameters.K), numpy.array(self.optic_parameters.D))
+ markers_rvecs, markers_tvecs, markers_points = aruco.estimatePoseSingleMarkers(selected_markers_corners, self.marker_size, numpy.array(self.optic_parameters.K), numpy.array(self.optic_parameters.D))
for i, marker_id in enumerate(selected_markers_ids):
@@ -330,7 +339,8 @@ class ArUcoDetector():
marker.translation = markers_tvecs[i][0]
marker.rotation, _ = cv.Rodrigues(markers_rvecs[i][0])
- marker.points = markers_points.reshape(4, 3)
+
+ marker.points = markers_points.reshape(4, 3).dot(marker.rotation) + marker.translation
@property
def detected_markers(self) -> dict[ArUcoMarkerType]:
@@ -361,19 +371,19 @@ class ArUcoDetector():
def detect_board(self, image: numpy.array, board, expected_markers_number):
"""Detect ArUco markers board in image setting up the number of detected markers needed to agree detection.
- .. danger:: DON'T MIRROR IMAGE
- It makes the markers detection to fail.
+ !!! danger "DON'T MIRROR IMAGE"
+ It makes the markers detection to fail.
"""
# detect markers from gray picture
gray = cv.cvtColor(image, cv.COLOR_BGR2GRAY)
- self.__detected_markers_corners, self.__detected_markers_ids, _ = aruco.detectMarkers(gray, self.dictionary.markers, parameters = self.parameters.internal)
+ detected_markers_corners, detected_markers_ids, _ = aruco.detectMarkers(gray, self.dictionary.markers, parameters = self.parameters.internal)
# if all board markers are detected
- if len(self.__detected_markers_corners) == expected_markers_number:
+ if len(detected_markers_corners) == expected_markers_number:
self.__board = board
- self.__board_corners_number, self.__board_corners, self.__board_corners_ids = aruco.interpolateCornersCharuco(self.__detected_markers_corners, self.__detected_markers_ids, gray, self.__board.model)
+ self.__board_corners_number, self.__board_corners, self.__board_corners_ids = aruco.interpolateCornersCharuco(detected_markers_corners, detected_markers_ids, gray, self.__board.model)
else:
@@ -398,9 +408,11 @@ class ArUcoDetector():
@property
def detection_metrics(self) -> Tuple[int, dict]:
"""Get marker detection metrics.
+
Returns:
- number of detect function call
- dict with number of detection for each marker identifier"""
+ number of detect function call
+ dict with number of detection for each marker identifier
+ """
return self.__detection_count, Counter(self.__detected_ids)