4.迭代最近点ICP及非线性优化求解

使用非线性优化方法求解ICP

文章目录

  • 使用非线性优化方法求解ICP
    • 前情提要
    • ICP问题回顾
      • 对矩阵变量求导数
    • ICP问题的非线性解法
    • 代码示例


欢迎访问个人网络日志🌹🌹知行空间🌹🌹


前情提要

在迭代最近点算法ICP及SVD求解中介绍了ICP问题及使用SVD分解求解ICP的方法。除了SVD,还可以使用非线性优化的方法来求解ICP

ICP问题回顾

还记得,ICP优化的目标函数为:

min ⁡ R , t 1 2 ∑ i n ∣ ∣ p i − ( R q i + t ) ∣ ∣ 2 2 \min\limits_{R,t}\frac{1}{2}\sum\limits_{i}^n||p_i-(Rq_i+t)||_2^2 R,tmin21in∣∣pi(Rqi+t)22

我们知道旋转和平移可以写成齐次变换的形式,

T = [ R t 0 0 ] T=\begin{bmatrix} R & t\\ 0 &0 \end{bmatrix} T=[R0t0]

ICP优化的目标函数可以写成:

min ⁡ T 1 2 ∑ i n ∣ ∣ p i − T q i ∣ ∣ 2 2 \min\limits_{T}\frac{1}{2}\sum\limits_{i}^n||p_i-Tq_i||_2^2 Tmin21in∣∣piTqi22

这里要优化的变量是 T T T,而 T T T是矩阵?如何对矩阵求导数呢?需要使用李群与李代数的概念。

对矩阵变量求导数

根据《视觉SLAM十四讲》第4讲的介绍, T T T属于特殊欧式群 S E ( 3 ) SE(3) SE(3) S E ( 3 ) SE(3) SE(3)具有连续性质,是李群。

李群局部正切空间上的表示是李代数,李代数相对于李群,类似于导数对函数的意义。

S E ( 3 ) SE(3) SE(3)对应的李代数 s e ( 3 ) \mathcal{se(3)} se(3)为:

s e ( 3 ) = { ξ = [ ρ ϕ ] ∈ R 6 , ρ ∈ R 3 , ϕ ∈ s o ( 3 ) , ξ ∧ = [ ϕ ∧ ρ 0 T 0 ] ∈ R 4 × 4 } \mathcal{se}(3)=\left \{ \xi = \begin{bmatrix} \rho \\ \phi \end{bmatrix} \in \mathbb{R}^6, \rho \in \mathbb{R}^3 ,\phi \in \mathcal{so}(3), \xi^{\wedge } = \begin{bmatrix} \phi ^{\wedge } & \rho \\ 0^T & 0 \end{bmatrix} \in \mathbb{R}^{4\times 4} \right \} se(3)={ξ=[ρϕ]R6,ρR3,ϕso(3),ξ=[ϕ0Tρ0]R4×4}

其中, ξ \xi ξ s e ( 3 ) \mathcal{se}(3) se(3)的元素,是包含平移 ρ \rho ρ和旋转 ϕ \phi ϕ的六维向量。 ϕ \phi ϕ其实是 s o ( 3 ) \mathcal{so}(3) so(3)的元素。

∧ {\wedge } 符号这里表示将六维向量转换成四维矩阵。

t = 0 t=0 t=0附近,齐次变换矩阵可以由 T = e x p ( ξ 0 t ) T=exp(\xi_0t) T=exp(ξ0t)计算出来,由此可以看到,齐次变换矩阵与一个反对称矩阵 ξ 0 ∧ t \xi_0 ^{\wedge }t ξ0t建立了联系,在一时刻对于给定的 T T T,可以求得一个 ξ \xi ξ,其描述了 T T T在局部的导数关系。

矩阵的指数运算显然没有定义,如何计算呢?这里可以用泰勒公式,

e x p ( A ) = ∑ n = 0 ∞ 1 n ! A n exp(A)=\sum\limits _{n=0}^{\infty }\frac{1}{n!}A^n exp(A)=n=0n!1An

ξ \xi ξ写成旋转加平移的形式 [ ρ , ϕ ] T [\rho, \phi]^T [ρ,ϕ]T,再将 ϕ \phi ϕ写成模长和方向的形式 ϕ = θ a \phi=\theta a ϕ=θa,代入上面的公式可得:

