估算给定世界空间坐标和图像坐标的点的位置

时间:2018-02-26 16:26:35

标签: python numpy opencv linear-algebra

我正在尝试使用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的变换矩阵(即,求解W的X * S = X)并且估计世界空间坐标乘以X的缺失点。问题是X不包含透视变换,因此错误地预测了估计点。为了说明这一点,第二张图片被链接,其中所有点被正确检测,然后由投影矩阵X投影。  Incorrect Marker Points

快速的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.我的问题是,有没有办法计算缺失点的屏幕坐标,给定多个其他点的世界空间和屏幕空间坐标?

1 个答案:

答案 0 :(得分:0)

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

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

为什么以及如何最有效地检查上面提到的问题,坦率地说我不了解自己,我很高兴能找到解决方案。