如何从xyz世界坐标获取xy屏幕坐标?

问题描述 投票:1回答:1

我正在构建一个简单的应用程序,在屏幕上放置一个标记,位于现实世界某些地标的顶部,将标记覆盖在相机的视图上。我有观察设备和世界地标的纬度/经度/高度,我将它们转换为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个回答
2
投票

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

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);

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

您的数学使用隐含的摄像机视图,该视图与x,y,z轴对齐。要移动视图,您需要在进行透视分割步骤(由xRelative划分)之前计算相对于相机的zRelative等。一种简单的方法是将摄像机表示为3个矢量,即摄像机视图的X,Y,Z。然后通过将矢量[xRelative, yRelative, zRelative]的点积与X,Y和Z中的每一个相乘来计算相机上3D点的投影。这将为您提供一个新的[xCamera, yCamera, zCamera],当您移动相机时它会发生变化。您也可以使用矩阵执行此操作。

© www.soinside.com 2019 - 2024. All rights reserved.