【问题标题】:How to get xy screen coordinates from xyz world coordinates?如何从 xyz 世界坐标中获取 xy 屏幕坐标?
【发布时间】:2019-08-22 00:44:53
【问题描述】:

我正在构建一个简单的应用程序,它会在您的屏幕上放置一个标记,该标记位于现实世界中某些地标的顶部,将标记覆盖在相机的视图上。 我有查看设备和世界地标的纬度/经度/高度,并将它们转换为 ECEF 坐标。但是我在 3D 投影数学上遇到了麻烦。这个点似乎总是放在屏幕的中间……也许我的缩放比例在某个地方是错误的,所以看起来它几乎没有从中心移动?

查看设备 GPS 坐标:

GPS:
  lat: 45.492132
  lon: -122.721062
  alt: 124 (meters)

ECEF:
  x: -2421034.078421273
  y: -3768100.560012433
  z: 4525944.676268726

地标 GPS 坐标:

GPS:
  lat: 45.499278
  lon: -122.708417
  alt: 479 (meters)

ECEF:
  x: -2420030.781624382
  y: -3768367.5284123267
  z: 4526754.604333807

我尝试按照 here 的数学运算来构建一个函数,从 3D 点坐标中获取屏幕坐标。

当我将这些 ECEF 点放入我的投影函数时,视口为 1440x335,我得到:x: 721, y: 167

这是我的功能:

function projectionCoordinates(origin, destination) {
  const relativeX = destination.x - origin.x;
  const relativeY = destination.y - origin.y;
  const relativeZ = destination.z - origin.z;

  const xPerspective = relativeX / relativeZ;
  const yPerspective = relativeY / relativeZ;

  const xNormalized = (xPerspective + viewPort.width / 2) / viewPort.width;
  const yNormalized = (yPerspective + viewPort.height / 2) / viewPort.height;

  const xRaster = Math.floor(xNormalized * viewPort.width);
  const yRaster = Math.floor((1 - yNormalized) * viewPort.height);

  return { x: xRaster, y: yRaster };
}

我认为这个点应该放在屏幕上更高的位置。我链接的那篇文章提到了我无法遵循的 3x4 矩阵(不确定如何从 3D 点构建 3x4 矩阵)。也许这些很重要,尤其是因为我最终将不得不考虑设备的倾斜度(用手机向上或向下看)。

如果需要,这是我将纬度/经度/高度坐标转换为 ECEF 的函数(从另一个 SO 答案复制/粘贴):

function llaToCartesion({ lat, lon, alt }) {
  const cosLat = Math.cos((lat * Math.PI) / 180.0);
  const sinLat = Math.sin((lat * Math.PI) / 180.0);
  const cosLon = Math.cos((lon * Math.PI) / 180.0);
  const sinLon = Math.sin((lon * Math.PI) / 180.0);
  const rad = 6378137.0;
  const f = 1.0 / 298.257224;
  const C =
    1.0 / Math.sqrt(cosLat * cosLat + (1 - f) * (1 - f) * sinLat * sinLat);
  const S = (1.0 - f) * (1.0 - f) * C;
  const h = alt;

  const x = (rad * C + h) * cosLat * cosLon;
  const y = (rad * C + h) * cosLat * sinLon;
  const z = (rad * S + h) * sinLat;

  return { x, y, z };
}

【问题讨论】:

    标签: javascript 3d computer-vision projection


    【解决方案1】:

    您的规范化和光栅化步骤正在取消您需要的视口缩放。乘以这个:

    const xNormalized = (xPerspective + viewPort.width / 2) / viewPort.width;
    

    给你:

    const xNormalized = xPerspective / viewPort.width + 0.5;
    

    并应用这一行:

    const xRaster = Math.floor(xNormalized * viewPort.width);
    

    给你:

    const xRaster = Math.floor(xPerspective + viewPort.width * 0.5);
    

    您对xPerspective 的计算是正确的(但请参阅下面的评论)-但是查看您的数字,该值将在 1 左右。这就是该点靠近屏幕中心的原因。

    正确的做法是:

    const xRaster = Math.floor(xPerspective * viewPort.width /2 + viewPort.width /2);
    

    您可以简化它。这个想法是xPerspectivexRelative 对着眼睛的角度的tan。将tan 乘以屏幕宽度的一半,即可得到与屏幕中心的 x 距离。然后添加屏幕中心的 x 位置以获得屏幕坐标。

    您的数学运算使用与 x、y、z 轴对齐的隐式相机视图。要移动视图,您需要在执行透视除法步骤(除以zRelative)之前相对于相机计算xRelative 等。一个简单的方法是将您的相机表示为 3 个向量,它们是相机视图的 X、Y、Z。然后,您通过将矢量[xRelative, yRelative, zRelative] 与 X、Y 和 Z 中的每一个进行点积来计算 3D 点在相机上的投影。这会为您提供一个新的[xCamera, yCamera, zCamera],它会随着您移动相机而改变。您也可以使用矩阵来执行此操作。

    【讨论】:

    • 谢谢,这非常有帮助!我应用了这个数学,它给了我一个更合理的 x 坐标。 yRaster 值是否相同(使用视口高度而不是宽度)?这样做,该点几乎垂直居中,但我希望它会在屏幕顶部更高。即使有非常接近的原点坐标lat: 45.498953 lon: -122.708429 alt: 124(相同的目标坐标)。高度差为 355 米,我希望最终的 y 坐标高于视口的上边界。知道为什么会这样吗?
    • 是的,yRaster 也是如此,但您可能希望从 y 中心减去 y 距离,因为 y 屏幕坐标通常从上到下增加。关于你没有看到的高度差,yPerspective 的值对于更靠近的点是多少?
    • 啊。是的。减去y距离的好点。我应该抓住那个。之后屏幕坐标似乎好多了。将不得不做更多的测试以确保!再次感谢!如果你仍然对这里的值感兴趣:relativeX: 814.5247336803004relativeY: 182.14889590069652relativeZ: 1081.0716344099492xPerspective 0.7534419623588307yPerspective 0.16848920099556003xRaster: 1262yRaster: -193`
    猜你喜欢
    • 2021-10-22
    • 2016-02-29
    • 1970-01-01
    • 1970-01-01
    • 2018-01-29
    • 2017-12-11
    • 2017-05-26
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多