尝试从二维图像准确测量三维距离

4

我正在尝试从2D图像中提取两个已知点之间的3D距离(以毫米为单位)。我使用正方形AR标记来获取相机坐标与场景中标记的相对位置。这些点是这些标记的角落。

下面是一个示例:

enter image description here

这段代码是用 C# 写的,我使用 XNA。 我使用 AForge.net 来进行 CoPlanar POSIT。

我的步骤如下,以计算距离:

1. 在屏幕上标记角落。角落以 2D 矢量形式表示,图像中心为 (0,0)。向上在 Y 方向上为正,向右在 X 方向上为正。

2. 使用 AForge.net Co-Planar POSIT 算法来获取每个标记的姿态:

    float focalLength = 640; //Needed for POSIT
    float halfCornerSize = 50; //Represents 1/2 an edge i.e. 50mm
    AVector[] modelPoints = new AVector3[]
    {
         new AVector3( -halfCornerSize, 0,  halfCornerSize ),
         new AVector3(  halfCornerSize, 0,  halfCornerSize ),
         new AVector3(  halfCornerSize, 0, -halfCornerSize ),
         new AVector3( -halfCornerSize, 0, -halfCornerSize ),
    };
    CoplanarPosit coPosit = new CoplanarPosit(modelPoints, focalLength);
    coPosit.EstimatePose(cornersToEstimate, out marker1Rot, out marker1Trans);

3. 将转换为XNA旋转/平移矩阵(AForge使用OpenGL矩阵形式):

    float yaw, pitch, roll;
    marker1Rot.ExtractYawPitchRoll(out yaw, out pitch, out roll);

    Matrix xnaRot = Matrix.CreateFromYawPitchRoll(-yaw, -pitch, roll);
    Matrix xnaTranslation = Matrix.CreateTranslation(marker1Trans.X, marker1Trans.Y, -marker1Trans.Z);
    Matrix transform = xnaRot * xnaTranslation;

4. 找到角落的三维坐标:

    //Model corner points
    cornerModel = new Vector3[]
    {
        new Vector3(halfCornerSize,0,-halfCornerSize),
        new Vector3(-halfCornerSize,0,-halfCornerSize),

        new Vector3(halfCornerSize,0,halfCornerSize),
        new Vector3(-halfCornerSize,0,halfCornerSize)
    };

    Matrix markerTransform =  Matrix.CreateTranslation(cornerModel[i].X, cornerModel[i].Y, cornerModel[i].Z);
    cornerPositions3d1[i] = (markerTransform * transform).Translation;

    //DEBUG: project corner onto screen - represented by brown dots
    Vector3 t3 = viewPort.Project(markerTransform.Translation, projectionMatrix, viewMatrix, transform);
    cornersProjected1[i].X = t3.X; cornersProjected1[i].Y = t3.Y;

5. 查看标记上两个角之间的三维距离,表示100mm。找到将此三维距离转换为100mm所需的比例因子。(我实际上获取平均比例因子):

    for (int i = 0; i < 4; i++)
    {
        //Distance scale;
        distanceScale1 += (halfCornerSize * 2) / Vector3.Distance(cornerPositions3d1[i], cornerPositions3d1[(i + 1) % 4]);
    }
    distanceScale1 /= 4;

6. 最后,我找到相关角落之间的3D距离,并乘以缩放因子以获得毫米单位的距离:

    for(int i = 0; i < 4; i++)
    {
       distance[i] = Vector3.Distance(cornerPositions3d1[i], cornerPositions3d2[i]) * scalingFactor;
    }

获取的距离从未真正正确。我使用切菜板,因为它让我轻松计算距离应该是多少。上面的图像计算出第1个角(红色到紫色)的距离为147毫米(预期为150毫米)。下面的图像显示188毫米(预期为200毫米)。

enter image description here

令人担忧的是,当测量共享同一标记边缘的标记角之间的距离时,所得到的三维距离永远不相同。我还注意到的一件事是,棕色点似乎从未与彩色点完全匹配。彩色点是作为CoPlanar posit输入使用的坐标。棕色点是通过POSIT计算出的从标记中心计算出的位置。

有人知道这里可能出了什么问题吗?我正在拼命地想办法解决它。代码应该很简单,我不认为我在代码方面犯了任何明显的错误。我不擅长数学,请指出我的基本数学可能出错的地方...


2D转3D,最显而易见的是立体视觉。 - ldog
这应该适用于单个网络摄像头,因此我正在使用已知目标的姿势估计。 - Jkh2
1
我认为你从所有计算中获取了很多噪声和舍入误差。XNA数学方法是为了速度而设计的,而不是为了精确性。考虑使用double和/或使用自定义数学函数。 - Julien Lebot
我考虑了舍入误差,我尝试使用双精度手动计算,但结果相似。 - Jkh2
你有检查过相机的镜头畸变吗?如果你在垂直于图像轴的平面上移动相机而不旋转它,那么估计值会发生什么变化,使得物体在图像中改变位置但其他方面保持不变? - jilles de wit
我现在正在尝试添加相机去畸变功能。我使用了GML工具箱http://graphics.cs.msu.ru/en/science/research/calibration/cpp来获取畸变参数,但我不确定如何使用它们。我看了这个答案:https://dev59.com/ZnE95IYBdhLWcg3wDpmg#7076541,我想知道那是否是扭曲了一个校正后的图像。此外,我认为我只有从GML工具箱中得到的K值,我能将p(切向畸变)设置为0吗? - Jkh2
2个回答

1

你在问题中使用了太多的黑盒子。第二步的焦距是多少?为什么要在第三步中经过ypr?如何进行校准?我建议您从头开始重新开始,不要使用您不理解的库。

步骤1:创建相机模型。了解错误,构建投影。如果需要,应用2D滤镜以消除镜头畸变。这可能很难。

步骤2:在消除镜头畸变后找到2D标记。确保您知道误差并获得中心。也许在多个帧上。

步骤3:取消投影到3D。在完成步骤1和2之后,这应该很容易。

步骤4:???

步骤5:利润!(在3D中测量距离并了解您的误差)


0

我认为你需要拥有3D照片(一组距离的两张照片),这样你就可以通过图像差异得到视差距离。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接