From 8113ee988e85a501338bf6ea8a8159fcc3365038 Mon Sep 17 00:00:00 2001 From: Théo de la Hogue Date: Tue, 29 Mar 2022 17:16:04 +0200 Subject: Improving ArUco markers library managment --- src/argaze/ArUcoMarkers/ArUcoBoard.py | 49 +++----- src/argaze/ArUcoMarkers/ArUcoMarkers.py | 134 ---------------------- src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py | 115 +++++++++++++++++++ src/argaze/ArUcoMarkers/ArUcoTracker.py | 63 ++-------- src/argaze/ArUcoMarkers/__init__.py | 2 +- src/argaze/utils/export_aruco_markers.py | 8 +- 6 files changed, 141 insertions(+), 230 deletions(-) delete mode 100644 src/argaze/ArUcoMarkers/ArUcoMarkers.py create mode 100644 src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py diff --git a/src/argaze/ArUcoMarkers/ArUcoBoard.py b/src/argaze/ArUcoMarkers/ArUcoBoard.py index ce4abd8..de50363 100644 --- a/src/argaze/ArUcoMarkers/ArUcoBoard.py +++ b/src/argaze/ArUcoMarkers/ArUcoBoard.py @@ -1,47 +1,19 @@ #!/usr/bin/env python +from argaze.ArUcoMarkers import ArUcoMarkersDictionary + import numpy import cv2 as cv import cv2.aruco as aruco -# Built-in ArUco dictionaries from OpenCV library -ARUCO_DICT = { - 'DICT_4X4_50': aruco.DICT_4X4_50, - 'DICT_4X4_100': aruco.DICT_4X4_100, - 'DICT_4X4_250': aruco.DICT_4X4_250, - 'DICT_4X4_1000': aruco.DICT_4X4_1000, - 'DICT_5X5_50': aruco.DICT_5X5_50, - 'DICT_5X5_100': aruco.DICT_5X5_100, - 'DICT_5X5_250': aruco.DICT_5X5_250, - 'DICT_5X5_1000': aruco.DICT_5X5_1000, - 'DICT_6X6_50': aruco.DICT_6X6_50, - 'DICT_6X6_100': aruco.DICT_6X6_100, - 'DICT_6X6_250': aruco.DICT_6X6_250, - 'DICT_6X6_1000': aruco.DICT_6X6_1000, - 'DICT_7X7_50': aruco.DICT_7X7_50, - 'DICT_7X7_100': aruco.DICT_7X7_100, - 'DICT_7X7_250': aruco.DICT_7X7_250, - 'DICT_7X7_1000': aruco.DICT_7X7_1000, - 'DICT_ARUCO_ORIGINAL': aruco.DICT_ARUCO_ORIGINAL -} - class ArUcoBoard(): """Calibration chess board with ArUco markers inside.""" def __init__(self, aruco_dictionary_name: str, columns: int, rows: int, square_size: float, marker_size: float): """Create columnsxrows chess board with ArUco markers type at given sizes in centimeters.""" - # check aruco dictionary name - if ARUCO_DICT.get(aruco_dictionary_name, None) is None: - raise NameError(f'Bad ArUco dictionnary name: {aruco_dictionary_name}') - - dict_name_split = aruco_dictionary_name.split('_') - - self.__aruco_dict_format = dict_name_split[1] - self.__aruco_dict_number = int(dict_name_split[2]) - - # load ArUco dictionary - self.__aruco_dict = aruco.Dictionary_get(ARUCO_DICT[aruco_dictionary_name]) + # load ArUco markers dictionary + self.__aruco_dict = ArUcoMarkersDictionary.ArUcoMarkersDictionary(aruco_dictionary_name) # store property self.__columns = columns @@ -50,7 +22,7 @@ class ArUcoBoard(): self.__marker_size = marker_size # in cm # create board model - self.__board = aruco.CharucoBoard_create(self.__columns, self.__rows, self.__square_size/100., self.__marker_size/100., self.__aruco_dict) + self.__board = aruco.CharucoBoard_create(self.__columns, self.__rows, self.__square_size/100., self.__marker_size/100., self.__aruco_dict.get_markers()) def __del__(self): pass @@ -65,13 +37,20 @@ class ArUcoBoard(): def get_size(self): """Get numbers of columns and rows.""" - return self.__board.getChessboardSize() + def get_markers_number(self): + """Get number of markers.""" + return len(self.__board.ids) + + def get_corners_number(self): + """Get number of corners.""" + return (self.__board.getChessboardSize()[0] - 1 ) * (self.__board.getChessboardSize()()[1] - 1) + def export(self, destination_folder: str, dpi: int): """Save a picture of the calibration board.""" - output_filename = f'board_{self.__columns*self.__square_size}cmx{self.__rows*self.__square_size}cm_markers_{self.__aruco_dict_format}_{self.__marker_size}cm.png' + output_filename = f'board_{self.__columns*self.__square_size}cmx{self.__rows*self.__square_size}cm_markers_{self.__aruco_dict.get_markers_format()}_{self.__marker_size}cm.png' dimension = [int(e * self.__board.getSquareLength() * 254 * dpi) for e in self.__board.getChessboardSize()] # 1 meter = 254 inches diff --git a/src/argaze/ArUcoMarkers/ArUcoMarkers.py b/src/argaze/ArUcoMarkers/ArUcoMarkers.py deleted file mode 100644 index 9f7e96b..0000000 --- a/src/argaze/ArUcoMarkers/ArUcoMarkers.py +++ /dev/null @@ -1,134 +0,0 @@ -#!/usr/bin/env python - -import numpy -import cv2 as cv -import cv2.aruco as aruco - -# Built-in ArUco dictionaries from OpenCV library -ARUCO_DICT = { - 'DICT_4X4_50': aruco.DICT_4X4_50, - 'DICT_4X4_100': aruco.DICT_4X4_100, - 'DICT_4X4_250': aruco.DICT_4X4_250, - 'DICT_4X4_1000': aruco.DICT_4X4_1000, - 'DICT_5X5_50': aruco.DICT_5X5_50, - 'DICT_5X5_100': aruco.DICT_5X5_100, - 'DICT_5X5_250': aruco.DICT_5X5_250, - 'DICT_5X5_1000': aruco.DICT_5X5_1000, - 'DICT_6X6_50': aruco.DICT_6X6_50, - 'DICT_6X6_100': aruco.DICT_6X6_100, - 'DICT_6X6_250': aruco.DICT_6X6_250, - 'DICT_6X6_1000': aruco.DICT_6X6_1000, - 'DICT_7X7_50': aruco.DICT_7X7_50, - 'DICT_7X7_100': aruco.DICT_7X7_100, - 'DICT_7X7_250': aruco.DICT_7X7_250, - 'DICT_7X7_1000': aruco.DICT_7X7_1000, - 'DICT_ARUCO_ORIGINAL': aruco.DICT_ARUCO_ORIGINAL, - 'DICT_APRILTAG_16h5': aruco.DICT_APRILTAG_16h5, - 'DICT_APRILTAG_25h9': aruco.DICT_APRILTAG_16h5, - 'DICT_APRILTAG_36h10': aruco.DICT_APRILTAG_36h10, - 'DICT_APRILTAG_36h11': aruco.DICT_APRILTAG_36h11 -} - -class ArUcoMarkers(): - """Markers factory.""" - - def __init__(self, aruco_dictionary_name): - """Define which markers library to edit: - - 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 - """ - - # check aruco dictionary name - if ARUCO_DICT.get(aruco_dictionary_name, None) is None: - raise NameError(f'Bad ArUco dictionnary name: {aruco_dictionary_name}') - - dict_name_split = aruco_dictionary_name.split('_') - - self.__aruco_dict_format = dict_name_split[1] - - # DICT_ARUCO_ORIGINAL case - if self.__aruco_dict_format == 'ARUCO': - - self.__aruco_dict_format = '5X5' - self.__aruco_dict_number = 1024 - - # DICT_APRILTAG_ case - elif self.__aruco_dict_format == 'APRILTAG': - - april_tag_format = dict_name_split[2] - - if april_tag_format == '16h5': - - self.__aruco_dict_format = '4X4' - self.__aruco_dict_number = 30 - - elif april_tag_format == '25h9': - - self.__aruco_dict_format = '5X5' - self.__aruco_dict_number = 30 - - elif april_tag_format == '36h10': - - self.__aruco_dict_format = '6X6' - self.__aruco_dict_number = 2320 - - elif april_tag_format == '36h11': - - self.__aruco_dict_format = '6X6' - self.__aruco_dict_number = 587 - - # other cases - else: - - self.__aruco_dict_number = int(dict_name_split[2]) - - # load ArUco dictionary - self.__aruco_dict = aruco.Dictionary_get(ARUCO_DICT[aruco_dictionary_name]) - - def __del__(self): - pass - - def export(self, destination_folder, dpi, i): - """Save one marker into a .png file.""" - - if i >= 0 and i < self.__aruco_dict_number: - - output_filename = f'marker_{self.__aruco_dict_format}_{i}.png' - - # create marker - marker = numpy.zeros((dpi, dpi, 1), dtype="uint8") - aruco.drawMarker(self.__aruco_dict, i, dpi, marker, 1) - - # save marker into destination folder - cv.imwrite(f'{destination_folder}/{output_filename}', marker) - - else: - raise ValueError(f'Bad ArUco index: {i}') - - def export_all(self, destination_folder, dpi): - """Save all library markers into separated .png files.""" - - for i in range(self.__aruco_dict_number): - - self.export(destination_folder, dpi, i) - - diff --git a/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py b/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py new file mode 100644 index 0000000..f8060f3 --- /dev/null +++ b/src/argaze/ArUcoMarkers/ArUcoMarkersDictionary.py @@ -0,0 +1,115 @@ +#!/usr/bin/env python + +import cv2 as cv +import cv2.aruco as aruco +import numpy + +all_aruco_markers_dictionaries = { + 'DICT_4X4_50': aruco.DICT_4X4_50, + 'DICT_4X4_100': aruco.DICT_4X4_100, + 'DICT_4X4_250': aruco.DICT_4X4_250, + 'DICT_4X4_1000': aruco.DICT_4X4_1000, + 'DICT_5X5_50': aruco.DICT_5X5_50, + 'DICT_5X5_100': aruco.DICT_5X5_100, + 'DICT_5X5_250': aruco.DICT_5X5_250, + 'DICT_5X5_1000': aruco.DICT_5X5_1000, + 'DICT_6X6_50': aruco.DICT_6X6_50, + 'DICT_6X6_100': aruco.DICT_6X6_100, + 'DICT_6X6_250': aruco.DICT_6X6_250, + 'DICT_6X6_1000': aruco.DICT_6X6_1000, + 'DICT_7X7_50': aruco.DICT_7X7_50, + 'DICT_7X7_100': aruco.DICT_7X7_100, + 'DICT_7X7_250': aruco.DICT_7X7_250, + 'DICT_7X7_1000': aruco.DICT_7X7_1000, + 'DICT_ARUCO_ORIGINAL': aruco.DICT_ARUCO_ORIGINAL, + 'DICT_APRILTAG_16h5': aruco.DICT_APRILTAG_16h5, + 'DICT_APRILTAG_25h9': aruco.DICT_APRILTAG_16h5, + 'DICT_APRILTAG_36h10': aruco.DICT_APRILTAG_36h10, + 'DICT_APRILTAG_36h11': aruco.DICT_APRILTAG_36h11 +} +"""Dictionnary to list all built-in ArUco markers dictionaries from OpenCV package.""" + +class ArUcoMarkersDictionary(): + """Handle an ArUco markers dictionary.""" + + def __init__(self, aruco_dictionary_name): + + if all_aruco_markers_dictionaries.get(aruco_dictionary_name, None) is None: + raise NameError(f'Bad ArUco markers dictionary name: {aruco_dictionary_name}') + + dict_name_split = aruco_dictionary_name.split('_') + + self.__format = dict_name_split[1] + + # DICT_ARUCO_ORIGINAL case + if self.__format == 'ARUCO': + + self.__format = '5X5' + self.__number = 1024 + + # DICT_APRILTAG_ case + elif self.__format == 'APRILTAG': + + april_tag_format = dict_name_split[2] + + if april_tag_format == '16h5': + + self.__format = '4X4' + self.__number = 30 + + elif april_tag_format == '25h9': + + self.__format = '5X5' + self.__number = 30 + + elif april_tag_format == '36h10': + + self.__format = '6X6' + self.__number = 2320 + + elif april_tag_format == '36h11': + + self.__format = '6X6' + self.__number = 587 + + # other cases + else: + + self.__number = int(dict_name_split[2]) + + self.__aruco_dict = aruco.Dictionary_get(all_aruco_markers_dictionaries[aruco_dictionary_name]) + + def get_markers(self): + return self.__aruco_dict + + def get_markers_format(self): + return self.__format + + def get_markers_number(self): + return self.__number + + def export_as_png(self, destination_folder, dpi, i): + """Save one marker into a .png file.""" + + if i >= 0 and i < self.__number: + + output_filename = f'marker_{self.__format}_{i}.png' + + print(destination_folder, output_filename) + + # create marker + marker = numpy.zeros((dpi, dpi, 1), dtype="uint8") + aruco.drawMarker(self.__aruco_dict, i, dpi, marker, 1) + + # save marker into destination folder + cv.imwrite(f'{destination_folder}/{output_filename}', marker) + + else: + raise ValueError(f'Bad ArUco index: {i}') + + def export_all(self, destination_folder, dpi): + """Save all markers dictionary into separated .png files.""" + + for i in range(self.__number): + + self.export_as_png(destination_folder, dpi, i) diff --git a/src/argaze/ArUcoMarkers/ArUcoTracker.py b/src/argaze/ArUcoMarkers/ArUcoTracker.py index 93cb5c8..29e862f 100644 --- a/src/argaze/ArUcoMarkers/ArUcoTracker.py +++ b/src/argaze/ArUcoMarkers/ArUcoTracker.py @@ -1,68 +1,19 @@ #!/usr/bin/env python +from argaze.ArUcoMarkers import ArUcoMarkersDictionary, ArUcoCamera + import numpy import cv2 as cv import cv2.aruco as aruco -# Built-in ArUco dictionaries from OpenCV library -ARUCO_DICT = { - 'DICT_4X4_50': aruco.DICT_4X4_50, - 'DICT_4X4_100': aruco.DICT_4X4_100, - 'DICT_4X4_250': aruco.DICT_4X4_250, - 'DICT_4X4_1000': aruco.DICT_4X4_1000, - 'DICT_5X5_50': aruco.DICT_5X5_50, - 'DICT_5X5_100': aruco.DICT_5X5_100, - 'DICT_5X5_250': aruco.DICT_5X5_250, - 'DICT_5X5_1000': aruco.DICT_5X5_1000, - 'DICT_6X6_50': aruco.DICT_6X6_50, - 'DICT_6X6_100': aruco.DICT_6X6_100, - 'DICT_6X6_250': aruco.DICT_6X6_250, - 'DICT_6X6_1000': aruco.DICT_6X6_1000, - 'DICT_7X7_50': aruco.DICT_7X7_50, - 'DICT_7X7_100': aruco.DICT_7X7_100, - 'DICT_7X7_250': aruco.DICT_7X7_250, - 'DICT_7X7_1000': aruco.DICT_7X7_1000, - 'DICT_ARUCO_ORIGINAL': aruco.DICT_ARUCO_ORIGINAL, - 'DICT_APRILTAG_16h5': aruco.DICT_APRILTAG_16h5, - 'DICT_APRILTAG_25h9': aruco.DICT_APRILTAG_16h5, - 'DICT_APRILTAG_36h10': aruco.DICT_APRILTAG_36h10, - 'DICT_APRILTAG_36h11': aruco.DICT_APRILTAG_36h11 -} - class ArUcoTracker(): """Track ArUco markers into a frame.""" - def __init__(self, aruco_dictionary_name, marker_length, camera): - """Define which markers library to track and their size: - - 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 - """ - - # check aruco dictionary name - if ARUCO_DICT.get(aruco_dictionary_name, None) is None: - raise NameError(f'Bad ArUco dictionnary name: {aruco_dictionary_name}') - - # load ArUco dictionary - self.__aruco_dict = aruco.Dictionary_get(ARUCO_DICT[aruco_dictionary_name]) + def __init__(self, aruco_dictionary_name: str, marker_length: float, camera: ArUcoCamera.ArUcoCamera): + """Define which markers library to track and their size""" + + # load ArUco markers dictionary + self.__aruco_dict = ArUcoMarkersDictionary.ArUcoMarkersDictionary(aruco_dictionary_name) # define marker length in centimeter self.__marker_length = marker_length diff --git a/src/argaze/ArUcoMarkers/__init__.py b/src/argaze/ArUcoMarkers/__init__.py index 1d214be..28386d2 100644 --- a/src/argaze/ArUcoMarkers/__init__.py +++ b/src/argaze/ArUcoMarkers/__init__.py @@ -2,4 +2,4 @@ .. include:: README.md """ __docformat__ = "restructuredtext" -__all__ = ['ArUcoBoard', 'ArUcoCamera', 'ArUcoMarkers', 'ArUcoTracker'] \ No newline at end of file +__all__ = ['ArUcoMarkersDictionary', 'ArUcoBoard', 'ArUcoCamera', 'ArUcoTracker'] \ No newline at end of file diff --git a/src/argaze/utils/export_aruco_markers.py b/src/argaze/utils/export_aruco_markers.py index 2bc878e..78c996f 100644 --- a/src/argaze/utils/export_aruco_markers.py +++ b/src/argaze/utils/export_aruco_markers.py @@ -3,7 +3,7 @@ import argparse import os -from argaze.ArUcoMarkers import ArUcoMarkers +from argaze.ArUcoMarkers import ArUcoMarkersDictionary def main(): """Generates ArUco markers to place into a scene.""" @@ -20,11 +20,11 @@ def main(): os.makedirs(args.output) print(f'{args.output} folder created') - # create aruco markers - aruco_markers = ArUcoMarkers.ArUcoMarkers(args.dictionary) + # create aruco markers dictionary + aruco_markers_dict = ArUcoMarkersDictionary.ArUcoMarkersDictionary(args.dictionary) # export markers - aruco_markers.export_all(args.output, args.resolution) + aruco_markers_dict.export_all(args.output, args.resolution) if __name__ == '__main__': -- cgit v1.1