Python求解两组三维点之间的刚体变换矩阵

该代码实现了对两组三维点的坐标进行处理,通过计算点集的重心并中心化,然后运用奇异值分解求解旋转矩阵。接着计算平移向量,最终组合成变换矩阵RT,实现点集之间的对应变换。
Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

给定两组对应的三维点的坐标,分别存储在变量 PointsPoints_prime 中。代码首先对两组点分别计算了点集的重心,并将点集中心化(将每个点坐标减去点集重心)。然后,通过奇异值分解(SVD)求解旋转矩阵,使用 SVD 方法可以在保证计算稳定性的同时,可以在奇异矩阵(Singular matrix)存在的情况下计算出解。求出旋转矩阵后,根据重心的偏移量求出平移向量,并将旋转矩阵

和平移向量组合成一个4 \times 4的变换矩阵返回,即变量 RT

import numpy as np
import scipy.io as io

real = np.mat([[2079.43, -1547.92, 1134.55], [2034.43, -278.79, 1077.51], \
          [2035.94, -275.07, 573.15], [2882.85, -1173.37, 1682.69]])

# [2079.43, -1547.92, 1134.55], [2034.43, -278.79, 1077.51], \
#           [2035.94, -275.07, 573.15], [2882.85, -1173.37, 1682.69]

point_real = np.zeros(16).reshape(4, 4)
point_real[:, 0:3] = real
point_real[:, 3] = 1
# point_real[:, 1] = real[:, 2].T
# point_real[:, 2] = real[:, 1].T
print(point_real)

model = np.mat([[-824.53, 589.02, -2779.23], [-869.54, 533.76, -1516.28], [-867.87, 30.86, -1508.99], \
               [-20.7, 1137.32, -2420.62]])

model_real = np.zeros(16).reshape(4, 4)
model_real[:, 0:3] = model
model_real[:, 3] = 1
model_real[:, 1] = model[:, 2].T
model_real[:, 2] = model[:, 1].T
print(model_real)

import numpy as np
import cv2

Points = model_real

Points_prime = point_real


P = Points[:, 0:3]
P_hat = Points_prime[:, 0:3]
points1_sum = P.sum(axis=0)
points2_sum = P_hat.sum(axis=0)
print(P, P_hat)
points1_mean = P.mean(axis=0)
points2_mean = P_hat.mean(axis=0)

srcDat = P - points1_mean
dstDat = P_hat - points2_mean

matS = srcDat.T.dot(dstDat)

w, u, v = cv2.SVDecomp(matS)

matTemp = u.dot(v)

det = cv2.determinant(matTemp)

matM = np.eye(3, dtype=np.float64)
matM[2, 2] = det

matR = v.T.dot(matM).dot(u.T)

print(matR)

t_x = points2_mean[0] - points1_mean.dot(matR[0, :].T)
t_y = points2_mean[1] - points1_mean.dot(matR[1, :].T)
t_z = points2_mean[2] - points1_mean.dot(matR[2, :].T)

print(t_x, t_y, t_z)
T = [t_x, t_y, t_z]
print(T)

RT = np.zeros(16).reshape(4, 4)
RT[0:3, 0:3] = matR
RT[0, 3] = t_x
RT[1, 3] = t_y
RT[2, 3] = t_z
RT[3, 3] = 1

# io.savemat("matR_right.mat", {'data': matR})
# io.savemat("T_right.mat", {'data': T})
print(RT)
print((np.matmul(RT, model_real.T) - point_real.T).T)
# io.savemat("RT.mat", {'data': RT})

具体来说,给定两组对应的三维点的坐标,分别存储在变量 PointsPoints_prime 中。首先,将每个点的坐标都减去它所在点集的重心,这是为了保证变换不受点集的绝对位置影响,只考虑点集之间的相对位置和方向。

然后,假设存在一个3 \times 3的旋转矩阵R和一个3 \times 1的平移向量T,可以用它们来对第一个点集 P进行变换,得到对应的第二个点集P': 

P'=RP+T

我们的目标是求解旋转矩阵R和平移向量T, 使得变换后的点集P' 尽可能接近于目标点集 P_\text{target}。可以最小化点集之间的距离,例如平均欧氏距离:

 

为了最小化这个距离,可以利用最小二乘法求解RT。可以将PP'拉成向量形式,然后用P'来逼近P_\text{target},即: 

 

