我正在尝试提取 2D 图像中两个已知点之间的 3D 距离(以 mm 为单位)。我正在使用方形 AR 标记来获取相对于场景中标记的相机坐标。这些点是这些标记的角。
一个例子如下所示:
代码是用 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.找到角的 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 距离,这表示 100mm。找到将此 3D 距离转换为 100 毫米所需的比例因子。(我实际上得到了平均比例因子):
for (int i = 0; i < 4; i++)
{
//Distance scale;
distanceScale1 += (halfCornerSize * 2) / Vector3.Distance(cornerPositions3d1[i], cornerPositions3d1[(i + 1) % 4]);
}
distanceScale1 /= 4;
6.最后,我找到相关角之间的 3D 距离,并乘以比例因子得到距离(以 mm 为单位):
for(int i = 0; i < 4; i++)
{
distance[i] = Vector3.Distance(cornerPositions3d1[i], cornerPositions3d2[i]) * scalingFactor;
}
获得的距离从来都不是真正正确的。我使用了砧板,因为它可以让我轻松计算距离应该是多少。上图计算出角 1(红色到紫色)的距离为 147 毫米(预期为 150 毫米)。下图显示 188 毫米(预期 200 毫米)。
同样令人担忧的是,在测量同一标记上共享一条边的标记角之间的距离时,获得的 3D 距离永远不会相同。我注意到的另一件事是棕色点似乎与彩色点不完全匹配。彩色点是用作 CoPlanar 位置输入的坐标。棕色圆点是通过 POSIT 计算的距标记中心的计算位置。
有谁知道这里可能出了什么问题?我正在拔头发试图弄清楚。代码应该很简单,我不认为我的代码有任何明显的错误。我数学不是很好,所以请指出我的基本数学也可能是错误的......