1. ChArUco 介绍(Detection of ChArUco Corners)

opencv 标定板点集排序 opencv圆形标定板_插值


Chessboard具有高的交点精度,但是交点提取比较困难。ArUco能够快速检测,但即使使用亚像素精度提取,提取的交点精度也不甚理想。ChArUco集成了Chessboard的高精度与ArUco易用性的优点。

使用ArUco的特征插值出棋盘格黑白块的内角点

2. ChArUco 创建

charuco_board = cv.aruco.CharucoBoard_create(squaresX, squaresY, squareLength, markerLength, dictionary	)

2.1 算子参数

  • squaresX
    X方向棋盘格黑白块的数量
  • squaresY
    Y方向棋盘格黑白块的数量
  • squareLength
    棋盘格黑白块的边长,通常以为单位
  • markerLength
    标志点的边长,单位与参数squareLength的单位相同
  • dictionary
    标志块的编码集合。OpenCV提供了一些内置编码。内置编码命名规则(方便记忆):
    DICT_4X4_50
  • 4X4 两个4分别表示标志块在X与Y方向被划分的数量
  • 50 表示该集合种包含的标志块图案的数量

2.2 参数示意

  • squaresX,squaresY,squareLength,markerLength
  • dictionary
  • cv.aruco.DICT_4X4_50
  • cv.aruco.DICT_7X7_50
  • 编码图案的最小模块(以cv.aruco.DICT_4X4_50为例)
    默认情况下编码区域标志块区域有一个模块单位的距离。这个距离可通过draw函数的borderBits参数进行修改。当指定的编码区域为4X4时,实际的标志块区域被6X6等分。边缘有一个模块单位的间距。

2.3 算子返回值

  • charuco_board
    表示一个CharucoBoard对象实例

3. ChArUco 绘制

img	= cv.aruco_CharucoBoard.draw(charuco_board, outSize, marginSize = 1, borderBits = 1)
aruco_CharucoBoard.draw(self, outSize, img=None, marginSize=None, borderBits=None)

3.1 算子参数

  • charuco_board
    CharucoBoard对象实例
  • outSize
    输出图像的像素尺寸,以元组的形式输入,格式(image_width, image_height)
  • marginSize
    >=0 棋盘格黑白块距离图像边界的最小像素宽度
  • borderBits
    >=1 标志块种的图案编码区域距离标志块边缘的距离,以编码图案的最小模块为单位

3.2 参数示意

  • marginSize
  • = 1
  • = 10
  • borderBits
  • = 1
  • = 3

3.3 算子返回值

  • img
    指定尺寸的二值图像

4. ChArUco 创建与绘制样例

# 如果提示找不到cv2.aruco,请执行以下语句(重装python)
# pip uninstall opencv-python
# pip uninstall opencv-contrib-python
# pip install   opencv-python
# pip install   opencv-contrib-python

import cv2 as cv

dictionary = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_4X4_50)
board=cv.aruco.CharucoBoard_create(7, 7, 0.04, 0.02, dictionary)
img = cv.aruco_CharucoBoard.draw(board, (600, 600), marginSize = 10, borderBits=1)
cv.imwrite('charuco.png',img)

corners, ids, rejectedImgPoints  = cv.aruco.detectMarkers(img, dictionary)
print(corners)
print(ids)
print(rejectedImgPoints)

if(len(ids) > 0):
    cv.aruco.estimatePoseSingleMarkers()

5. ChArUco 标志块检测

当执行ChArUco检测时,首先检测出标志块的角点,每个标志块包含四个角点,按照顺时针顺序排列。

detectMarkers(image, dictionary, corners=None, ids=None, parameters=None, rejectedImgPoints=None, cameraMatrix=None, distCoeff=None)

5.1 算子参数

  • image
    输入图像
  • dictionary
    Charuco的类型
  • corners
    标志块的角点在输入图像坐标系种的坐标。对于每个检测到的标志块会输出四个角点,按照顺时针排列。第一个角点为标志块的左上角点。标志块在corners中的顺序为右下角开始,先从右到左,然后从下到上
  • opencv 标定板点集排序 opencv圆形标定板_角点_02

  • - ids
    检测到的标志块的ID,从零开始。第一个标志块位于生成的标定板图像的左上角。从左到右,从上到下
  • opencv 标定板点集排序 opencv圆形标定板_opencv 标定板点集排序_03

  • parameters
    标志块的检测参数
  • rejectedImgPoints
    指示对应位置的标志块的内部编码是不正确的(无法被识别),用于调试目的
  • cameraMatrix
    相机的内参矩阵(float)opencv 标定板点集排序 opencv圆形标定板_插值_04
  • distCoeff
    相机的扭曲系数opencv 标定板点集排序 opencv圆形标定板_角点_05

6. ChArUco 标志块绘制

