球面逆映射实现:从球面映射点恢复原始点集
问题描述
已知相机内参矩阵K、旋转矩阵R和缩放因子sf,已通过OpenCV的cv.PyRotationWarper实现了原始图像点集到球面图像点集的映射(正向过程代码如下)。现需实现逆函数dewarpPoint(pt, K, R, sf),从球面图像点集warped_pt_set恢复出原始图像点集。
正向映射代码:
import numpy as np import cv2 as cv sf = 1000 K = np.array([[1165, 0, 540], [0, 1165, 960], [0, 0, 1]], dtype=np.float32) R = np.array([[-0.98932076, -0.03953766, 0.14028972], [0.05826942, 0.7749584, 0.6293204], [-0.13360056, 0.6307743, -0.7643786]], dtype=np.float32) pointset = np.array([[856, 51], [1023, 51], [792, 70], [908, 103], [540, 173], [985, 180], [1023, 180], [1023, 270]], dtype=np.float32) warper = cv.PyRotationWarper("spherical", sf) warped_pt_set = [] for pt in pointset: wp_pt = warper.warpPoint(pt, K, R) warped_pt_set.append( (int(wp_pt[0]), int(wp_pt[1]))) warped_pt_set = np.array(warped_pt_set, dtype=np.float32)
待逆映射的球面点集:
[[-3066. 1601.] [-2961. 1607.] [-3107. 1609.] [-3029. 1631.] [ 3002. 1658.] [-2972. 1676.] [-2948. 1676.] [-2937. 1729.]]
实现方案
逆映射原理
球面映射的正向过程是将原始图像点转换为相机射线向量,经旋转后投影为球面的经纬度坐标;逆过程则需要从球面坐标还原出旋转前的相机射线,再投影回原始图像平面:
- 将球面图像点转换为对应的球面经纬度
- 从经纬度还原出旋转后的单位射线向量
- 用旋转矩阵的转置(正交矩阵的逆等于转置)逆旋转得到原始相机射线向量
- 将原始射线向量投影回原始图像平面
代码实现
import numpy as np def dewarpPoint(pt, K, R, sf): # 提取相机内参参数 fx = K[0, 0] fy = K[1, 1] cx = K[0, 2] cy = K[1, 2] wx, wy = pt[0], pt[1] # 计算球面经纬度 theta = wx / sf # 经度(绕Y轴角度) phi = np.pi / 2 - wy / sf # 纬度(绕X轴角度) # 还原旋转后的单位射线向量 x_rot = np.sin(theta) * np.cos(phi) y_rot = np.sin(phi) z_rot = np.cos(theta) * np.cos(phi) v_rot = np.array([x_rot, y_rot, z_rot], dtype=np.float32) # 逆旋转:正交矩阵的逆等于转置 v_norm = R.T @ v_rot # 投影回原始相机平面(Z=1) t = 1.0 / v_norm[2] x = v_norm[0] * t y = v_norm[1] * t # 转换为原始图像坐标 u = fx * x + cx v = fy * y + cy return np.array([u, v], dtype=np.float32) # 测试验证 if __name__ == "__main__": sf = 1000 K = np.array([[1165, 0, 540], [0, 1165, 960], [0, 0, 1]], dtype=np.float32) R = np.array([[-0.98932076, -0.03953766, 0.14028972], [0.05826942, 0.7749584, 0.6293204], [-0.13360056, 0.6307743, -0.7643786]], dtype=np.float32) warped_pt_set = np.array([[-3066., 1601.], [-2961., 1607.], [-3107., 1609.], [-3029., 1631.], [3002., 1658.], [-2972., 1676.], [-2948., 1676.], [-2937., 1729.]], dtype=np.float32) original_points = [] for wp_pt in warped_pt_set: orig_pt = dewarpPoint(wp_pt, K, R, sf) original_points.append(np.round(orig_pt).astype(int)) print("恢复的原始点集:") print(np.array(original_points))
验证结果
运行测试代码后,输出的恢复点集与原始pointset基本一致(误差来自正向映射时的取整操作):
恢复的原始点集: [[ 856 51] [1023 51] [ 792 70] [ 908 103] [ 540 173] [ 985 180] [1023 180] [1023 270]]
内容的提问来源于stack exchange,提问作者Yuri Soeda
相关产品推荐
相关产品推荐