两边同时左乘P^T,得到: 

 

 这里P^TP的转置。因为PP_\text{target}是已知的,所以可以用P'的值来逼近 P_\text{target},从而得到P'

 

这里(P^T P)^{-1}P^T P的逆矩阵。将P'的值代入P' = RP + T,可以得到: 

 

两边同时左乘P^T,得到: 

接下来是对平移向量的求解。平移向量是指在变换过程中,整个物体沿着 x、y、z 三个方向发生的位移。可以通过计算两组点集的质心之间的差异来求解平移向量。质心是指物体在空间中的平均位置。

可以首先分别计算出两组点集的质心,然后计算它们之间的差异,就能得到平移向量了。在这里,首先用 sum 方法计算每个点集中所有点的坐标之和,然后用 mean 方法计算出所有点的平均坐标,从而得到两个点集的质心。

接下来,需要将每个点与它所在的点集的质心之间的差异计算出来,这样就能得到每个点在三维空间中的位置相对于它所在的点集的平移量。用 srcDatdstDat 分别表示两个点集中每个点与质心之间的差异,然后将它们放在一个矩阵 matS 中,这个矩阵的大小为 3x3。在这里,使用了 NumPy 的广播机制,将质心向量重复了多次,然后再进行减法操作,从而得到每个点与质心之间的差异。

接下来,需要计算旋转矩阵和平移向量。为了求解旋转矩阵,需要进行奇异值分解(SVD),将矩阵 matS 分解为 UWV 三个矩阵的乘积。然后,需要将 UV 进行转置,将它们乘起来得到旋转矩阵 matR

为了求解平移向量,可以使用矩阵运算来计算,将平移向量记为 T,然后计算出每个分量的值,这里的计算方法是将两个质心之间的向量乘以旋转矩阵,再取相反数。最后,将旋转矩阵和平移向量合并成一个 4x4 的变换矩阵 RT,其中最后一个元素设置为 1。

这样,就得到了从一个点集到另一个点集的变换矩阵。可以使用这个矩阵来对点云进行变换,从而得到对应的形状变化和位姿变化。

您可能感兴趣的与本文相关的镜像

Python3.11

Python3.11

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

