高斯牛顿法去畸变(C++实现)

1. 背景

在实际三维重建时,通常会遇到如下问题:
已知有畸变的点坐标 x ′ , y ′ x',y' x,y,已知畸变模型 f ( x , y ) , g ( x , y ) f(x,y),g(x,y) f(x,y),g(x,y), 求无畸变的点坐标 x , y x,y x,y。畸变模型为
x ′ = x + f ( x , y ) y ′ = y + g ( x , y ) \begin{matrix} x'=x+f(x,y) \\ y'=y+g(x,y) \end{matrix} x=x+f(x,y)y=y+g(x,y)
对于畸变模型通常是非线性函数来说,通过左边的有畸变坐标解算无畸变坐标,解析方法难度很大。因此,数值求解的方法更适用于去畸变的情况。

2. 一维高斯牛顿法

先来看该问题的一维表示
y = x + f ( x ) y=x+f(x) y=x+f(x)
相当于已知 y y y f ( x ) f(x) f(x),求解x。令
F ( x ) = x + f ( x ) − y F(x) =x+f(x)-y F(x)=x+f(x)y
该问题等价求 F ( x ) = 0 F(x)=0 F(x)=0时的x, 在数值分析上就是求最小化时的x,即
x = a r g m i n ∣ ∣ F ( x ) ∣ ∣ x=argmin{||F(x)||} x=argminF(x)
为了求导的方便,通常等价为如下形式
x = a r g m i n 1 2 ∣ ∣ F ( x ) ∣ ∣ 2 x=arg\rm{min}{\frac{1}{2}||F(x)||^2} x=argmin21F(x)2
F ( x ) F(x) F(x) x x x处进行泰勒展开
F ( x + Δ x ) = F ( x ) + F ′ ( x ) Δ x + F ′ ′ ( x ) 2 Δ x 2 + . . . F(x+\Delta{x})=F(x)+F'(x)\Delta{x}+\frac{F''(x)}{2}\Delta{x}^2+... F(x+Δx)=F(x)+F(x)Δx+2F(x)Δx2+...
高斯牛顿法的思想是取其一阶线性近似为
F ( x + Δ x ) ≈   F ( x ) + F ′ ( x ) Δ x F(x+\Delta{x})\approx\,F(x)+F'(x)\Delta{x} F(x+Δx)F(x)+F(x)Δx
用雅可比矩阵 J ( x ) J(x) J(x)来表示一阶导数
代入式(5)中,求最小化的问题需要对目标求导,求一阶导数为0时的x
1 2 ∣ ∣ F ( x + Δ x ) ∣ ∣ 2 = 1 2 [ F ( x ) T F ( x ) + 2 F ( x ) T J ( x ) Δ x + Δ x T J ( x ) T J ( x ) Δ x ] \frac{1}{2}||F(x+\Delta{x})||^2=\frac{1}{2}[{F(x)^TF(x)+2F(x)^TJ(x)\Delta{x}+\Delta{x}^TJ(x)^TJ(x)\Delta{x}}] 21F(x+Δx)2=21[F(x)TF(x)+2F(x)TJ(x)Δx+ΔxTJ(x)TJ(x)Δx]
对上式求导,并令导数为0,得到
J ( x ) T J ( x ) Δ x = − J ( x ) T F ( x ) J(x)^TJ(x)\Delta{x}=-J(x)^TF(x) J(x)TJ(x)Δx=J(x)TF(x)
那么
Δ x = ( J ( x ) T J ( x ) ) − 1 ( − J ( x ) T F ( x ) ) \Delta{x}=(J(x)^TJ(x))^{-1}(-J(x)^TF(x)) Δx=(J(x)TJ(x))1(J(x)TF(x))

这样获得了增量 Δ x \Delta{x} Δx的大小,则x的迭代为
x k + 1 = x k + Δ x = x k + ( J ( x k ) T J ( x k ) ) − 1 ( − J ( x k ) T F ( x k ) ) x_{k+1}=x_{k}+\Delta{x}=x_{k}+(J(x_{k})^TJ(x_{k}))^{-1}(-J(x_{k})^TF(x_{k})) xk+1=xk+Δx=xk+(J(xk)TJ(xk))1(J(xk)TF(xk))
对该迭代过程限制最大迭代次数或者增量小于最小改变量来求解得到最终的x。

3. 高斯牛顿去畸变求解过程