e x p ( ξ ∧ ) = [ ∑ n = 0 ∞ 1 n ! ( ϕ ∧ ) n ∑ n = 0 ∞ 1 ( n + 1 ) ! ( ϕ ∧ ) n ρ 0 1 ] ≜ [ R J ρ 0 T 1 ] = T exp(\xi^{\wedge})=\begin{bmatrix} \sum\limits_{n=0}^{\infty}\frac{1}{n!}(\phi ^\wedge )^n & \sum\limits_{n=0}^{\infty}\frac{1}{(n+1)!}(\phi ^\wedge )^n\rho \\ 0 & 1 \end{bmatrix}\triangleq \begin{bmatrix} R & J\rho \\ 0^T &1 \end{bmatrix}=T exp(ξ)= n=0n!1(ϕ)n0n=0(n+1)!1(ϕ)nρ1 [R0TJρ1]=T

ϕ = θ a \phi=\theta a ϕ=θa时,推导可得

J = s i n θ θ I + ( 1 − s i n θ θ ) a a T + 1 − c o s θ θ a ∧ J=\frac{sin\theta}{\theta}I+(1-\frac{sin\theta}{\theta})aa^T+\frac{1-cos\theta}{\theta}a^\wedge J=θsinθI+(1θsinθ)aaT+θ1cosθa

当在李群中完成两个矩阵的乘法时,也就是依次进行两个变换时,李代数上对应会发生怎样的变化呢?

S E ( 3 ) SE(3) SE(3) s e ( 3 ) \mathcal{se}(3) se(3)的指数映射,那么

e x p ( ξ 1 ∧ ) e x p ( ξ 2 ∧ ) exp(\xi_1^\wedge)exp(\xi_2^\wedge) exp(ξ1)exp(ξ2)是否等于 e x p ( ( ξ 1 + ξ 2 ) ∧ ) exp((\xi_1+\xi_2)^\wedge) exp((ξ1+ξ2))呢?对于矩阵的指数运算,上式并不成立。

两个李代数指数映射乘积的完整形式,由Baker-Campbell-Hausdorff(BCH)公式给出,

l n ( e x p ( A ) e x p ( B ) ) = A + B + 1 2 [ A , B ] + 1 12 [ A , [ A , B ] ] − 1 12 [ B , [ A , B ] ] + . . . ln(exp(A)exp(B))=A+B+\frac{1}{2}[A,B]+\frac{1}{12}[A,[A,B]]-\frac{1}{12}[B,[A,B]]+... ln(exp(A)exp(B))=A+B+21[A,B]+121[A,[A,B]]121[B,[A,B]]+...

[,]是李括号,表示二元运算。

以旋转矩阵组成的特殊正交群 S O ( 3 ) SO(3) SO(3)为例,

考虑 S O ( 3 ) SO(3) SO(3)上的李代数 ( l n ( e x p ( ϕ 1 ∧ ) ( ϕ 2 ∧ ) ) ) ∧ (ln(exp(\phi_1^\wedge)(\phi_2^\wedge)))^\wedge (ln(exp(ϕ1)(ϕ2))),当 ϕ 1 \phi_1 ϕ1 ϕ 2 \phi_2 ϕ2为小量,BCH公式中李括号二次以上的项可以忽略掉,则可得近似线性表示为,

