Source code for naps.aruco

#!/usr/bin/env python
import cv2.aruco


[docs]class ArUcoModel: """Class providing a wrapper around the cv2.aruco library""" def __init__( self, tag_set: str, adaptiveThreshWinSizeMin: int, adaptiveThreshWinSizeMax: int, adaptiveThreshWinSizeStep: int, adaptiveThreshConstant: float, perspectiveRemoveIgnoredMarginPerCell: float, errorCorrectionRate: float, **kwargs, ): # Store the tag set self.tag_set = tag_set # Store the ArUco parameters self.adaptiveThreshWinSizeMin = adaptiveThreshWinSizeMin self.adaptiveThreshWinSizeMax = adaptiveThreshWinSizeMax self.adaptiveThreshWinSizeStep = adaptiveThreshWinSizeStep self.adaptiveThreshConstant = adaptiveThreshConstant self.errorCorrectionRate = errorCorrectionRate self.perspectiveRemoveIgnoredMarginPerCell = ( perspectiveRemoveIgnoredMarginPerCell ) """ Set the ArUco dict and params to None. Create w/ buildModel as we cannot pickle them when using multiprocessing """ self.aruco_dict = None self.aruco_params = None self.model_built = False @classmethod def withTagSet(cls, tag_set, **kwargs): return cls(tag_set, **kwargs) def build(self): # Assign the aruco dict self.aruco_dict = self._assignArucoDict(self.tag_set) """ ArUco parameters: These have been adjusted by dyknapp but are worth playing with if ArUco is too slow or not detecting enough tags. These thresholding parameters DRAMATICALLY improve detection rate, while DRAMATICALLY hurting performance. Since super fast processing isn't really necessary here they should be fine as is. """ self.aruco_params = cv2.aruco.DetectorParameters_create() """ Assign the corner refinement method: Should we permit all options? """ self.aruco_params.cornerRefinementMethod = cv2.aruco.CORNER_REFINE_SUBPIX # Window parameters self.aruco_params.adaptiveThreshWinSizeMin = self.adaptiveThreshWinSizeMin self.aruco_params.adaptiveThreshWinSizeMax = self.adaptiveThreshWinSizeMax self.aruco_params.adaptiveThreshWinSizeStep = self.adaptiveThreshWinSizeStep # If too slow, start by adjusting this one up. If we want more tags, lower it (diminishing returns) self.aruco_params.adaptiveThreshConstant = self.adaptiveThreshConstant # No note for this option self.aruco_params.perspectiveRemoveIgnoredMarginPerCell = ( self.perspectiveRemoveIgnoredMarginPerCell ) # If false positives are a problem, lower this parameter. self.aruco_params.errorCorrectionRate = self.errorCorrectionRate # Indicate the model has been built self.model_built = True def detect(self, img): # Check if the image is empty, normally when prediction falls outside the image if 0 in img.shape: return [None] # Build the model if needed if not self.model_built: self.build() # Detect ArUco tag(s) within the image corners, tags, _ = cv2.aruco.detectMarkers( img, self.aruco_dict, parameters=self.aruco_params ) # Return None if no ArUco tag was found if len(corners) == 0: return [None] # Return detected ArUco tags return [marker_tag[0] for _, marker_tag in zip(corners, tags)] def _assignArucoDict(self, tag_set): # Define names of each possible ArUco tag OpenCV supports ARUCO_DICT = { "DICT_4X4_50": cv2.aruco.DICT_4X4_50, "DICT_4X4_100": cv2.aruco.DICT_4X4_100, "DICT_4X4_250": cv2.aruco.DICT_4X4_250, "DICT_4X4_1000": cv2.aruco.DICT_4X4_1000, "DICT_5X5_50": cv2.aruco.DICT_5X5_50, "DICT_5X5_100": cv2.aruco.DICT_5X5_100, "DICT_5X5_250": cv2.aruco.DICT_5X5_250, "DICT_5X5_1000": cv2.aruco.DICT_5X5_1000, "DICT_6X6_50": cv2.aruco.DICT_6X6_50, "DICT_6X6_100": cv2.aruco.DICT_6X6_100, "DICT_6X6_250": cv2.aruco.DICT_6X6_250, "DICT_6X6_1000": cv2.aruco.DICT_6X6_1000, "DICT_7X7_50": cv2.aruco.DICT_7X7_50, "DICT_7X7_100": cv2.aruco.DICT_7X7_100, "DICT_7X7_250": cv2.aruco.DICT_7X7_250, "DICT_7X7_1000": cv2.aruco.DICT_7X7_1000, "DICT_ARUCO_ORIGINAL": cv2.aruco.DICT_ARUCO_ORIGINAL, "DICT_APRILTAG_16h5": cv2.aruco.DICT_APRILTAG_16h5, "DICT_APRILTAG_25h9": cv2.aruco.DICT_APRILTAG_25h9, "DICT_APRILTAG_36h10": cv2.aruco.DICT_APRILTAG_36h10, "DICT_APRILTAG_36h11": cv2.aruco.DICT_APRILTAG_36h11, } # Check there are no problem with the tag set if tag_set not in ARUCO_DICT: raise Exception(f"Unable to assign tag set: {tag_set}") # Return the OpenCV tags return cv2.aruco.Dictionary_get(ARUCO_DICT[tag_set])