参照一维高斯牛顿法的过程,对于式(1)的畸变模型,令残差
r ( x , y ) = [ F ( x , y ) G ( x , y ) ] r(x,y)=\begin{bmatrix} F(x,y) \\ G(x,y) \end{bmatrix} r(x,y)=[F(x,y)G(x,y)]
其中,
F ( x , y ) = x + f ( x , y ) − x ′ G ( x , y ) = y + g ( x , y ) − y ′ F(x,y)=x+f(x,y)-x'\\ G(x,y)=y+g(x,y)-y' F(x,y)=x+f(x,y)xG(x,y)=y+g(x,y)y

那么去畸变的结果就是
( x , y ) = a r g m i n 1 2 ∣ ∣ r ( x , y ) ∣ ∣ 2 (x,y)=arg\rm{min}{\frac{1}{2}||\it{r}(x,y)||^2} (x,y)=argmin21r(x,y)2
根据式(10),
[ Δ x Δ y ] = ( J ( x , y ) T J ( x , y ) ) − 1 ( − J ( x , y ) T r ( x , y ) ) \begin{bmatrix} \Delta{x} \\ \Delta{y} \end{bmatrix} =(J(x,y)^TJ(x,y))^{-1}(-J(x,y)^Tr(x,y)) [ΔxΔy]=(J(x,y)TJ(x,y))1(J(x,y)Tr(x,y))
其中,
J ( x ) = [ ∂ F ( x , y ) ∂ x ∂ F ( x , y ) ∂ y ∂ G ( x , y ) ∂ x ∂ G ( x , y ) ∂ y ] J(x)=\begin{bmatrix} \frac{\partial{F(x,y)}}{\partial{x}} & \frac{\partial{F(x,y)}}{\partial{y}} \\ \frac{\partial{G(x,y)}}{\partial{x}} & \frac{\partial{G(x,y)}}{\partial{y}} \end{bmatrix} J(x)=[xF(x,y)xG(x,y)yF(x,y)yG(x,y)]
同样地,根据式(11)迭代计算最后去畸变的结果。

为了更好说明计算过程,用具体的数据来进行推导。通常畸变模型是高阶非线性的,但为了说明方便,这里假设畸变模型为双线性,如下:

f ( x , y ) = ( 1 − x − y + x y ) ∗ k 1 + ( x − x y ) ∗ k 2 + ( y − x y ) ∗ k 3 + x y ∗ k 4 g ( x , y ) = ( 1 − x − y + x y ) ∗ k 5 + ( x − x y ) ∗ k 6 + ( y − x y ) ∗ k 7 + x y ∗ k 8 f(x,y)=(1-x-y+xy)*k_1+(x-xy)*k_2+(y-xy)*k_3+xy*k_4 \\ g(x,y)=(1-x-y+xy)*k_5+(x-xy)*k_6+(y-xy)*k_7+xy*k_8 f(x,y)=1xy+xy)k1+(xxy)k2+(yxy)k3+xyk4g(x,y)=1xy+xy)k5+(xxy)k6+(yxy)k7+xyk8

