c# - 尝试从 2D 图像准确测量 3D 距离

标签 c# math graphics xna computer-vision

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

示例如下:

enter image description here

代码是用 C# 编写的,我使用的是 XNA。我正在使用 AForge.net 进行 CoPlanar POSIT 我为计算距离而采取的步骤:

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

2.使用AForge.net Co-Planar POSIT算法得到每个marker的位姿:

    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. 找到角的 3D 坐标:

    //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. 查看标记上两个角之间的 3D 距离,这表示 100 毫米。找到将此 3D 距离转换为 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 毫米)。下图显示 188mm(预期 200mm)。

enter image description here

同样令人担忧的是,当测量同一标记上共享边缘的标记角之间的距离时,获得的 3D 距离永远不会相同。我注意到的另一件事是棕色圆点似乎永远不会与彩色圆点完全匹配。彩色点是用作 CoPlanar 位置输入的坐标。棕色点是通过 POSIT 计算的距离标记中心的计算位置。

有没有人知道这里可能出了什么问题?我正在拔头发试图弄明白。代码应该很简单,我认为我没有对代码犯任何明显的错误。我的数学不是很好,所以请指出我的基础数学也可能有错误的地方......

最佳答案

您在问题中使用了很多黑框。第二步的焦距是多少?为什么要在第 3 步中通过 ypr?你如何校准?我建议从头开始,不要使用您不了解的库。

第 1 步:创建相机模型。了解错误,构建投影。如果需要,应用 2d 滤镜来消除镜头失真。这可能很难。

第 2 步:在消除镜头畸变后,在 2d 中找到标记。确保你知道错误并且你得到了中心。可能超过多个帧。

第 3 步:取消投影到 3d。在 1 和 2 之后这应该很容易。

第 4 步:???

第 5 步:获利! (在 3d 中测量距离并知道你的错误)

关于c# - 尝试从 2D 图像准确测量 3D 距离,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/10790904/

相关文章:

c# - 在 C# 中从 PDF 中读取基于标签名称的特定值

c# - ASP.NET Core 2.0 站点 - FileIOException System.Runtime

c# - 如果已添加/更新/删除特定数据库表中的记录,我如何提醒我的程序?

c# - 访问在 MainWindow() 构造函数期间实例化的类

java - 为什么我的标签没有沿 y 轴居中? (斯坦福SEE CS106A)

java - 添加 While 循环

math - 在什么情况下需要多项式的泰勒级数?

php - 如何确定数据是在 PHP 中增加还是减少

c++ - 我如何制作屏幕缓冲区 C++

c++ - 如何将纹理应用于 OpenGL 中的子网格?