将 3d 对象与相机图像匹配以实现增强现实

Matching 3d object with camera image for augmented reality

我正在开发一个简单的 AR 引擎,但在将 3d 对象与相机图像匹配时遇到了问题。 为了更好的理解,我用图来说明。点 A 和 B 在 3d space 中。点 C 和 D 在纹理平面上给出。从相机到平面的距离是已知的。 我知道如何获取 Anear、Bnear、Afar、Bfar、Cnear、Dnear、Cfar 和 Dfar 的坐标。 问题是如何在 3d space 中找到点 A' 和 B',例如向量 d==d' 和点 Anear == Cnear 和 Bnear == Dnear(3d 点到屏幕的投影应该导致坐标相同) 谁能帮我算一下,或者至少告诉我在哪里可以找到答案?

PS。似乎我的问题描述不够清楚,换句话说:我在 3d space 中有一对点,在纹理平面上有一对点(来自网络摄像头的图像)。我需要将 3d space 中的点放在与相机的正确距离处 - 因此在透视变换之后,它们会覆盖纹理平面上的点。需要保留 3d 点的空间关系。在图中,视觉解决方案是点 A' 和 B'。虚线说明了透视变换(它们投射在与点 C 和 D 相同位置的近平面上)。

所以如果我理解正确

给定的世界点数-space是

  • A
  • B
  • C
  • D

也知道距离 d 和隐含的 Camera.position 原点和 Camera.transform.forward 方向。

搜索到的是

  • A'
  • B'

据我了解,您可以通过找到线(原点 = A,方向 = 相机向前)和线(原点 = camera.position,方向= Camera.position -> C).

同样也是第二个点B'通过找到直线(origin=B,direction=camera.forward)和直线(origin=camera.position,direction= Camera.position -> D).

Unity 提供了一些特殊的 Math3d 来帮助这里,例如:

//Calculate the intersection point of two lines. Returns true if lines intersect, otherwise false.
//Note that in 3d, two lines do not intersect most of the time. So if the two lines are not in the 
//same plane, use ClosestPointsOnTwoLines() instead.
public static bool LineLineIntersection(out Vector3 intersection, Vector3 linePoint1, Vector3 lineVec1, Vector3 linePoint2, Vector3 lineVec2)
{
    Vector3 lineVec3 = linePoint2 - linePoint1;
    Vector3 crossVec1and2 = Vector3.Cross(lineVec1, lineVec2);
    Vector3 crossVec3and2 = Vector3.Cross(lineVec3, lineVec2);

    float planarFactor = Vector3.Dot(lineVec3, crossVec1and2);

    //is coplanar, and not parrallel
    if(Mathf.Abs(planarFactor) < 0.0001f && crossVec1and2.sqrMagnitude > 0.0001f)
    {
        float s = Vector3.Dot(crossVec3and2, crossVec1and2) / crossVec1and2.sqrMagnitude;
        intersection = linePoint1 + (lineVec1 * s);
        return true;
    }
    else
    {
        intersection = Vector3.zero;
        return false;
    }
}

所以你可能会做类似的事情

public static bool TryFindPoints(Vector3 cameraOrigin, Vector3 cameraForward, Vector3 A, Vector3 B, Vector3 C, Vector3 D, out Vector3 AMapped, out Vector3 BMapped)
{
    AMapped = default;
    BMapped = default;

    if(LineLineIntersection(out AMapped, A, cameraForward, cameraOrigin, C - cameraOrigin))
    {
        if(LineLineIntersection(out BMapped, B, cameraForward, cameraOrigin, D - cameraOrigin))
        {
            return true;
        }
    }

    return false;
}

然后像

一样使用它
if(TryFindPoints(Camera.transform.position, Camera.transform.forward, A, B, C, D, out var aMapped, out var bMapped))
{
    // do something with aMapped and bMapped
}
else
{
    Debug.Log("It was mathematically impossible to find valid points");
}

注意:在智能手机上打字,但我希望思路清晰

给定 K 相机位置和 X=A' 和 Y=B'

var angleK = Vector3.Angle(C-K,D-K);
var angleB = Vector3.Angle(D-K, A-B);
var XK = Mathf.Sin(angleB)*(Vector3.Distance(A,B))/Mathf.Sin(angleK);
var X= K+(C-K).normalized*XK;
var Y= B + X - A;