drawDetectedMarkers(image, corners, ids=None, borderColor=None)

  • image
    绘制标志块的图像,必须为1/3通道的图像
  • corners
    相对于输入图像坐标系的标志块角点坐标
  • ids
    标志块的ID
  • borderColor
    标志块绘制的颜色

opencv 标定板点集排序 opencv圆形标定板_python_06

7. ChArUco 棋盘格内角点坐标

棋盘格内角点的坐标是通过标志块角点坐标插值得到。

retval, charucoCorners, charucoIds = interpolateCornersCharuco(markerCorners, markerIds, image, board, cameraMatrix=None, distCoeffs=None, minMarkers=None)

  • markerCorners
    标志块的角点坐标
  • markerIds
    标志块的ID
  • image
    用于角点精定位
  • board
    标定板类型
  • charucoCorners
    输出,棋盘格内角点的坐标
  • charucoIds
    输出,棋盘格内焦点的ID
  • opencv 标定板点集排序 opencv圆形标定板_插值_07

  • cameraMatrix
    相机内参矩阵
  • distCoeffs
    相机扭曲系数
  • minMarkers
    相邻的标志块被检测出的最小数量
  • retval
    被插值出的内角点数量

8. 标定板位姿估计

retval, rvec, tvec = estimatePoseCharucoBoard(charucoCorners, charucoIds, board, cameraMatrix, distCoeffs, rvec, tvec[, useExtrinsicGuess]) ```![在这里插入图片描述](https://img-blog.csdnimg.cn/f0f50010e5ba489eab55e468efbadc36.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3poeTI5NTYz,size_16,color_FFFFFF,t_70,#pic_center)

9. 源码

import cv2 as cv
import numpy as np

# 创建ChArUco标定板
dictionary = cv.aruco.getPredefinedDictionary(dict=cv.aruco.DICT_6X6_250)
board = cv.aruco.CharucoBoard_create(squaresY=7,
                                     squaresX=5,
                                     squareLength=0.04,
                                     markerLength=0.02,
                                     dictionary=dictionary)
img_board = board.draw(outSize=(600, 500), marginSize=10, borderBits=1)
cv.imwrite(filename='charuco.png', img=img_board, params=None)

camera_matrix = np.array([[532.79536562, 0, 342.4582516],
                          [0, 532.91928338, 233.90060514],
                          [0, 0, 1.]])
dist_coefs = np.array([-2.81086258e-01, 2.72581018e-02, 1.21665908e-03, -1.34204275e-04, 1.58514022e-01])

# 主要用于图形的绘制与显示
img_color = cv.cvtColor(src=img_board,
                        code=cv.COLOR_GRAY2BGR,
                        dstCn=None)

# 查找标志块的左上角点
corners, ids, rejectedImgPoints = cv.aruco.detectMarkers(image=img_board,
                                                         dictionary=dictionary,
                                                         parameters=None,
                                                         cameraMatrix=camera_matrix,
                                                         distCoeff=dist_coefs)
# print(corners)
# print(ids)
if len(ids) > 0:
    print((int(corners[0][0][0][0]), int(corners[0][0][0][1])))
    print((int(corners[1][0][0][0]), int(corners[1][0][0][1])))
    cv.circle(img_color, (int(corners[0][0][0][0]), int(corners[0][0][0][1])), 8, [0, 255, 0])
    cv.circle(img_color, (int(corners[1][0][0][0]), int(corners[1][0][0][1])), 8, [0, 255, 0])
    cv.circle(img_color, (int(corners[2][0][0][0]), int(corners[2][0][0][1])), 8, [0, 255, 0])
    # 绘制标志块的左上角点与对应的ID
    cv.aruco.drawDetectedMarkers(image=img_color, corners=corners, ids=ids, borderColor=None)
    cv.imshow("out", img_color)
    cv.waitKey()

    # 棋盘格黑白块内角点
    retval, charucoCorners, charucoIds = cv.aruco.interpolateCornersCharuco(markerCorners=corners,
                                                                            markerIds=ids,
                                                                            image=img_board,
                                                                            board=board,
                                                                            cameraMatrix=camera_matrix,
                                                                            distCoeffs=dist_coefs)
    print(charucoCorners)
    print(charucoIds)
    if len(charucoIds) > 0:
        # 绘制棋盘格黑白块内角点
        cv.aruco.drawDetectedCornersCharuco(img_color, charucoCorners, charucoIds, [0, 0, 255])
        cv.imshow("out", img_color)
        cv.waitKey()

        rvec = None
        tvec = None
        retval, rvec, tvec = cv.aruco.estimatePoseCharucoBoard(charucoCorners, charucoIds, board, camera_matrix,
                                                               dist_coefs, rvec, tvec)
        if retval:
            cv.aruco.drawAxis(img_color, camera_matrix, dist_coefs, rvec, tvec, 0.01)

cv.imshow("out", img_color)
cv.waitKey()