( l n ( e x p ( ϕ 1 ∧ ) ( ϕ 2 ∧ ) ) ) ∨ ≈ { J l ( ϕ 2 ) − 1 ϕ 1 + ϕ 2 ϕ 1 为小量 J r ( ϕ 1 ) − 1 ϕ 2 + ϕ 1 ϕ 2 为小量 (ln(exp(\phi_1^\wedge)(\phi_2^\wedge)))^\vee\approx\left\{\begin{matrix} J_l(\phi_2)^{-1}\phi_1 +\phi_2 & \phi_1为小量\\ J_r(\phi_1)^{-1}\phi_2 +\phi_1 & \phi_2为小量 \end{matrix}\right. (ln(exp(ϕ1)(ϕ2))){Jl(ϕ2)1ϕ1+ϕ2Jr(ϕ1)1ϕ2+ϕ1ϕ1为小量ϕ2为小量

上面公式中第一种相当于是对原旋转矩阵左乘一个微小变换矩阵,第二种相当于是对原旋转矩阵右乘一个微小变换矩阵。乘以微小变换矩阵相当于是发生了微小的位移和姿态变化。

左乘微小变换矩阵的近似雅可比矩阵 J l J_l Jl同推导 s e ( 3 ) \mathcal{se}(3) se(3)的指数映射中作用在平移向量 ρ \rho ρ上的雅可比 J J J

J l = J = s i n θ θ I + ( 1 − s i n θ θ ) a a T + 1 − c o s θ θ a ∧ J_l=J=\frac{sin\theta}{\theta}I+(1-\frac{sin\theta}{\theta})aa^T+\frac{1-cos\theta}{\theta}a^\wedge Jl=J=θsinθI+(1θsinθ)aaT+θ1cosθa

通过上面的推导就建立了李群乘法和李代数加法之间的关系

以旋转矩阵为例,对某个旋转 R R R,其对应的李代数为 ϕ \phi ϕ,对其左乘一个微小旋转 △ R \triangle R R,其对应的李代数为 △ ϕ \triangle \phi ϕ。那么在李群上的变化就为 △ R R \triangle R R RR,而对应的在李代数的变化根据BCH公式近似就为 J l − 1 ( ϕ ) △ ϕ + ϕ J_l^{-1}(\phi)\triangle\phi+\phi Jl1(ϕ)ϕ+ϕ,综合以上可以写成:

e x p ( △ ϕ ∧ ) e x p ( ϕ ∧ ) = e x p ( ( ϕ + J l − 1 ( ϕ ) △ ϕ ) ) exp(\triangle \phi^\wedge)exp(\phi^\wedge)=exp((\phi+J_l^{-1}(\phi)\triangle \phi)) exp(ϕ)exp(ϕ)=exp((ϕ+Jl1(ϕ)ϕ))

上面公式中,如果左乘的微小旋转矩阵对应的李代数带雅可比矩阵,则上式就变为(以左乘为例):

e x p ( ( J l ( ϕ ) △ ϕ ) ∧ ) e x p ( ϕ ∧ ) = e x p ( ( ϕ + J l − 1 ( ϕ ) J l ( ϕ ) △ ϕ ) ∧ ) = e x p ( ( ϕ + △ ϕ ) ∧ ) exp((J_l(\phi)\triangle \phi)^\wedge)exp(\phi^\wedge)=exp((\phi+J_l^{-1}(\phi)J_l(\phi)\triangle \phi)^\wedge)=exp((\phi+\triangle \phi)^\wedge) exp((Jl(ϕ)ϕ))exp(ϕ)=exp((ϕ+Jl1(ϕ)Jl(ϕ)ϕ))=exp((ϕ+ϕ))

由上,李代数上的加法,可近似为李群上带左或右雅可比的乘法:

e x p ( ( ϕ + △ ϕ ) ∧ ) = e x p ( ( J l ( ϕ ) △ ϕ ) ∧ ) e x p ( ϕ ∧ ) = e x p ( ϕ ∧ ) e x p ( ( J r ( ϕ ) △ ϕ ) ∧ ) exp((\phi+\triangle \phi)^\wedge)=exp((J_l(\phi)\triangle \phi)^\wedge)exp(\phi^\wedge)=exp(\phi^\wedge)exp((J_r(\phi)\triangle \phi)^\wedge) exp((ϕ+ϕ))=exp((Jl(ϕ)ϕ))exp(ϕ)=exp(ϕ)exp((Jr(ϕ)ϕ))

因为旋转矩阵组成的李群各个变换之间只定义了有意义的乘法而没有定义有意义的加法,因此不能直接在李群上定义导数。

而考虑李群与李代数之间的关系,以旋转矩阵为例对 S O ( 3 ) SO(3) SO(3)上的李代数求导,

∂ R P ∂ R \frac{\partial RP}{\partial R} RRP

由于 S O ( 3 ) SO(3) SO(3)上只对乘法满足封闭性,因此不能按照常规的微分定义来求导,设 R R R对应的李代数为 ϕ \phi ϕ,由 R = e x p ( ϕ ∧ ) R=exp(\phi^\wedge) R=exp(ϕ)可得

∂ e x p ( ϕ ∧ ) P ∂ ϕ = lim ⁡ δ ϕ → 0 e x p ( ( ϕ + δ ϕ ) ∧ ) p − e x p ( ϕ ∧ ) p δ ϕ = lim ⁡ δ ϕ → 0 e x p ( J l ( ϕ ) δ ϕ ) ∧ ) e x p ( ϕ ∧ ) p − e x p ( ϕ ∧ ) p δ ϕ = lim ⁡ δ ϕ → 0 ( I + ( J l ( ϕ ) δ ϕ ) ∧ ) e x p ( ϕ ∧ ) p − e x p ( ϕ ∧ ) p δ ϕ = lim ⁡ δ ϕ → 0 ( J l ( ϕ ) δ ϕ ) ∧ e x p ( ϕ ∧ ) p δ ϕ = lim ⁡ δ ϕ → 0 − ( e x p ( ϕ ∧ ) p ) ∧ J l ( ϕ ) δ ϕ δ ϕ = − ( R p ) ∧ J l ( ϕ ) \begin{align}\frac{\partial exp(\phi^\wedge)P}{\partial \phi}&=\lim_{\delta\phi\to 0}\frac{exp((\phi+\delta \phi)^\wedge)p-exp(\phi^\wedge)p}{\delta\phi}\\ &=\lim_{\delta\phi\to 0}\frac{exp(J_l(\phi)\delta \phi)^\wedge)exp(\phi^\wedge)p-exp(\phi^\wedge)p}{\delta\phi}\\ &=\lim_{\delta\phi\to 0}\frac{(I+(J_l(\phi)\delta \phi)^\wedge)exp(\phi^\wedge)p-exp(\phi^\wedge)p}{\delta\phi}\\ &=\lim_{\delta\phi\to 0}\frac{(J_l(\phi)\delta \phi)^\wedge exp(\phi^\wedge)p}{\delta\phi}\\ &=\lim_{\delta\phi\to 0}\frac{-(exp(\phi^\wedge)p)^\wedge J_l(\phi)\delta \phi}{\delta\phi}\\ &=-(Rp)^\wedge J_l(\phi)\end{align} ϕexp(ϕ)P=δϕ0limδϕexp((ϕ+δϕ))pexp(ϕ)p=δϕ0limδϕexp(Jl(ϕ)δϕ))exp(ϕ)pexp(ϕ)p=δϕ0limδϕ(I+(Jl(ϕ)δϕ))exp(ϕ)pexp(ϕ)p=δϕ0limδϕ(Jl(ϕ)δϕ)exp(ϕ)p=δϕ0limδϕ(exp(ϕ)p)Jl(ϕ)δϕ=(Rp)Jl(ϕ)