求上式的一阶偏导数
∂ F ( x , y ) ∂ x = 1 + ∂ f ( x , y ) ∂ x = 1 + ( − 1 + y ) ∗ k 1 + ( 1 − y ) ∗ k 2 + ( − y ) ∗ k 3 + y ∗ k 4 ∂ F ( x , y ) ∂ y = ∂ f ( x , y ) ∂ y = ( − 1 + x ) ∗ k 1 + ( − x ) ∗ k 2 + ( 1 − x ) ∗ k 3 + x ∗ k 4 ∂ G ( x , y ) ∂ x = ∂ g ( x , y ) ∂ x = ( − 1 + y ) ∗ k 5 + ( 1 − y ) ∗ k 6 + ( − y ) ∗ k 7 + y ∗ k 8 ∂ G ( x , y ) ∂ y = 1 + ∂ g ( x , y ) ∂ y = 1 + ( − 1 + x ) ∗ k 5 + ( − x ) ∗ k 6 + ( 1 − x ) ∗ k 7 + x ∗ k 8 \begin{matrix} \frac{\partial{F(x,y)}}{\partial{x}}=1+\frac{\partial{f(x,y)}}{\partial{x}}=1+(-1+y)*k_1+(1-y)*k_2+(-y)*k_3+y*k_4 \\ \frac{\partial{F(x,y)}}{\partial{y}}=\frac{\partial{f(x,y)}}{\partial{y}}=(-1+x)*k_1+(-x)*k_2+(1-x)*k_3+x*k_4 \\ \frac{\partial{G(x,y)}}{\partial{x}}=\frac{\partial{g(x,y)}}{\partial{x}}=(-1+y)*k_5+(1-y)*k_6+(-y)*k_7+y*k_8 \\ \frac{\partial{G(x,y)}}{\partial{y}}=1+\frac{\partial{g(x,y)}}{\partial{y}}=1+(-1+x)*k_5+(-x)*k_6+(1-x)*k_7+x*k_8 \end{matrix} xF(x,y)=1+xf(x,y)=1+(1+y)k1+(1y)k2+(y)k3+yk4yF(x,y)=yf(x,y)=(1+x)k1+(x)k2+(1x)k3+xk4xG(x,y)=xg(x,y)=(1+y)k5+(1y)k6+(y)k7+yk8yG(x,y)=1+yg(x,y)=1+(1+x)k5+(x)k6+(1x)k7+xk8
带入式(16)得到雅可比矩阵,而残差为
r ( x , y ) = [ F ( x , y ) G ( x , y ) ] = [ x + ( 1 − x − y + x y ) ∗ k 1 + ( x − x y ) ∗ k 2 + ( y − x y ) ∗ k 3 + x y ∗ k 4 − x ′ y + ( 1 − x − y + x y ) ∗ k 5 + ( x − x y ) ∗ k 6 + ( y − x y ) ∗ k 7 + x y ∗ k 8 − y ′ ] r(x,y)=\begin{bmatrix} F(x,y) \\ G(x,y) \end{bmatrix} = \begin{bmatrix} x+(1-x-y+xy)*k_1+(x-xy)*k_2+(y-xy)*k_3+xy*k_4-x' \\ y+(1-x-y+xy)*k_5+(x-xy)*k_6+(y-xy)*k_7+xy*k_8-y' \end{bmatrix} r(x,y)=[F(x,y)G(x,y)]=[x+1xy+xy)k1+(xxy)k2+(yxy)k3+xyk4xy+1xy+xy)k5+(xxy)k6+(yxy)k7+xyk8y]
假设待定参数 x x x, y y y的初始值就是有畸变的值,即初始值为 x = x ′ x=x' x=x, y = y ′ y=y' y=y。将 x x x, y y y的初始值带入雅可比矩阵,以及残差矩阵中,得到式(15)的增量值,然后利用如式(11)迭代去畸变。

4. c++实现

利用Eigen矩阵库辅助完成去畸变的c++实现

完整工程:
csdn: 三维重建中高斯牛顿法求解去畸变坐标
github:DistortionRemoval

int RemoveDistortion(double &distX, double &distY, double srcX, double srcY, double *Kx, double *Ky)
{
	// 去畸变坐标的初始值设置为有畸变的坐标
	distX = srcX;
	distY = srcY;

	int iMaxItetNum = 5;
	int iIterCnt = 0;
	Eigen::MatrixXd delta;
	delta.setOnes(2, 1);

	// 迭代去畸变
	do{
		// 雅可比矩阵
		Eigen::Matrix2d Jacobi;
		Jacobi(0, 0) = 1 + (-1 + distY)*Kx[0]
			+ (1 - distY)*Kx[1]
			+ (-distY)*Kx[2]
			+ distY*Kx[3];
		Jacobi(0, 1) = (-1 + distX)*Kx[0]
			+ (-distX)*Kx[1]
			+ (1 - distX)*Kx[2]
			+ distX*Kx[3];
		Jacobi(1, 0) = (-1+distY)*Ky[0]
			+ (1 - distY)*Ky[1]
			+ (-distY)*Ky[2]
			+ distY*Ky[3];
		Jacobi(1, 1) = 1 + (-1 + distX)*Ky[0]
			+ (-distX)*Ky[1]
			+ (1 - distX)*Ky[2]
			+ distX*Ky[3];

		// 残差矩阵
		Eigen::MatrixXd R;
		R.setZero(2, 1);
		R(0, 0) = distX + (1 - distX - distY + distX*distY)*Kx[0]
			+ (distX-distX*distY)*Kx[1]
			+ (distY-distX*distY)*Kx[2]
			+ distX*distY*Kx[3]
			- srcX;
		R(1, 0) = distY + (1 - distX - distY + distX*distY)*Ky[0]
			+ (distX - distX*distY)*Ky[1]
			+ (distY - distX*distY)*Ky[2]
			+ distX*distY*Ky[3]
			- srcY;

		// 求解增量
		delta = (Jacobi.transpose() * Jacobi).inverse();
		delta *= Jacobi.transpose() * R *(-1);

		// 下一次迭代
		iIterCnt++;
		distX = distX + delta(0, 0);
		distY = distY + delta(1, 0);
	} while (iIterCnt < iMaxItetNum && (abs(delta(0, 0)) > 1e-3 || abs(delta(1, 0)) > 1e-3));

	return 0;
}
  • 7
    点赞
  • 15
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

leaf_csdn

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值