在增强现实应用中的Android透视投影

4

我正在开发一款增强现实应用程序,但是我遇到了一些问题,无法将对象显示在屏幕上。对于我而言,不能将GPS点转换为Android设备上相应的屏幕点非常令人沮丧。我已经阅读了许多文章和stackoverflow上的其他帖子(我已经问过类似的问题),但我仍然需要你的帮助。

我进行了在维基百科中解释的透视投影。

要如何处理透视投影的结果才能获得相应的屏幕点呢?

1个回答

16

维基百科文章在我之前读它时也让我感到困惑。以下是我的另一种解释:


情景

我们简化一下情况,有:

  • 我们的预计点D(x,y,z)- 你称之为相对位置X|Y|Z
  • 大小为w * h的图像平面
  • 视野的一半α

...我们要:

  • 图像平面上B的坐标(称为XY

X屏幕坐标的模式:

在这种配置中,E是我们的“眼睛”的位置,我选择它作为起点以简化问题。

可以通过估算焦距f来得到:

  • tan(α) = (w/2) / f (1)

几何学知识

从图片中可以看出三角形ECDEBM相似的,因此使用分线定理,我们得到:

  • MB / CD = EM / EC <=> X / x = f / z (2)

现在,结合两个方程(1)(2),我们有:

  • X = (x / z) * ((w / 2) / tan(α))

如果我们回到维基百科文章使用的符号,我们的方程等价于:

  • b_x = (d_x / d_z) * r_z

你可以注意到,我们缺少了乘以s_x / r_x。这是因为在我们的情况下,"显示尺寸"和"记录表面"是相同的,所以s_x / r_x = 1

注:对于Y,同样的推理。


实际应用

一些注意事项:

  • 通常使用α = 45度,这意味着tan(α)= 1,因此该术语不会出现在许多实现中。
  • 如果要保留显示元素的比率,请对XY都保持f不变,即不要计算:

    • X = (x / z) * ((w / 2) / tan(α))Y = (y / z) * ((h / 2) / tan(α))

    而是执行:

    • X = (x / z) * ((min(w,h) / 2) / tan(α))Y = (y / z) * ((min(w,h) / 2) / tan(α))

    注:当我说"显示尺寸"和"记录表面"是相同的"时,那并不完全正确,这里的min操作用于补偿此近似值,适应最小的尺寸。

    将正方形表面r转换为可能的矩形表面s

    注2:Appunta使用screenRatio=(getWidth()+getHeight())/2而不是min(w,h)/2,如您所注意到的。这两种解决方案都保留了元素比例。焦点和视角将根据屏幕自身的比例略有不同。实际上,您可以使用任何想要定义f的函数。

    正如您在上图中看到的那样,屏幕坐标在此处定义为X的[-w/2 ; w/2]和Y的[-h/2 ; h/2],但您可能希望改为 [0 ; w][0 ; h]。解决方法是X += w/2Y += h/2


    结论

    希望这能回答您的问题。如果需要修改,我会随时待命。

    再见!

    <自我推广警报>我实际上在一段时间前写了一篇关于3D投影和渲染的文章。实现是用Javascript完成的,但很容易翻译。


1
在我提出的方法中, 是水平和垂直视角(因为我使用了一个较小的有效正方形图像平面,尺寸为 min(h,w) x *min(h,w)*)。但是如果您愿意,可以调整它以使用您的 2 个值和整个有效屏幕 w x h - benjaminplanche
1
是的,只需检查您的比率即可。根据您的角度和尺寸,结果可能会受到一些影响(但我猜您的角度必须已经计算过了,以防止这种情况,所以应该没问题) :) - benjaminplanche
1
嗨, 很抱歉我不太熟悉经纬度和高度坐标。但你可能应该先检查错误来自哪里 - 是你的坐标系统转换还是投影。例如,尝试使用简单的输入(例如形成一个立方体的8个点)来使用你的投影方法,这样你就可以检查输出并知道期望的结果(从所选视角看到一个立方体)。 - benjaminplanche
2
在投影期间,当您执行“b_x =(d_x / d_z)* r_z”时,d_x和d_z以您选择的现实世界单位为单位,而b_x和r_z以屏幕单位(可能是像素)为单位。“(d_x / d_z)”因此是无单位的,因为您计算相对比例,并通过乘以r_z将其应用于屏幕尺寸。 - benjaminplanche
1
抱歉打扰了,但是你能解释一下“通常使用α = 90度,这意味着tan(α)= 1”吗?tan(90度)不应该是“未定义”的吗? - kikito
显示剩余9条评论

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