上面推导过程中1到2用到了BCH近似公式,2到3用到了泰勒公式,4到5用到了反对称矩阵的性质 A = − A T A=-A^T A=AT,最终得到了旋转后的点相对于旋转矩阵李代数的导数。

通过转换成李代数求导得到的最终的导数包含一个 J l J_l Jl矩阵,其形式和计算过于复杂。另外一种李群求导的方法是扰动模型,对 R R R进行一个左乘或右乘扰动,将结果相对于扰动的变化率作为导数,以左乘扰动 △ R \bigtriangleup R R为例,其对应的李代数为 φ \varphi φ,推导如下:

∂ R p ∂ R = lim ⁡ φ → 0 e x p ( φ ∧ ) e x p ( ϕ ∧ ) p − e x p ( ϕ ∧ ) p φ \frac{\partial Rp}{\partial R}=\lim\limits_{\varphi \to 0}\frac{exp(\varphi^\wedge)exp(\phi^\wedge)p-exp(\phi^\wedge)p}{\varphi} RRp=φ0limφexp(φ)exp(ϕ)pexp(ϕ)p

该式的求导可写成,

∂ R p ∂ R = lim ⁡ φ → 0 e x p ( φ ∧ ) e x p ( ϕ ∧ ) p − e x p ( ϕ ∧ ) p φ = lim ⁡ φ → 0 ( I + φ ∧ ) e x p ( ϕ ∧ ) p − e x p ( ϕ ∧ ) p φ = lim ⁡ φ → 0 φ ∧ R p φ = lim ⁡ φ → 0 − ( R p ) ∧ φ φ = − ( R p ) ∧ \begin{align}\frac{\partial Rp}{\partial R}&=\lim\limits_{\varphi \to 0}\frac{exp(\varphi^\wedge)exp(\phi^\wedge)p-exp(\phi^\wedge)p}{\varphi}\\ &=\lim\limits_{\varphi \to 0}\frac{(I+\varphi^\wedge)exp(\phi^\wedge)p-exp(\phi^\wedge)p}{\varphi} \\ &= \lim\limits_{\varphi \to 0}\frac{\varphi^\wedge Rp}{\varphi} = \lim\limits_{\varphi \to 0}\frac{-(Rp)^\wedge \varphi}{\varphi}= -(Rp)^\wedge\end{align} RRp=φ0limφexp(φ)exp(ϕ)pexp(ϕ)p=φ0limφ(I+φ)exp(ϕ)pexp(ϕ)p=φ0limφφRp=φ0limφ(Rp)φ=(Rp)

相比于对李代数直接求导,省去了一个雅可比 J l J_l Jl的计算。

ICP问题的非线性解法

考虑前面ICP优化的目标函数:

