From fa0802e176fb8bde21f1e41971781fb9c1a9686d Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 15 Nov 2022 13:53:57 +0100 Subject: Refactoring marker creation. --- src/argaze/ArUcoMarkers/ArUcoMarker.py | 21 +++++++++++- src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py | 40 ++++++++++------------- src/argaze/ArUcoMarkers/README.md | 2 +- src/argaze/utils/README.md | 4 +-- src/argaze/utils/aruco_markers_export.py | 5 +-- 5 files changed, 43 insertions(+), 29 deletions(-) diff --git a/src/argaze/ArUcoMarkers/ArUcoMarker.py b/src/argaze/ArUcoMarkers/ArUcoMarker.py index ef03ffd..5879a7b 100644 --- a/src/argaze/ArUcoMarkers/ArUcoMarker.py +++ b/src/argaze/ArUcoMarkers/ArUcoMarker.py @@ -39,6 +39,16 @@ class ArUcoMarker(): return self.corners[0].mean(axis=0) + def image(self, dpi) -> numpy.array: + """Create marker matrix image at a given resolution.""" + + dimension = round(dpi * self.size / 2.54) + matrix = numpy.zeros((dimension, dimension, 1), dtype="uint8") + + aruco.drawMarker(self.dictionary.markers, self.identifier, dimension, matrix, 1) + + return numpy.repeat(matrix, 3).reshape(dimension, dimension, 3) + def draw(self, frame, K, D): """Draw marker in frame.""" @@ -47,4 +57,13 @@ class ArUcoMarker(): cv.drawFrameAxes(frame, K, D, self.rotation, self.translation, self.size) - aruco.drawDetectedMarkers(frame, [self.corners], numpy.array([self.identifier])) \ No newline at end of file + aruco.drawDetectedMarkers(frame, [self.corners], numpy.array([self.identifier])) + + def save(self, destination_folder, dpi): + """Save marker image as .png file.""" + + filename = f'{self.dictionary.name}_{self.dictionary.format}_{self.identifier}.png' + filepath = f'{destination_folder}/{filename}' + + cv.imwrite(filepath, self.image(dpi)) + diff --git a/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py b/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py index 016c0b5..4f87881 100644 --- a/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py +++ b/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py @@ -1,5 +1,7 @@ #!/usr/bin/env python +from typing import TypeVar + import cv2 as cv import cv2.aruco as aruco import numpy @@ -29,6 +31,9 @@ all_aruco_markers_dictionaries = { } """Dictionnary to list all built-in ArUco markers dictionaries from OpenCV ArUco package.""" +ArUcoMarkerType = TypeVar('ArUcoMarker', bound="ArUcoMarker") +# Type definition for type annotation convenience + class ArUcoMarkersDictionary(): """Handle an ArUco markers dictionary.""" @@ -49,7 +54,7 @@ class ArUcoMarkersDictionary(): self.__format = '5X5' self.__number = 1024 - # DICT_APRILTAG_ case + # DICT_APRILTAG case elif self.__format == 'APRILTAG': april_tag_format = dict_name_split[2] @@ -80,7 +85,7 @@ class ArUcoMarkersDictionary(): self.__number = int(dict_name_split[2]) self.__aruco_dict = aruco.Dictionary_get(all_aruco_markers_dictionaries[self.__name]) - + @property def name(self)-> str: """Get dictionary name.""" @@ -88,7 +93,7 @@ class ArUcoMarkersDictionary(): return self.__name @property - def markers(self)-> aruco.Dictionary: + def markers(self) -> aruco.Dictionary: """Get all markers from dictionary.""" return self.__aruco_dict @@ -100,38 +105,27 @@ class ArUcoMarkersDictionary(): return self.__format @property - def size(self) -> int: + def number(self) -> int: """Get number of markers inside dictionary.""" return self.__number - def create_marker(self, i, dpi=300) -> numpy.array: - """Create a marker image.""" - - marker = numpy.zeros((dpi, dpi, 1), dtype="uint8") - aruco.drawMarker(self.__aruco_dict, i, dpi, marker, 1) - - return numpy.repeat(marker, 3).reshape(dpi, dpi, 3) - - def export_as_png(self, destination_folder, dpi, i): - """Save one marker into a .png file.""" + def create_marker(self, i, size) -> ArUcoMarkerType: + """Create a marker.""" if i >= 0 and i < self.__number: - output_filename = f'marker_{self.__format}_{i}.png' + from argaze.ArUcoMarkers import ArUcoMarker - # create marker - marker = self.create_marker(i, dpi) - - # save marker into destination folder - cv.imwrite(f'{destination_folder}/{output_filename}', marker) + return ArUcoMarker.ArUcoMarker(self, i, size) else: - raise ValueError(f'Bad ArUco index: {i}') - def export_all(self, destination_folder, dpi): + raise ValueError(f'Bad index: {i}') + + def save(self, destination_folder, size, dpi): """Save all markers dictionary into separated .png files.""" for i in range(self.__number): - self.export_as_png(destination_folder, dpi, i) + self.create_marker(i, size).save(destination_folder, dpi) diff --git a/src/argaze/ArUcoMarkers/README.md b/src/argaze/ArUcoMarkers/README.md index 011305f..821a582 100644 --- a/src/argaze/ArUcoMarkers/README.md +++ b/src/argaze/ArUcoMarkers/README.md @@ -2,7 +2,7 @@ Class interface to work with [OpenCV ArUco markers](https://docs.opencv.org/4.x/ ## ArUco markers dictionary -To work with ArUco markers, you need to choose a marker dictionary which have differents property concerning the difference between each markers to avoid error in tracking. +To work with ArUco markers, you need to choose a marker dictionary which have specific the format, the numbers of markers or the difference between each markers to avoid error in tracking. Here is more [about ArUco markers dictionaries](https://docs.opencv.org/3.4/d9/d6a/group__aruco.html#gac84398a9ed9dd01306592dd616c2c975) ## Utils diff --git a/src/argaze/utils/README.md b/src/argaze/utils/README.md index fd1c332..2fc3bab 100644 --- a/src/argaze/utils/README.md +++ b/src/argaze/utils/README.md @@ -10,10 +10,10 @@ Collection of command-line high level features based on ArGaze toolkit. ### ArUco factory -- Export all markers from DICT_APRILTAG_16h5 dictionary at 300 dpi into an export/markers folder: +- Export all markers from DICT_APRILTAG_16h5 dictionary as 5 cm pictures with 300 dpi resolution into an export/markers folder: ``` -python ./src/argaze/utils/aruco_markers_export.py -o export/markers -d DICT_APRILTAG_16h5 +python ./src/argaze/utils/aruco_markers_export.py -o export/markers -d DICT_APRILTAG_16h5 -s 5 -r 300 ``` - Export a 7 columns and 5 rows calibration board made of 5cm squares with 3cm markers from DICT_APRILTAG_16h5 dictionary at 50 dpi into an export folder: diff --git a/src/argaze/utils/aruco_markers_export.py b/src/argaze/utils/aruco_markers_export.py index ce68761..40d3e20 100644 --- a/src/argaze/utils/aruco_markers_export.py +++ b/src/argaze/utils/aruco_markers_export.py @@ -12,7 +12,8 @@ def main(): parser = argparse.ArgumentParser(description=main.__doc__) parser.add_argument('-o', '--output', metavar='OUT', type=str, default='.', help='destination path') parser.add_argument('-d', '--dictionary', metavar='DICT', type=ArUcoMarkersDictionary.ArUcoMarkersDictionary, default='DICT_ARUCO_ORIGINAL', help='aruco marker dictionnary (DICT_4X4_50, DICT_4X4_100, DICT_4X4_250, DICT_4X4_1000, DICT_5X5_50, DICT_5X5_100, DICT_5X5_250, DICT_5X5_1000, DICT_6X6_50, DICT_6X6_100, DICT_6X6_250, DICT_6X6_1000, DICT_7X7_50, DICT_7X7_100, DICT_7X7_250, DICT_7X7_1000, DICT_ARUCO_ORIGINAL, DICT_APRILTAG_16h5, DICT_APRILTAG_25h9, DICT_APRILTAG_36h10, DICT_APRILTAG_36h11)') - parser.add_argument('-r', '--resolution', metavar='RES', type=int, default=300, help='picture resolution in dpi') + parser.add_argument('-s', '--size', metavar='SIZE', type=float, default=3., help='marker size in cm') + parser.add_argument('-r', '--resolution', metavar='RES', type=int, default=50, help='picture resolution in dpi') args = parser.parse_args() # manage destination folder @@ -21,7 +22,7 @@ def main(): print(f'{args.output} folder created') # export markers - args.dictionary.export_all(args.output, args.resolution) + args.dictionary.export_all(args.output, args.size, args.resolution) if __name__ == '__main__': -- cgit v1.1