Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

What is the intended result of ChArUco diamond detection?

I've recently gotten into using the ArUco module in OpenCV 3.1 in order to do pose estimation for a project I'm working on. However, in the course of attempting to estimate pose and draw an axis, the detecting diamonds started behaving like below (diamonds are red borders, for the sake of clarity). My first thought is that diamonds should be surrounding the black checkerboard squares that are bordered by four markers and that the 5 diamonds below aren't accurate but I really don't have a clue. The second issue I've run into is that during live tests, pose estimate is very erratic. The drawn axis (from pose estimation) jumps around the entire image seemingly at random and nothing I've done so far has enabled me to get a reliable pose estimate even with a static camera and ChArUco board.

  1. Are the detected diamonds below accurate? If so, why (ELI5 if possible :) )?
  2. Why isn't the axis for the ChArUco board being drawn in the image below?
  3. Am I doing something wrong in the code below that's causing the live pose estimates to be so erratic?

    image description

import cv2
import numpy as np

def draw_axis(img, charuco_corners, charuco_ids, board):
    vecs = np.load("./calib.npz")  # I already calibrated the camera
    mtx, dist, _, _ = [vecs[i] for i in ('mtx', 'dist', 'rvecs', 'tvecs')]
    ret, rvec, tvec = cv2.aruco.estimatePoseCharucoBoard(
        charuco_corners, charuco_ids, board, mtx, dist)
    if ret is not None and ret is True:
        cv2.aruco.drawAxis(img, mtx, dist, rvec, tvec, 0.1)

def get_image(camera):
    ret, img = camera.read()
    return img

def make_grayscale(img):
    ret = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    return ret

def main():
    camera = cv2.VideoCapture(0)
    img = get_image(camera)
    while True:
        cv2.imshow('calibration', img)
        cv2.waitKey(10)
        img = get_image(camera)
        gray = make_grayscale(img)
        corners, ids, rejected = cv2.aruco.detectMarkers(gray, aruco_dict,
                                                         corners, ids)
        cv2.aruco.drawDetectedMarkers(img, corners, ids)
        if ids is not None and corners is not None \
                and len(ids) > 0 and len(ids) == len(corners):
            diamond_corners, diamond_ids = \
                cv2.aruco.detectCharucoDiamond(img, corners, ids,
                                               0.05 / 0.03, cameraMatrix=mtx,
                                               distCoeffs=dist)
            cv2.aruco.drawDetectedDiamonds(img, diamond_corners, diamond_ids)
            '''if diamond_ids is not None and len(diamond_ids) >= 4:
                break'''
            board = cv2.aruco.CharucoBoard_create(9, 6, 0.05, 0.03,
                                                  aruco_dict)
            if diamond_corners is not None and diamond_ids is not None \
                    and len(diamond_corners) == len(diamond_ids):
                count, char_corners, char_ids = \
                    cv2.aruco.interpolateCornersCharuco(diamond_corners,
                                                        diamond_ids, gray,
                                                        board)
                if count >= 3:
                    draw_axis(img, char_corners, char_ids, board)

if __name__ == '__main__':
    main()