diff --git a/Python/OAK/datasets/oak-fcc-3/utils/manual_fusion_calibrator.py b/Python/OAK/datasets/oak-fcc-3/utils/manual_fusion_calibrator.py index 734c084ab..31d399b6c 100644 --- a/Python/OAK/datasets/oak-fcc-3/utils/manual_fusion_calibrator.py +++ b/Python/OAK/datasets/oak-fcc-3/utils/manual_fusion_calibrator.py @@ -242,7 +242,25 @@ def save_offsets_json(path, data): def require_aruco(): if not hasattr(cv2, "aruco"): - raise RuntimeError("cv2.aruco não disponível. Instale opencv-contrib-python no ambiente.") + raise RuntimeError( + "cv2.aruco não disponível. Instale opencv-contrib-python no ambiente." + ) + + has_detector = hasattr(cv2.aruco, "ArucoDetector") or hasattr(cv2.aruco, "detectMarkers") + has_charuco = hasattr(cv2.aruco, "CharucoBoard") or hasattr(cv2.aruco, "CharucoBoard_create") + + if not has_detector: + raise RuntimeError( + "cv2.aruco existe, mas não tem ArucoDetector nem detectMarkers. " + "Provável instalação incompleta/incompatível do OpenCV. " + "Use opencv-contrib-python." + ) + + if not has_charuco: + raise RuntimeError( + "cv2.aruco existe, mas não tem suporte ChArUco. " + "Use opencv-contrib-python." + ) def get_aruco_dictionary(dict_name: str): @@ -319,6 +337,99 @@ def to_gray_u8_for_charuco(img01, equalize=True, invert=False): return gray +def detect_aruco_markers_compat(gray, dictionary, detector_params): + if hasattr(cv2.aruco, "ArucoDetector"): + detector = cv2.aruco.ArucoDetector(dictionary, detector_params) + return detector.detectMarkers(gray) + + if hasattr(cv2.aruco, "detectMarkers"): + return cv2.aruco.detectMarkers( + gray, + dictionary, + parameters=detector_params, + ) + + raise RuntimeError( + "Nenhuma API compatível para detectar ArUco foi encontrada. " + "Instale opencv-contrib-python no ambiente atual." + ) + + +def refine_detected_markers_compat(gray, board, dictionary, detector_params, corners, ids, rejected): + if ids is None or len(ids) == 0: + return corners, ids, rejected + + try: + if hasattr(cv2.aruco, "ArucoDetector"): + detector = cv2.aruco.ArucoDetector(dictionary, detector_params) + + result = detector.refineDetectedMarkers( + image=gray, + board=board, + detectedCorners=corners, + detectedIds=ids, + rejectedCorners=rejected, + ) + + if isinstance(result, tuple) and len(result) >= 3: + return result[0], result[1], result[2] + + return corners, ids, rejected + + if hasattr(cv2.aruco, "refineDetectedMarkers"): + result = cv2.aruco.refineDetectedMarkers( + gray, + board, + corners, + ids, + rejected, + ) + + if isinstance(result, tuple) and len(result) >= 3: + return result[0], result[1], result[2] + + except Exception: + pass + + return corners, ids, rejected + + +def interpolate_charuco_compat(gray, board, corners, ids): + if ids is None or len(ids) == 0: + return 0, None, None + + if hasattr(cv2.aruco, "interpolateCornersCharuco"): + return cv2.aruco.interpolateCornersCharuco( + markerCorners=corners, + markerIds=ids, + image=gray, + board=board, + ) + + if hasattr(cv2.aruco, "CharucoDetector"): + detector = cv2.aruco.CharucoDetector(board) + + try: + result = detector.detectBoard( + image=gray, + markerCorners=corners, + markerIds=ids, + ) + except TypeError: + result = detector.detectBoard(gray, corners, ids) + + if isinstance(result, tuple) and len(result) >= 2: + charuco_corners = result[0] + charuco_ids = result[1] + ret = 0 if charuco_ids is None else len(charuco_ids) + return ret, charuco_corners, charuco_ids + + raise RuntimeError( + "Nenhuma API compatível para interpolar ChArUco foi encontrada. " + "Verifique se o ambiente usa opencv-contrib-python." + ) + + def detect_charuco_points( img01, board, @@ -332,27 +443,36 @@ def detect_charuco_points( Retorna dict: charuco_id -> (x, y), além de resumo de detecção. Compatível com APIs nova/legada do OpenCV. """ + gray = to_gray_u8_for_charuco(img01, equalize=equalize, invert=invert) if gray is None: return {}, {"markers": 0, "corners": 0, "ok": False} - # API nova pode ter ArucoDetector, mas detectMarkers continua existindo em quase todos. - corners, ids, rejected = cv2.aruco.detectMarkers(gray, dictionary, parameters=detector_params) + corners, ids, rejected = detect_aruco_markers_compat( + gray, + dictionary, + detector_params, + ) n_markers = 0 if ids is None else int(len(ids)) if ids is None or n_markers < min_markers: return {}, {"markers": n_markers, "corners": 0, "ok": False} - try: - cv2.aruco.refineDetectedMarkers(gray, board, corners, ids, rejected) - except Exception: - pass + corners, ids, rejected = refine_detected_markers_compat( + gray, + board, + dictionary, + detector_params, + corners, + ids, + rejected, + ) - ret, charuco_corners, charuco_ids = cv2.aruco.interpolateCornersCharuco( - markerCorners=corners, - markerIds=ids, - image=gray, - board=board, + ret, charuco_corners, charuco_ids = interpolate_charuco_compat( + gray, + board, + corners, + ids, ) if charuco_corners is None or charuco_ids is None: @@ -467,11 +587,11 @@ def main(): # ChArUco automático parser.add_argument("--charuco_auto", action="store_true", help="Inicia direto no modo de homografia automática por ChArUco.") - parser.add_argument("--charuco_dictionary", default="DICT_5X5_100") - parser.add_argument("--charuco_squares_x", type=int, default=7) - parser.add_argument("--charuco_squares_y", type=int, default=5) - parser.add_argument("--charuco_square_length", type=float, default=1.0) - parser.add_argument("--charuco_marker_length", type=float, default=0.70) + parser.add_argument("--charuco_dictionary", default="DICT_4X4_50") + parser.add_argument("--charuco_squares_x", type=int, default=13) + parser.add_argument("--charuco_squares_y", type=int, default=7) + parser.add_argument("--charuco_square_length", type=float, default=0.031) + parser.add_argument("--charuco_marker_length", type=float, default=0.023) parser.add_argument("--charuco_min_markers", type=int, default=4) parser.add_argument("--charuco_min_common_corners", type=int, default=8) parser.add_argument("--charuco_ransac_px", type=float, default=3.0) @@ -684,7 +804,7 @@ def main(): charuco_last["summary"] = {"rgb": rgb_sum, "re": re_sum, "nir": nir_sum} if not rgb_pts: - return False, "ChArUco: RGB não detectou cantos válidos" + return False, "ChArUco: RGB nao detectou cantos validos" charuco_sample_id += 1 messages = []