【问题标题】:Estimate position of point given world space coordinates and image coordinates给定世界空间坐标和图像坐标估计点的位置
【发布时间】:2023-03-13 17:03:01
【问题描述】:

我正在尝试使用 8 个 aruco 标记、opencv 和 python 来检测棋盘。标记检测工作正常,但是一旦玩家移动,通常至少有一个标记会被他们的手臂覆盖。由于仍然可以检测到大多数标记,因此应该可以在给定其他标记位置的情况下估计该点。为了说明我的设置,我链接了一张图片。 Correct Marker Points

我第一次尝试预测缺失点是尝试计算从世界到图像空间的未知转换矩阵。为了表示 8 个标记角位置,世界空间坐标 [1,0,0], [1,50,0], [1,75,0], [1,100,0], [1,0,100], [1,使用了 0,50]、[1,75,100] 和 [1,100,100]。因此,这些总是已知的并由矩阵 W 表示。标记点的屏幕空间坐标由 opencv 计算并由矩阵 S 表示。为了论证,假设没有检测到一个标记并且需要估计该点。然后为给定的 7 个点计算从 W 到 S 的变换矩阵(即为 X 求解 W * X = S),并为估计缺失点,将世界空间坐标乘以 X。问题是 X 不包含透视变换,因此错误地投影估计点。为了说明这一点,连接了第二张图片,其中所有点都被正确检测到,但随后被投影矩阵 X 投影。 Incorrect Marker Points

python 代码的快速 sn-p 显示如何计算 X 和投影点:

ids = [81,277,939,275,683,677,335,981]

corner_world_coord = {
    683: [1,0,0],
    275: [1,50,0],
    939: [1,75,0],
    81: [1,100,0],
    335: [1,0,100],
    677: [1,50,100],
    277: [1,75,100],
    981: [1,100,100]
}

W = [corner_world_coord[i] for i in ids]
S = [aruco_corners[i] for i in ids]

X, res, _, _ = np.linalg.lstsq(W,S)

estimate = np.zeros(len(ids))

for idx, corner in enumerate(W):
    estimate[idx] = np.dot(corner,X)

X 的最小二乘误差计算的残差始终等于 0。因此,我的问题是,在给定多个其他点的世界空间和屏幕空间坐标的情况下,有没有办法计算缺失点的屏幕坐标?

【问题讨论】:

  • Aruco 还返回旋转rvec 和平移tvec 向量,允许将对象帧中表示的3D 点转换为相机帧。每个标记点都在一个全局对象框架中表示。如果未检测到标记,您可以使用其他标记姿势之一转换标记坐标,然后使用内部参数将其投影到图像平面。
  • 由于您有多个标记,您将有多个rvectvec。也许您需要在参考框架/全局对象框架中转换所有内容。有关camera framehomogeneous transformation 的更多信息,请参阅同构变换和文档。

标签: python numpy opencv linear-algebra


【解决方案1】:

我能够在以下问题下找到解决方案: How to draw a Perspective-Correct Grid in 2D

在这种情况下,您的图像世界和图像空间需要 4 个非共线 2D 点。 IE。从世界坐标中删除那些以获得[0,0], [50,0]、[75,0]、[100,0]、[0,100]、[50,100]、[75,100] 和 [100,100]。非共线可能不是正确的术语,但这意味着它们需要创建一个四边形,并且最多允许 2 个点位于同一条线上。这 4 个点的 x 坐标我们称为 x1...x4 和 y 坐标 y1...y4。对应的图像空间点的坐标我们称为x1p...x4p和y1p...y4p(p代表素数)。然后在下面的代码中给出了透视正确转换矩阵的计算:

def compute_proj_matrix(self, world_points, image_points):
    # compute A * C = B 
    # A is the following 8x8 Matrix:
    # x1   y1     1     0   0    0   -x1*x1'  -y1*x1'
    # 0    0     0    x1   y1   1   -x1*y1'  -y1*y1'
    # x2   y2     1     0   0    0   -x2*x2'  -y2*x2'
    # 0    0     0    x2   y2   1   -x2*y2'  -y2*y2'
    # x3   y3     1     0   0    0   -x3*x3'  -y3*x3'
    # 0    0     0    x3   y3   1   -x3*y3'  -y3*y3'
    # x4   y4     1     0   0    0   -x4*x4'  -y4*x4'
    # 0    0     0    x4   y4   1   -x4*y4'  -y4*y4'
    # B = [x1p,y1p,x2p,y2p,x3p,y3p,x4p,y4p]
    x1,x2,x3,x4 = world_points[:,0]
    y1,y2,y3,y4 = world_points[:,1]
    x1p,x2p,x3p,x4p = image_points[:,0]
    y1p,y2p,y3p,y4p = image_points[:,1]
    A = np.array([
        [x1,y1, 1, 0, 0, 0, -x1*x1p, -y1*x1p],
        [ 0, 0, 0,x1,y1, 1, -x1*y1p, -y1*y1p],
        [x2,y2, 1, 0, 0, 0, -x2*x2p, -y2*x2p],
        [ 0, 0, 0,x2,y2, 1, -x2*y2p, -y2*y2p],
        [x3,y3, 1, 0, 0, 0, -x3*x3p, -y3*x3p],
        [ 0, 0, 0,x3,y3, 1, -x3*y3p, -y3*y3p],
        [x4,y4, 1, 0, 0, 0, -x4*x4p, -y4*x4p],
        [ 0, 0, 0,x4,y4, 1, -x4*y4p, -y4*y4p]])
    B = np.array([x1p,y1p,x2p,y2p,x3p,y3p,x4p,y4p])
    return np.linalg.solve(A,B)

然后通过以下方式完成新点的映射(在上述情况下,缺失):

def map_point(self, proj_matrix, point):
    x,y = point
    factor = 1.0/(proj_matrix[6] * x + proj_matrix[7] * y + 1.0)
    projected_x = factor * (proj_matrix[0] * x + proj_matrix[1] * y + proj_matrix[2])
    projected_y = factor * (proj_matrix[3] * x + proj_matrix[4] * y + proj_matrix[5])
    return np.array([projected_x,projected_y])

可以在上面链接的问题中最好地检查为什么以及如何工作,坦率地说,我不了解自己,很高兴找到了解决方案。

【讨论】:

    猜你喜欢
    • 2015-08-10
    • 1970-01-01
    • 2018-07-03
    • 1970-01-01
    • 1970-01-01
    • 2019-02-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多