e = min ⁡ T 1 2 ∑ i n ∣ ∣ p i − T q i ∣ ∣ 2 2 = min ⁡ ξ 1 2 ∑ i = 1 n ∣ ∣ ( p i − e x p ( ξ ∧ ) q i ) ∣ ∣ 2 2 e = \min\limits_{T}\frac{1}{2}\sum\limits_{i}^n||p_i-Tq_i||_2^2=\min\limits_\xi\frac{1}{2}\sum_{i=1}^{n}||(p_i-exp(\xi^\wedge)q_i)||_2^2 e=Tmin21in∣∣piTqi22=ξmin21i=1n∣∣(piexp(ξ)qi)22

ξ \xi ξ S E ( 3 ) SE(3) SE(3) T T T对应的李代数。

单个误差项关于位姿的导数,使用李代数的扰动模型可得,

∂ e ∂ ξ = lim ⁡ δ ξ → 0 e ( δ ξ ⊕ ξ ) − e ( ξ ) δ ξ \frac{\partial e}{\partial \xi}=\lim\limits_{\delta\xi\to 0}\frac{e(\delta\xi\oplus\xi)-e(\xi)}{\delta\xi} ξe=δξ0limδξe(δξξ)e(ξ)

⊕ \oplus 表示左乘模型

对于n对三维空间中的点 p p p及其投影 q q q,希望计算的相机旋转和平移分别为 R , t R,t R,t其对应的李群为 T T T。对于空间中的一点 p i = [ X i , Y i , Z i ] T p_i=[X_i,Y_i,Z_i]^T pi=[Xi,Yi,Zi]T,其对应的投影点像素坐标为 μ i = [ μ i , v i ] T \mu_i=[\mu_i,v_i]^T μi=[μi,vi]T,根据相机模型,有以下关系,

s i [ μ i v i 1 ] = K T [ X i Y i Z i 1 ] s_i\begin{bmatrix}\mu_i\\v_i\\1 \end{bmatrix}=KT\begin{bmatrix}X_i\\Y_i\\Z_i\\1 \end{bmatrix} si μivi1 =KT XiYiZi1

写成矩阵的形式为:

s i μ i = K T p i s_i\mu_i=KTp_i siμi=KTpi

上式隐含了一次齐次坐标往三维坐标的转换。

对于n对空间点和对应的图像中投影的观测点,要估计相机的位姿,目标函数就是最小化两者之间的误差,

T ∗ = a r g min ⁡ T 1 2 ∑ i = 1 n ∣ ∣ μ i − 1 s i K T p i ∣ ∣ T^*=arg \min\limits_T\frac{1}{2}\sum\limits_{i=1}^{n}||\mu_i-\frac{1}{s_i}KTp_i|| T=argTmin21i=1n∣∣μisi1KTpi∣∣

