将 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;
我正在开发一个简单的 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;