1

我目前正在研究openCV的'aruco'模块,特别关注ArUco标记和AprilTags的poseEstimation。

查看亚像素精度,我遇到了一个奇怪的行为,下面的代码证明了这一点:如果我确实提供了“完美”校准(例如 cx/cy 等于图像中心并且失真设置为零)和“完美”具有已知边长的标记,如果旋转为 0/90/180 或 270 度,cv.detectMarkers 只会产生正确的值。子像素例程为其他方向产生(几乎)恒定值,但处于“偏移”水平。很明显,在 0/90/180/270 度的特定角度,角落中的像素会产生急剧的过渡,因此可以高精度检测。然而,我很难看出在所有其他情况下被低估的长度是从哪里来的。这是一个错误还是由某些三角函数引起的?--> 看下面脚本生成的图表:姿态误差是由角点检测误差引起的。因此,检测精度将取决于代码的方向。

我还检查了 ArUco 标记和不同的亚像素化方法。尽管两者之间的角度行为会改变,但“峰值”仍然存在。

我很确定,这不是由于与标记旋转相关的插值,因为我也可以在实际数据中观察到相同的行为(但请注意,峰的“高度”似乎在某种程度上取决于插值方法。您可以通过将 cv.warpAffine 中的标志更改为 cv.INTER_LINEAR 来进行测试。

我的问题是:

  1. 峰值是由于错误还是这是预期的行为?
  2. 如果是后者,你能帮我理解为什么吗?
  3. 有没有办法消除精度的这种方向依赖性(除了增加系统的分辨率,不需要亚像素)?

编辑:请注意,AprilTag 功能最近才添加到 openCV,因此您需要升级到某些标准存储库中尚不可用的最新版本。例如,您可以在 conda-forge 上获取最新版本。/编辑

# -*- coding: utf-8 -*-

import numpy as np
import cv2 as cv
import pylab as plt

""" generate an "ideal" calibration with zero distortion and perfect alignment 
    of the main optical axis: """
cam_matrix = np.array([[1.0e+04, 0.00000000e+00, 1.22400000e+03],
       [0.00000000e+00, 1.0e+04, 1.02400000e+03],
       [0.00000000e+00, 0.00000000e+00, 1.00000000e+00]])
dist_coeffs = np.array([[0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.],
       [0.]])

# define detection parameters
marker_length = 30.00 # some arbitrary value
marker_length_px = 700
marker_id = 3
dictionary = cv.aruco.getPredefinedDictionary(cv.aruco.DICT_APRILTAG_16H5)
para = cv.aruco.DetectorParameters_create()
para.cornerRefinementMethod = cv.aruco.CORNER_REFINE_APRILTAG
para.aprilTagDeglitch = 0           
para.aprilTagMinWhiteBlackDiff = 30
para.aprilTagMaxLineFitMse = 20
para.aprilTagCriticalRad = 0.1745329201221466 *6
para.aprilTagMinClusterPixels = 5  
para.maxErroneousBitsInBorderRate = 0.35
para.errorCorrectionRate = 1.0                    
para.minMarkerPerimeterRate = 0.05                  
para.maxMarkerPerimeterRate = 4                  
para.polygonalApproxAccuracyRate = 0.05
para.minCornerDistanceRate = 0.05

marker_length_list = []
tvec_z_list = []

# generate pictures (AprilTag ID: 3 centered in image will be rotated by fixed angular steps, e. g. 10 degrees) 
degrees_list = np.linspace(0,350,36, dtype=np.int).tolist()
marker = cv.aruco.drawMarker(dictionary, marker_id, marker_length_px)
img = np.zeros((2048, 2448), np.uint8)+255
img[674:1374, 874:1574] = marker
cv.imshow("Original", img)
cv.imwrite("original.png", img)
rows, cols = img.shape

for entry in degrees_list:
    # rotate original picture
    rot_mat = cv.getRotationMatrix2D((((rows-1)/2),(cols-1)/2), entry, 1)
    rot_img = cv.warpAffine(img, rot_mat, (cols, rows), flags=cv.INTER_CUBIC) # interpolation changes the "peak amplitude" e.g. try cv.INTER_LINEAR instead 
    # detect marker an get pose estimate
    corners, ids, rejected = cv.aruco.detectMarkers(rot_img,dictionary,parameters=para)
    my_index = ids.tolist().index([marker_id])
    fCorners = corners[my_index]
    fRvec,fTvec, _obj_points = cv.aruco.estimatePoseSingleMarkers(fCorners, marker_length, cam_matrix, dist_coeffs)
    # calculate the respective edge length for each side
    L1 = abs(np.sqrt(np.square(fCorners[0][0][0]-fCorners[0][1][0])+np.square(fCorners[0][0][1]-fCorners[0][1][1])))
    L2 = abs(np.sqrt(np.square(fCorners[0][0][0]-fCorners[0][3][0])+np.square(fCorners[0][0][1]-fCorners[0][3][1])))
    L3 = abs(np.sqrt(np.square(fCorners[0][2][0]-fCorners[0][1][0])+np.square(fCorners[0][2][1]-fCorners[0][1][1])))
    L4 = abs(np.sqrt(np.square(fCorners[0][2][0]-fCorners[0][3][0])+np.square(fCorners[0][2][1]-fCorners[0][3][1])))
    mean_length = (L1+L2+L3+L4)/4
    # append results
    marker_length_list. append(mean_length)
    tvec_z_list.append(fTvec[0][0][2])
        
plt.figure("TVEC Z")
plt.plot(degrees_list, tvec_z_list, "go--")
plt.xlabel("marker rotation angle (°)")
plt.ylabel("TVEC Z (units of length)")

plt.figure("Mean marker length (should be 700)")
plt.plot(degrees_list, marker_length_list, "bo--")
plt.xlabel("marker rotation angle (°)")
plt.ylabel("marker length (pixels)")
4

0 回答 0