记通过相机外参变换到相机坐标系下 p p p点对应的点 q q q的坐标为 q = ( T p ) 1 : 3 = [ X ′ , Y ′ , Z ′ ] q=(Tp)_{1:3}=[X',Y',Z'] q=(Tp)1:3=[X,Y,Z]

根据相机模型关于 q q q点有:

s μ = K q s\mu=Kq sμ=Kq

展开有:

[ s μ s v s ] = [ f x 0 c x o f y c y 0 0 1 ] [ X ′ Y ′ Z ′ ] \begin{bmatrix} s\mu\\sv\\s \end{bmatrix}=\begin{bmatrix} f_x&0&c_x\\o&f_y&c_y\\0&0&1 \end{bmatrix}\begin{bmatrix}X'\\Y'\\Z'\end{bmatrix} sμsvs = fxo00fy0cxcy1 XYZ

重投影误差的左乘扰动求导数为:

∂ e ∂ ξ = ∂ e ∂ q ∂ q ∂ ξ \frac{\partial e}{\partial \xi}=\frac{\partial e}{\partial q}\frac{\partial q}{\partial \xi} ξe=qeξq

根据目标函数和相机模型的公式有:

∂ e ∂ q = − [ ∂ μ ∂ X ′ ∂ μ ∂ Y ′ ∂ μ ∂ Z ′ ∂ v ∂ X ′ ∂ v ∂ Y ′ ∂ v ∂ Z ′ ] = − [ f x Z ′ 0 − f x X ′ Z ′ 2 0 f y Z ′ − f y Y ′ Z ′ 2 ] \frac{\partial e}{\partial q}=-\begin{bmatrix}\frac{\partial \mu}{\partial X'} & \frac{\partial \mu}{\partial Y'} &\frac{\partial \mu}{\partial Z'}\\ \frac{\partial v}{\partial X'}&\frac{\partial v}{\partial Y'}&\frac{\partial v}{\partial Z'}\end{bmatrix}=-\begin{bmatrix}\frac{f_x}{Z'} & 0 &-\frac{f_xX'}{Z'^2}\\ 0&\frac{f_y}{Z'}&-\frac{f_yY'}{Z'^2}\end{bmatrix} qe=[XμXvYμYvZμZv]=[Zfx00ZfyZ′2fxXZ′2fyY]

而第二项为变换后的点关于李代数的导数,

∂ ( T p ) ∂ T = [ I − q ∧ 0 0 ] \frac{\partial(Tp)}{\partial T}=\begin{bmatrix}I&-q^\wedge \\ 0 & 0 \end{bmatrix} T(Tp)=[I0q0]

根据 q q q定义取出前三维,

∂ q ∂ T = [ I , − q ∧ ] T \frac{\partial q}{\partial T}=[I,-q^\wedge ]^T Tq=[I,q]T

最后将两者相乘可以求得 ∂ e ∂ ξ \frac{\partial e}{\partial \xi} ξe

代码示例

使用G2O求解非线性优化问题,节点就是待求解变量,边是观测数据点。

前面推导的是相机模型的点与三维空间点的PnP问题的求解,对于ICP直接是成对三维点之间的优化,相对于PnP更简单。

定义G2O的顶点和边,

    class VertexPose : public g2o::BaseVertex<6, Sophus::SE3d> {public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW;// 设置初始化的更新值 virtual void setToOriginImpl() override { _estimate = Sophus::SE3d();}// left multiplication on SE3virtual void oplusImpl(const double *update) {Eigen::Matrix<double, 6, 1> update_eigen;update_eigen << update[0], update[1], update[2],update[3], update[4], update[5];_estimate = Sophus::SE3d::exp(update_eigen) * _estimate;}virtual bool read(std::istream &in) override {return true;} virtual bool write(std::ostream &out) const override { return true;}};class EdgeProjectXYZRGBDPoseOnly : public g2o::BaseUnaryEdge<3, Eigen::Vector3d, bcv::VertexPose> {public:EIGEN_MAKE_ALIGNED_OPERATOR_NEW;EdgeProjectXYZRGBDPoseOnly(const Eigen::Vector3d &point) : _point(point) {}virtual void computeError() override {const VertexPose* p = static_cast<const VertexPose*> (_vertices[0]);_error = _measurement - p->estimate() * _point;}virtual void linearizeOplus() override {VertexPose *p = static_cast<VertexPose*> (_vertices[0]);Sophus::SE3d T = p->estimate();Eigen::Vector3d xyz_trans = T * _point;_jacobianOplusXi.block<3, 3>(0, 0) = -Eigen::Matrix3d::Identity();_jacobianOplusXi.block<3, 3>(0, 3) = Sophus::SO3d::hat(xyz_trans);}bool read(std::istream &in) { return true; }bool write(std::ostream &out) const { return true; }protected:Eigen::Vector3d _point;};

定义求解器:

    void ICPSolver::NLOSolver(std::vector<cv::Point3f> &pts1,std::vector<cv::Point3f> &pts2,cv::Mat &R, cv::Mat &t){typedef g2o::BlockSolverX BlockSolverType;typedef g2o::LinearSolverDense<BlockSolverType::PoseMatrixType> LinearSolverType;auto solver = new g2o::OptimizationAlgorithmGaussNewton(g2o::make_unique<BlockSolverType>(g2o::make_unique<LinearSolverType>()));g2o::SparseOptimizer optimizer; // graph modeloptimizer.setAlgorithm(solver); // set solveroptimizer.setVerbose(true); // print infobcv::VertexPose *p = new VertexPose();p->setId(0);p->setEstimate(Sophus::SE3d());optimizer.addVertex(p);// add edgefor(size_t i = 0; i < pts1.size(); i++) {bcv::EdgeProjectXYZRGBDPoseOnly *e = new bcv::EdgeProjectXYZRGBDPoseOnly(Eigen::Vector3d(pts2[i].x, pts2[i].y, pts2[i].z));e->setVertex(0, p);e->setMeasurement(Eigen::Vector3d(pts1[i].x, pts1[i].y, pts1[i].z));e->setInformation(Eigen::Matrix3d::Identity());optimizer.addEdge(e);}auto t1 = std::chrono::system_clock::now();optimizer.initializeOptimization();optimizer.optimize(10);auto t2 = std::chrono::system_clock::now();auto d = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();std::cout << "duration: " << d << " ms" << std::endl;std::cout << "after optim:\n";std::cout << "T=\n" << p->estimate().matrix() << std::endl;Eigen::Matrix3d R_ = p->estimate().rotationMatrix();Eigen::Vector3d t_ = p->estimate().translation();std::cout <<"det(R_)=" << R_.determinant() << std::endl;std::cout <<"R_R_^T=" << R_ * R_.transpose() << std::endl;std::cout << "R:\n" << R_ << std::endl;std::cout << "t:\n" << t_ << std::endl;R = (cv::Mat_<double>(3, 3) <<R_(0, 0), R_(0, 1), R_(0, 2),R_(1, 0), R_(1, 1), R_(1, 2),R_(2, 0), R_(2, 1), R_(2, 2));t = (cv::Mat_<double>(3, 1) << t_(0, 0), t_(1, 0), t_(2, 0));}

完整可运行代码见https://gitee.com/lx_r/basic_cplusplus_examples

  • 1.视觉SLAM十四讲第二版p196-198

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.xdnf.cn/news/143816.html

如若内容造成侵权/违法违规/事实不符,请联系一条长河网进行投诉反馈,一经查实,立即删除!

相关文章

河北吉力宝以步力宝健康鞋引发的全新生活生态商

在当今瞬息万变的商业世界中&#xff0c;成功企业通常都是那些不拘泥于传统、勇于创新的先锋之选。河北吉力宝正是这样一家企业&#xff0c;通过打造一双步力宝健康鞋&#xff0c;他们以功能性智能科技穿戴品为核心&#xff0c;成功创造了一种结合智能康养与时尚潮流的独特产品…

Zotero同步论文、笔记

之前用 Mendeley[1]看论文&#xff0c;看中几个功能&#xff1a; tags&#xff0c;多标签分类&#xff0c;类似微信分组&#xff0c;用来快速筛&#xff08;已添加的&#xff09;某一类文献&#xff1b;同步&#xff0c;包括 pdf 和笔记&#xff08;高亮、便签、tags&#xff…

数链科技基于PP-ChatOCR实现合同信息抽取,准确率达98%

传统大宗商品供应链领域数字化程度低&#xff0c;存在交易环节不透明、业务流程不标准、依赖主体信用评价等问题&#xff0c;业务中存在大量营业执照、身份证、终端合同等线下单据&#xff0c;严重依赖人工线下审核&#xff0c;且数字化难度大。 不同终端、机构、仓库的单据格式…

python使用websocket实现多端数据同步,多个websocket同步消息,断开链接自动清理

我使用的是flask_sock这个模块&#xff0c;我的使用场景是&#xff1a;可以让数据多端实时同步。在游戏控制后台和游戏选手的ipad上都可以实时调整角色的技能和点数什么的&#xff0c;所以需要这样的一个功能来实现数据实时同步。 下面是最小的demo案例&#xff1a; from fla…

LoadLibraryEx调用dll时有未经处理的异常,发生访问冲突

0x000000000006A220 处的第一机会异常(在 testHFHZDll.exe 中): 0xC0000005: 执行位置 0x000000000006A220 时发生访问冲突。 0x000000000006A220 处有未经处理的异常(在 testHFHZDll.exe 中): 0xC0000005: 执行位置 0x000000000006A220 时发生访问冲突。 最近做一个测试&#…

[C++随笔录] stack queue使用

stack && queue使用 stackqueue题目训练 stack 栈的特点是 先进后出(first in last out) 我们可以看出, stack的接口相比 vector/string/list 的接口少的太多了 构造函数 && 容器适配器 容器适配器的含义: 首先, 适配器 — — 用户传数据进来, 我们用合适的…

mac安装python2

Python 2 于 2020 年 1 月 1 日宣布结束支持&#xff0c;包括 Homebrew 在内的许多项目和包管理器已经停止支持 Python 2。 如果现在你还要安装 Python 2&#xff0c;需要从 Python 官网下载安装包&#xff1a; 访问 Python 的发布页面。从页面底部找到 Python 2 的最后一个版…

DeepSpeed简单教程

DeepSpeed github地址、DeepSpeed 官网 、DeepSpeed API文档、huggingface DeepSpeed文档、知乎deepspeed入门教程、微软deepspeed博客示例代码&#xff1a;《Using DeepSpeed with HF&#x1f917; Trainer》、 BLOOM_LORA&#xff08;运行示例见《Running_Deepspeed》&#x…

C++标准模板(STL)- 输入/输出操纵符-(std::setbase,std::setfill)

操纵符是令代码能以 operator<< 或 operator>> 控制输入/输出流的帮助函数。 不以参数调用的操纵符&#xff08;例如 std::cout << std::boolalpha; 或 std::cin >> std::hex; &#xff09;实现为接受到流的引用为其唯一参数的函数。 basic_ostream::…

人工智能AI 全栈体系(七)

第一章 神经网络是如何实现的 神经网络不仅仅可以处理图像&#xff0c;同样也可以处理文本。由于处理图像讲起来比较形象&#xff0c;更容易理解&#xff0c;所以基本是以图像处理为例讲解的。 七、词向量 图像处理之所以讲起来比较形象&#xff0c;是因为图像的基本元素是像…

Ctfshow web入门 代码审计篇 web301-web310 详细题解 全

CTFshow 代码审计 web301 下载的附件的目录结构如下&#xff1a; 开题后界面&#xff0c;看见输入框&#xff0c;感觉是sql。 大概浏览一遍源码&#xff0c;我们可以发现在checklogin.php文件中有无过滤的SQL语句&#xff0c;SQL注入没得跑了。 这题SQL注入有三种做法。 方法一…

信息安全:网络物理隔离技术原理与应用.

信息安全&#xff1a;网络物理隔离技术原理与应用. 随着网络攻击技术不断增强&#xff0c;恶意入侵内部网络的风险性也相应急剧提高。满足内外网信息及数据交换需求&#xff0c;又能防止网络安全事件出现的安全技术就应运而生了&#xff0c;这种技术称为“物理隔离技术” 基本原…

使用Vue、ElementUI实现登录注册,配置axios全局设置,解决CORS跨域问题

目录 引言 什么是ElementUI&#xff1f; 步骤1&#xff1a;创建Vue组件用于用户登录和注册 1. 基于SPA项目完成登录注册 在SPA项目中添加elementui依赖 在main.js中添加elementui模块 创建用户登录注册组件 配置路由 修改项目端口并启动项目 静态页面展示图 步骤2&#x…

网络爬虫——urllib(1)

前言&#x1f36d; ❤️❤️❤️网络爬虫专栏更新中&#xff0c;各位大佬觉得写得不错&#xff0c;支持一下&#xff0c;感谢了&#xff01;❤️❤️❤️ 前篇简单介绍了什么是网络爬虫及相关概念&#xff0c;这篇开始讲解爬虫中的第一个库——urllib。 urllib&#x1f36d; …

Jenkins学习笔记4

配置构建流程&#xff1a; Jenkins任务创建&#xff1a; 1&#xff09;创建新任务&#xff1a; 把这个Accept first connection改成 No Validation。问题得到解决。 说明下&#xff0c;要确认下主分支的名称是master还是main。 构建触发器这块暂时没有需要配置的。 传输文件…

[FineReport]安装与使用(连接Hive3.1.2)

一、安装(对应hive3.1.2) 注&#xff1a;服务器的和本地的要同时安装。本地是测试环境&#xff0c;服务器的是生产环境 1、服务器安装 1、下载 免费下载FineReport - FineReport报表官网 向下滑找到 2、解压 [rootck1 /home/data_warehouse/software]# tar -zxvf tomcat…

利用C++开发一个迷你的英文单词录入和测试小程序-源码

接上一篇&#xff0c;有了数据库的查询&#xff0c;再把小测试的功能给补足&#xff0c;小程序的结构就出来了。 备注&#xff1a;enable_if 有更优秀的concept C 20替代品&#xff0c;C11 里面提到的any&#xff0c;variant&#xff0c;再C17 已经被纳入了标准库。这里完全可…

软件设计模式系列之十八——迭代器模式

1 模式的定义 迭代器模式是一种行为型设计模式&#xff0c;它允许客户端逐个访问一个聚合对象中的元素&#xff0c;而不暴露该对象的内部表示。迭代器模式提供了一种统一的方式来遍历不同类型的集合&#xff0c;使客户端代码更加简洁和可复用。 2 举例说明 为了更好地理解迭…

瑞云介绍使用ZBrush和Marmoset工具包制作的风格化巨怪战斗机

Renderbus瑞云渲染的小编今天给大家介绍下Gianluca Squillace使用 ZBrush 和 Marmoset 工具包制作巨怪战士的一些技巧。这位艺术家还贴心地告诉大家&#xff0c;有些步骤是可以省略跳过的&#xff0c;这样就可以节省时间&#xff0c;帮助我们快速完成角色的创作啦。快速有用的步…

tp5连接多个数据库

一、如果你的主数据库配置文件都在config.php里 直接在config.php中中定义db2&#xff1a; 控制器中打印一下&#xff1a; <?php namespace app\index\controller; use think\Controller; use think\Db; use think\Request; class Index extends Controller {public fun…