简体   繁体   English

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

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

I am trying to detect a chessboard using 8 aruco markers, opencv and python. 我正在尝试使用8个aruco标记,opencv和python检测棋盘。 The marker detection works fine, but as soon as a player makes a move, at least one of the markers will usually be covered by their arm. 标记检测效果很好,但是一旦玩家移动,通常至少有一个标记会被他们的手臂覆盖。 Since most of the markers can still be detected, an estimation of the point given the position of the other markers should be possible. 由于仍然可以检测到大多数标记,因此应该可以在给出其他标记位置的情况下估算该点。 To illustrate my setup I have linked a picture. 为了说明我的设置,我链接了一张图片。 Correct Marker Points 正确的标记点

My first attempts to predict a missing point were to try to compute the unknown transition matrix from world to image space. 我最初的预测缺失点的尝试是尝试计算从世界到图像空间的未知过渡矩阵。 To represent the 8 marker corner positions the world space coordinates [1,0,0], [1,50,0], [1,75,0], [1,100,0], [1,0,100], [1,0,50], [1,75,100] and [1,100,100] were used. 为了表示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]。 These are therefore always known and represented by matrix W. The screen space coordinates of the marker points are computed by opencv and represented by matrix S. For the sake of argument, lets pretend one marker was not detected and the point needs to be estimated. 因此,它们始终是已知的,并由矩阵W表示。标记点的屏幕空间坐标由opencv计算,并由矩阵S表示。为了进行论证,让我们假装未检测到一个标记,并且需要估计该点。 The transformation matrix from W to S (ie solving W * X = S for X) was then computed for the given 7 points and to estimate the missing point the world space coordinates were multiplied with X. The problem is that X does not incorporate the perspective transformation and therefore incorrectly projects an estimated point. 然后,针对给定的7个点,计算了从W到S的转换矩阵(即,对X求解W * X = S),并估计了世界空间坐标与X的乘积。该问题是X不包含透视变换,因此错误地投影了一个估计点。 To illustrate this a second picture is linked where all points were correctly detected, but are then projected by the projection matrix X. Incorrect Marker Points 为了说明这一点,链接了第二张图片,其中所有点均已正确检测,但随后由投影矩阵X投影。 不正确的标记点

A quick snippet of python code which shows how X is computed and points projected: 一个简短的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)

The residual of the least square error computation of X is always equal to 0. My question therefore is, is there a way to compute the screen coordinates of a missing point, given the world space and screen space coordinates of multiple other points? X的最小二乘误差计算的残差始终等于0。因此,我的问题是,考虑到多个其他点的世界空间和屏幕空间坐标,是否有一种方法可以计算缺失点的屏幕坐标?

I was able to find a solution under the following question: How to draw a Perspective-Correct Grid in 2D 我能够在以下问题下找到解决方案: 如何在2D中绘制透视正确的网格

In this case, 4 non-collinear 2D points are required from your image world and image space. 在这种情况下,您的图像世界和图像空间需要4个非共线的2D点。 Ie remove the ones from the world coordinates to obtain [0,0], [50,0], [75,0], [100,0], [0,100], [50,100], [75,100] and [100,100]. 即从世界坐标中删除那些以获得[0,0],[50,0],[75,0],[100,0],[0,100],[50,100],[75,100]和[100,100]。 Non-collinear is probably not the correct term, but what is meant by that is that they need to create a quadrilateral and at most 2 points are allowed to lie on the same line. 非共线可能不是正确的术语,但这意味着它们需要创建一个四边形,并且最多允许2个点位于同一条线上。 The x coordinates of these 4 points we call x1...x4 and the y coordinates y1...y4. 这四个点的x坐标我们称为x1 ... x4,y坐标y1 ... y4。 The coordinates of the corresponding image space points we call x1p...x4p and y1p...y4p (p stands for prime). 对应图像空间点的坐标我们称为x1p ... x4p和y1p ... y4p(p表示质数)。 The computation of the perspective correct transition matrix is then given in code below: 下面的代码给出了透视正确过渡矩阵的计算:

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)

Mapping of new (in the above case, missing) point is then done by: 然后通过以下方法完成新点(在上述情况下,缺少点)的映射:

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])

Why and how this works can best be checked in the question linked above, as frankly I do not understand myself and am just happy to have found a solution. 可以在上面链接的问题中最好地检查为什么以及如何进行此工作,因为坦率地说,我不了解自己,很高兴找到解决方案。

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

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