给定等距柱状全景图(长宽比 2:1,分辨率 4000x2000)、相机的方向、所需的图像形状和 2D FOV,我正在尝试将其转换为透视图像。根据方向向量,透视图像要么看起来正确,要么旋转不正确并扭曲。
看起来错误的方向是具有 x 和 y 分量的方向。我测试过的所有其他方向看起来都是正确的。您知道我的代码的哪一部分导致了这个问题吗?
def calculate_R(orientation, up=cp.array([0, -1, 0])):
orientation = orientation / cp.linalg.norm(orientation)
if cp.allclose(orientation, up):
return cp.array([[1, 0, 0], [0, 0, 1], [0, -1, 0]])
if cp.allclose(orientation, -up):
return cp.array([[1, 0, 0], [0, 0, -1], [0, 1, 0]])
x = cp.cross(up, orientation)
x = x / cp.linalg.norm(x)
y = cp.cross(orientation, x)
y = y / cp.linalg.norm(y)
R = cp.array([x, y, orientation])
return R
def rotate_xyz(R, x, y, z):
xyz = cp.stack((x.ravel(), y.ravel(), z.ravel()))
x, y, z = cp.matmul(R, xyz).reshape(3, *x.shape)
return x, y, z
def transform_back(pano, orientation, image_shape, fov=[90, 90]):
orientation = orientation / cp.linalg.norm(orientation)
fov_x = cp.radians(fov[0])
fov_y = cp.radians(fov[1]))
x_max = cp.tan(fov_x / 2)
y_max = cp.tan(fov_y / 2)
x = cp.linspace(-x_max, x_max, num=image_shape[1], dtype=cp.float32)
y = cp.linspace(-y_max, y_max, num=image_shape[0], dtype=cp.float32)
x, y = cp.meshgrid(x, y)
z = -cp.ones_like(x)
R = calculate_R(orientation)
x, y, z = Panorama.rotate_xyz(R, x, y, z)
xyz = cp.stack([x, y, z], axis=-1).reshape(-1, 3)
lon = cp.arctan2(xyz[:, 0], xyz[:, 2])
lat = cp.arcsin(xyz[:, 1] / cp.linalg.norm(xyz, axis=1))
u = ((lon + cp.pi) / (2 * cp.pi)) * pano.shape[1]
v = ((cp.pi / 2 - lat) / cp.pi) * pano.shape[0]
u = u.reshape(image_shape[0], image_shape[1]).astype(cp.float32)
v = v.reshape(image_shape[0], image_shape[1]).astype(cp.float32)
image = cp.empty((image_shape[0], image_shape[1], pano.shape[2]), dtype=pano.dtype)
for i in range(pano.shape[2]):
image[:, :, i] = ndimage.map_coordinates(pano[:, :, i], cp.stack([v, u]), order=1, mode='wrap')
return image
我仍然不是 100% 确定原因,但我通过使用旋转矩阵的逆并翻转方向的 x 分量解决了我的问题。
我添加了
orientation[0] *= -1
并更换
R = calculate_R(orientation)
与
R = cp.linalg.inv(calculate_R(orientation))