#!/usr/bin/env python """ """ __author__ = "Théo de la Hogue" __credits__ = [] __copyright__ = "Copyright 2023, Ecole Nationale de l'Aviation Civile (ENAC)" __license__ = "BSD" from dataclasses import dataclass, field from argaze.ArUcoMarkers import ArUcoMarkersDictionary import numpy import cv2 as cv import cv2.aruco as aruco @dataclass class ArUcoMarker(): """Define ArUco marker class.""" dictionary: ArUcoMarkersDictionary.ArUcoMarkersDictionary """Dictionary to which it belongs.""" identifier: int """Index into dictionary""" size: float """Size of marker in centimeters.""" corners: numpy.array = field(init=False, repr=False) """Estimated 2D corner positions in camera image referential.""" translation: numpy.array = field(init=False, repr=False) """Estimated 3D center position in camera world referential.""" rotation: numpy.array = field(init=False, repr=False) """Estimated 3D marker rotation in camera world referential.""" points: numpy.array = field(init=False, repr=False) """Estimated 3D corners positions in camera world referential.""" color: tuple = field(init=False, repr=False, default_factory=lambda : (0, 255, 0)) """Color used to draw marker on frame.""" @property def center(self) -> numpy.array: """Get 2D center position in camera image referential.""" return self.corners[0].mean(axis=0) def image(self, dpi) -> numpy.array: """Create marker matrix image at a given resolution.""" dimension = round(self.size * dpi / 2.54) # 1 cm = 2.54 inches matrix = numpy.zeros((dimension, dimension, 1), dtype="uint8") aruco.generateImageMarker(self.dictionary.markers, self.identifier, dimension, matrix, 1) return numpy.repeat(matrix, 3).reshape(dimension, dimension, 3) def draw(self, frame: numpy.array, K, D): """Draw marker in frame.""" # Draw marker axis if pose has been estimated if self.translation.size == 3 and self.rotation.size == 9: cv.drawFrameAxes(frame, numpy.array(K), numpy.array(D), self.rotation, self.translation, self.size) aruco.drawDetectedMarkers(frame, [self.corners], numpy.array([self.identifier]), self.color) def save(self, destination_folder, dpi): """Save marker image as .png file into a destination folder.""" filename = f'{self.dictionary.name}_{self.dictionary.format}_{self.identifier}.png' filepath = f'{destination_folder}/{filename}' cv.imwrite(filepath, self.image(dpi))