<think>好的,我现在需要帮助用户解决如何根据已知的三维点对计算变换矩阵的问题。首先,我需要回忆相关的知识,确保自己对这个主题有足够的理解。三维点对的变换通常涉及刚体变换,包括旋转和平移,也可能包括缩放,这取决于具体需求。 用户提到的是“变换矩阵”,这可能包括仿射变换,比如刚体变换(旋转+平移)或相似变换(旋转+平移+缩放)。所以首先需要确定用户需要的是哪种变换。如果是刚体变换变换矩阵通常是一个4x4的矩阵,包含旋转矩阵R和平移向量t,形式如下: $$ \begin{bmatrix} R & t \\ 0 & 1 \\ \end{bmatrix} $$ 其中R是3x3的旋转矩阵,t是3x1的平移向量。如果是相似变换,可能还会有一个缩放因子s,这时候R会被缩放为sR。 接下来,用户想知道如何根据已知的三维点求解这个矩阵。最常见的解法应该是使用最小二乘法来最小化对应点之间的误差。例如,对于刚体变换,可以使用奇异值分解(SVD)的方法来计算最优的R和t。 首先,假设我们有n对三维点,源点集为$P = \{p_i\}$,目标点集为$Q = \{q_i\}$,其中每个点对满足$q_i = R p_i + t + \epsilon_i$,其中$\epsilon_i$是噪声或误差。我们需要找到R和t使得所有点的总误差最小。 步骤大致如下: 1. 计算两个点集的质心: - 源点集的质心$\bar{p} = \frac{1}{n}\sum_{i=1}^n p_i$ - 目标点集的质心$\bar{q} = \frac{1}{n}\sum_{i=1}^n q_i$ 2. 将点集去中心化,得到新的坐标: - $p'_i = p_i - \bar{p}$ - $q'_i = q_i - \bar{q}$ 3. 计算协方差矩阵H: $$ H = \sum_{i=1}^n p'_i {q'_i}^T $$ 4. 对H进行奇异值分解(SVD): $$ H = U \Sigma V^T $$ 5. 旋转矩阵R由U和V的乘积得到: $$ R = V U^T $$ 这里需要注意,如果V和U的行列式为负,则需要取反其中一个矩阵的符号以保证R是真正的旋转矩阵(行列式为1)。 6. 计算平移向量t: $$ t = \bar{q} - R \bar{p} $$ 这样得到的R和t就是最优的刚体变换参数。如果是相似变换,还需要计算缩放因子s,可以通过计算所有点对之间的尺度差异的平均值来得到。 此外,如果点对数量较少(如刚好3个非共线点),可能有闭式解。而如果存在噪声或更多点,最小二乘方法会更鲁棒。 需要注意的是,这种方法假设对应点对已经正确匹配,并且不存在外点(outliers)。如果存在外点,可能需要使用RANSAC等鲁棒估计方法。 用户可能还需要知道如何实现这个算法,或者是否有现成的库可以使用。例如,在Python中,可以使用NumPy进行矩阵运算和SVD分解。 可能的相关问题包括如何处理噪声、点对不匹配的情况,或者如何扩展到其他类型的变换(如仿射变换,包含剪切等)。此外,还有如何评估计算得到的变换矩阵的精度,或者如何处理三维点对的配准问题等。 验证过程中,我需要确保公式的正确性,比如协方差矩阵的计算是否应该是$p'_i {q'_i}^T$的求和,以及SVD分解后的旋转矩阵是否正确。此外,平移向量的推导是否正确,是否确实需要减去质心的变换后坐标。 可能的问题点:如果点对的数量不足,或者点共面、共线,可能导致解不唯一或不可靠。这时候需要更多的点或者不同的方法。 总结下来,回答的结构应该包括: 1. 问题定义:三维点对到变换矩阵的计算,可能的变换类型。 2. 解法步骤:质心去中心化,协方差矩阵,SVD分解求旋转,平移计算。 3. 公式展示,使用$$...$$格式。 4. 可能的扩展(如缩放,鲁棒方法)。 5. 相关问题的生成,如优化方法、应用场景等。 最后,确保引用正确,比如提到SVD方法时是否需要引用相关文献,但用户可能没有提供具体的引用源,所以可能暂时不需要添加引用标识,除非有内部引用需求。根据用户的示例,可能需要在某些结论后添加引用,但如果没有明确的来源,可能可以忽略或使用通用引用格式。</think>### 根据三维点对计算变换矩阵的方法 根据已知的三维点求解变换矩阵的核心是**刚体变换**(旋转+平移),可通过以下步骤实现: #### 1. 问题建模 假设有$n$对三维点,源点集为$P = \{p_i\}$,目标点集为$Q = \{q_i\}$,需找到旋转矩阵$R$和平移向量$t$,使得: $$ q_i = R \cdot p_i + t + \epsilon_i $$ 其中$\epsilon_i$为噪声,目标是最小化总误差$\sum \|\epsilon_i\|^2$。 #### 2. 计算步骤 **a. 计算质心** 源点集质心: $$ \bar{p} = \frac{1}{n} \sum_{i=1}^n p_i $$ 目标点集质心: $$ \bar{q} = \frac{1}{n} \sum_{i=1}^n q_i $$ **b. 去中心化坐标** $$ p'_i = p_i - \bar{p}, \quad q'_i = q_i - \bar{q} $$ **c. 构建协方差矩阵** $$ H = \sum_{i=1}^n p'_i {q'_i}^T $$ **d. 奇异值分解(SVD)** 对$H$进行分解: $$ H = U \Sigma V^T $$ 旋转矩阵$R$为: $$ R = V U^T $$ (需确保$\det(R)=1$,若为$-1$则取$V \cdot \text{diag}(1,1,-1) \cdot U^T$)[^1] **e. 计算平移向量** $$ t = \bar{q} - R \cdot \bar{p} $$ #### 3. 扩展情况 - **相似变换**(含缩放):在计算$R$后,通过最小二乘法求缩放因子$s$: $$ s = \frac{\sum_{i=1}^n \|q'_i\|}{\sum_{i=1}^n \|p'_i\|} $$ - **含噪声或外点**:使用RANSAC等鲁棒估计算法[^2]。 #### 4. 代码示例(Python) ```python import numpy as np def compute_transform(P, Q): # P和Q为n×3的矩阵 centroid_p = np.mean(P, axis=0) centroid_q = np.mean(Q, axis=0) P_centered = P - centroid_p Q_centered = Q - centroid_q H = P_centered.T @ Q_centered U, _, Vt = np.linalg.svd(H) R = Vt.T @ U.T if np.linalg.det(R) < 0: Vt[-1,:] *= -1 R = Vt.T @ U.T t = centroid_q - R @ centroid_p return R, t ```
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值