如何通过欧氏变换对齐超平面并转换数据点坐标系
3D超平面对齐与数据坐标转换实现
核心思路
欧氏变换仅包含旋转和平移操作,能保持点间距离与角度不变,恰好满足将第二个平面对齐到第一个平面坐标系的需求。实现分为两步:
- 旋转:让两个平面的法向量方向完全一致
- 平移:让两个平面的位置重合
具体步骤与代码实现
1. 提取并归一化平面法向量
平面方程 ax+by+cz+d=0 的法向量为 (a,b,c),先对两个法向量做归一化处理:
import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot3d import Axes3D # 给定的两个平面参数 plane1 = np.array([-5.297742252442251, 21.751836101364013, -2.470896764133499, -0.5601826186620921]) plane2 = np.array([45.42557999642176, -16.9433283673388, 2.5117971500097287, -8.528560240570203]) # 提取法向量并归一化 n1 = plane1[:3] / np.linalg.norm(plane1[:3]) n2 = plane2[:3] / np.linalg.norm(plane2[:3])
2. 计算旋转矩阵
通过Rodrigues旋转公式计算将法向量n2旋转到n1的旋转矩阵:
def rodrigues_rotation(n_from, n_to): # 计算旋转轴(叉乘) axis = np.cross(n_from, n_to) axis_norm = np.linalg.norm(axis) if axis_norm < 1e-8: # 法向量方向相同或相反 if np.dot(n_from, n_to) > 0: return np.eye(3) else: # 构造180度旋转矩阵 if abs(n_from[0]) > abs(n_from[1]): ortho = np.array([-n_from[2], 0, n_from[0]]) else: ortho = np.array([0, -n_from[2], n_from[1]]) ortho = ortho / np.linalg.norm(ortho) return np.eye(3) - 2 * np.outer(ortho, ortho) axis = axis / axis_norm # 计算旋转角度(点乘) angle = np.arccos(np.clip(np.dot(n_from, n_to), -1, 1)) # 构造Rodrigues矩阵 K = np.array([[0, -axis[2], axis[1]], [axis[2], 0, -axis[0]], [-axis[1], axis[0], 0]]) R = np.eye(3) + np.sin(angle)*K + (1 - np.cos(angle))*np.dot(K, K) return R # 生成旋转矩阵 R = rodrigues_rotation(n2, n1)
3. 计算平移向量
以原点到平面的垂足为对应点,计算平移量让第二个平面的垂足移到第一个平面的垂足:
# 计算原点到平面的垂足 def plane_foot_point(plane): a, b, c, d = plane denom = a**2 + b**2 + c**2 return np.array([-a*d, -b*d, -c*d]) / denom p1 = plane_foot_point(plane1) p2 = plane_foot_point(plane2) # 平移向量:将旋转后的p2移到p1 t = p1 - np.dot(R, p2)
4. 转换data2的所有数据点
对data2的每个点 x 应用变换:x' = R @ x + t
# 假设data2是N×3的numpy数组,示例用模拟数据 np.random.seed(42) data2 = np.random.randn(100, 3) # 应用欧氏变换 data2_transformed = np.dot(data2, R.T) + t
5. 绘制对齐后的3D图
绘制原始平面1、对齐后的平面2,以及data1、转换后的data2:
# 生成平面网格点 xx, yy = np.meshgrid(np.linspace(-5,5,20), np.linspace(-5,5,20)) # 平面1的z坐标 z1 = (-plane1[0]*xx - plane1[1]*yy - plane1[3]) / plane1[2] # 对齐后平面2的z坐标(基于法向量n1和垂足p1推导) z2_aligned = (-n1[0]*xx - n1[1]*yy - (-np.dot(n1, p1))) / n1[2] # 创建3D图 fig = plt.figure(figsize=(10,8)) ax = fig.add_subplot(111, projection='3d') # 绘制平面 ax.plot_surface(xx, yy, z1, alpha=0.3, label='Plane 1') ax.plot_surface(xx, yy, z2_aligned, alpha=0.3, label='Aligned Plane 2', color='orange') # 绘制数据点(示例用模拟data1) data1 = np.random.randn(100,3) ax.scatter(data1[:,0], data1[:,1], data1[:,2], color='blue', label='Data 1') ax.scatter(data2_transformed[:,0], data2_transformed[:,1], data2_transformed[:,2], color='red', label='Transformed Data 2') ax.set_xlabel('X') ax.set_ylabel('Y') ax.set_zlabel('Z') ax.legend() plt.show()
关键注意事项
- 归一化法向量是计算旋转矩阵的前提,避免因法向量长度差异导致旋转错误
- 欧氏变换必须先旋转,再平移,顺序不可颠倒
- 平面平移后需重新推导方程,确保绘制的对齐平面与转换后的数据点匹配
内容的提问来源于stack exchange,提问作者Sunwoo Kwak
相关产品推荐
相关产品推荐

