繁体   English   中英

根据世界空间坐标和图像坐标估计点的位置

[英]Estimate position of point given world space coordinates and image coordinates

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

我最初的预测缺失点的尝试是尝试计算从世界到图像空间的未知过渡矩阵。 为了表示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投影。 不正确的标记点

一个简短的python代码片段,显示了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。因此,我的问题是,考虑到多个其他点的世界空间和屏幕空间坐标,是否有一种方法可以计算缺失点的屏幕坐标?

我能够在以下问题下找到解决方案: 如何在2D中绘制透视正确的网格

在这种情况下,您的图像世界和图像空间需要4个非共线的2D点。 即从世界坐标中删除那些以获得[0,0],[50,0],[75,0],[100,0],[0,100],[50,100],[75,100]和[100,100]。 非共线可能不是正确的术语,但这意味着它们需要创建一个四边形,并且最多允许2个点位于同一条线上。 这四个点的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])

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM