世界坐标系中三维点 M = [ X , Y , Z ] T M=[X,Y,Z]^T M=[X,Y,Z]T 和 像素坐标系中二维点 m = [ u , v ] T m=[u,v]^T m=[u,v]T的关系为:
s m ~ = A [ R t ] M ~ s\tilde{m} = A [R \quad t] \tilde{M} sm~=A[Rt]M~
即(针孔相机模型)
s [ u v 1 ] = [ f x 0 c x 0 f y c y 0 0 1 ] [ r 11 r 12 r 13 t 1 r 21 r 22 r 23 t 2 r 31 r 32 r 33 t 3 ] [ X w Y w Z w 1 ] \begin{aligned} s\left[\begin{array}{c}u\\v\\1\end{array}\right] = \left[\begin{array}{ccc} f_x&0&c_x\\0&f_y&c_y\\0&0&1 \end{array}\right] \left[\begin{array}{cccc} r_{11}&r_{12}&r_{13}&t_1\\r_{21}&r_{22}&r_{23}&t_2\\r_{31}&r_{32}&r_{33}&t_3 \end{array}\right] \left[\begin{array}{c}X_w\\Y_w\\Z_w\\1\end{array}\right] \end{aligned} s⎣⎡uv1⎦⎤=⎣⎡fx000fy0cxcy1⎦⎤⎣⎡r11r21r31r12r22r32r13r23r33t1t2t3⎦⎤⎣⎢⎢⎡XwYwZw1⎦⎥⎥⎤
其中, s s s为缩放因子, A A A为相机的内参矩阵, [ R t ] [R \quad t] [Rt]为相机的外参矩阵, m ~ \tilde{m} m~和 M ~ \tilde{M} M~分别为 m m m和 M M M对应的齐次坐标。
相机将三维世界中的坐标点(单位:米)映射到二维图像平面(单位:像素)的过程能够用一个几何模型来描述,其中最简单的称为针孔相机模型 (pinhole camera model),其框架如下图所示。
[ X c Y c Z c ] = R [ X w Y w Z w ] + t = [ R t ] [ X w Y w Z w 1 ] \begin{aligned} \left[\begin{array}{c}X_c\\Y_c\\Z_c\end{array}\right] = R \left[\begin{array}{c}X_w\\Y_w\\Z_w\end{array}\right] + t = [R \quad t] \left[\begin{array}{c}X_w\\Y_w\\Z_w\\1\end{array}\right] \end{aligned} ⎣⎡XcYcZc⎦⎤=R⎣⎡XwYwZw⎦⎤+t=[Rt]⎣⎢⎢⎡XwYwZw1⎦⎥⎥⎤
根据三角形相似关系,有
Z c f = X c x = Y c y \frac{Z_c}{f} = \frac{X_c}{x} = \frac{Y_c}{y} fZc=xXc=yYc
整理,得
{ x = f ⋅ X c Z c y = f ⋅ Y c Z c \begin{cases} x = f \cdot \frac{X_c}{Z_c} \\[2ex] y = f \cdot \frac{Y_c}{Z_c} \end{cases} ⎩⎨⎧x=f⋅ZcXcy=f⋅ZcYc
像素坐标系和成像平面坐标系之间,相差一个缩放和平移,联合上式整理得
{ u = α ⋅ x + c x v = β ⋅ y + c y ⟹ { u = α f ⋅ X c Z c + c x v = β f ⋅ Y c Z c + c y \begin{cases} u = \alpha \cdot x + c_x \\[2ex] v = \beta \cdot y + c_y \end{cases} \quad \Longrightarrow \quad \begin{cases} u = \alpha f \cdot \frac{X_c}{Z_c} + c_x \\[2ex] v = \beta f \cdot \frac{Y_c }{Z_c} + c_y \end{cases} ⎩⎨⎧u=α⋅x+cxv=β⋅y+cy⟹⎩⎨⎧u=αf⋅ZcXc+cxv=βf⋅ZcYc+cy
或
{ u = 1 d x ⋅ x + c x v = 1 d y ⋅ y + c y ⟹ { u = f d x ⋅ X c Z c + c x v = f d y ⋅ Y c Z c + c y \begin{cases} u = \frac{1}{dx} \cdot x + c_x \\[2ex] v = \frac{1}{dy} \cdot y + c_y \end{cases} \quad \Longrightarrow \quad \begin{cases} u = \frac{f}{dx} \cdot \frac{X_c}{Z_c} + c_x \\[2ex] v = \frac{f}{dy} \cdot \frac{Y_c }{Z_c} + c_y \end{cases} ⎩⎨⎧u=dx1⋅x+cxv=dy1⋅y+cy⟹⎩⎨⎧u=dxf⋅ZcXc+cxv=dyf⋅ZcYc+cy
其中,
{ d x = W s e n s o r W i m a g e d y = H s e n s o r H i m a g e \begin{cases} dx = \frac{W_{sensor}}{W_{image}}\\[2ex] dy = \frac{H_{sensor}}{H_{image}} \end{cases} ⎩⎨⎧dx=WimageWsensordy=HimageHsensor
则
{ f x = f d x f y = f d y ⟹ { u = f x X c Z c + c x v = f y Y c Z c + c y \begin{cases} f_x = \frac{f}{dx}\\[2ex] f_y = \frac{f}{dy} \end{cases} \quad \Longrightarrow \quad \begin{cases} u = f_x \frac{X_c}{Z_c} + c_x \\[2ex] v = f_y \frac{Y_c }{Z_c} + c_y \end{cases} ⎩⎨⎧fx=dxffy=dyf⟹⎩⎨⎧u=fxZcXc+cxv=fyZcYc+cy
或
{ f n x = f W s e n s o r f n y = f H s e n s o r ⟹ { u = f n x W i m a g e X c Z c + c x v = f n y H i m a g e Y c Z c + c y \begin{cases} f_{nx} = \frac{f}{W_{sensor}}\\[2ex] f_{ny} = \frac{f}{H_{sensor}} \end{cases} \quad \Longrightarrow \quad \begin{cases} u = f_{nx} W_{image} \frac{X_c}{Z_c} + c_x \\[2ex] v = f_{ny} H_{image} \frac{Y_c }{Z_c} + c_y \end{cases} ⎩⎨⎧fnx=Wsensorffny=Hsensorf⟹⎩⎨⎧u=fnxWimageZcXc+cxv=fnyHimageZcYc+cy
其中,
最终,写成矩阵的形式为:
[ u v 1 ] = 1 Z c [ f x 0 c x 0 f y c y 0 0 1 ] [ X c Y c Z c ] \begin{aligned} \left[\begin{array}{c}u\\v\\1\end{array}\right] = \frac{1}{Z_c} \left[\begin{array}{ccc} f_x&0&c_x\\0&f_y&c_y\\0&0&1 \end{array}\right] \left[\begin{array}{c}X_c\\Y_c\\Z_c\end{array}\right] \end{aligned} ⎣⎡uv1⎦⎤=Zc1⎣⎡fx000fy0cxcy1⎦⎤⎣⎡XcYcZc⎦⎤
或
Z c [ u v 1 ] = [ f x 0 c x 0 f y c y 0 0 1 ] [ X c Y c Z c ] \begin{aligned} Z_c\left[\begin{array}{c}u\\v\\1\end{array}\right] = \left[\begin{array}{ccc} f_x&0&c_x\\0&f_y&c_y\\0&0&1 \end{array}\right] \left[\begin{array}{c}X_c\\Y_c\\Z_c\end{array}\right] \end{aligned} Zc⎣⎡uv1⎦⎤=⎣⎡fx000fy0cxcy1⎦⎤⎣⎡XcYcZc⎦⎤
透镜的畸变主要分为径向畸变和切向畸变。
径向畸变是由于透镜形状的制造工艺导致,且越向透镜边缘移动径向畸变越严重,实际情况中我们常用r=0处的泰勒级数展开的前几项来近似描述径向畸变,径向畸变后的归一化坐标为:
{ x d i s t o r t e d = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) y d i s t o r t e d = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) \begin{cases} x_{distorted} = x (1+k_1r^2+k_2r^4+k_3r^6)\\[2ex] y_{distorted} = y (1+k_1r^2+k_2r^4+k_3r^6) \end{cases} ⎩⎨⎧xdistorted=x(1+k1r2+k2r4+k3r6)ydistorted=y(1+k1r2+k2r4+k3r6)
切向畸变是由于透镜和CMOS或者CCD的安装位置误差导致,切向畸变需要两个额外的畸变参数来描述,切向畸变后的归一化坐标为:
{ x d i s t o r t e d = x + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) y d i s t o r t e d = y + 2 p 2 x y + p 1 ( r 2 + 2 y 2 ) \begin{cases} x_{distorted} = x + 2p_1xy + p_2(r^2+2x^2)\\[2ex] y_{distorted} = y + 2p_2xy + p_1(r^2+2y^2) \end{cases} ⎩⎨⎧xdistorted=x+2p1xy+p2(r2+2x2)ydistorted=y+2p2xy+p1(r2+2y2)
联合上式,整理得
{ x d i s t o r t e d = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) y d i s t o r t e d = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 2 x y + p 1 ( r 2 + 2 y 2 ) \begin{cases} x_{distorted} = x (1+k_1r^2+k_2r^4+k_3r^6) + 2p_1xy + p_2(r^2+2x^2)\\[2ex] y_{distorted} = y (1+k_1r^2+k_2r^4+k_3r^6) + 2p_2xy + p_1(r^2+2y^2) \end{cases} ⎩⎨⎧xdistorted=x(1+k1r2+k2r4+k3r6)+2p1xy+p2(r2+2x2)ydistorted=y(1+k1r2+k2r4+k3r6)+2p2xy+p1(r2+2y2)
其中, r 2 = x 2 + y 2 r^2 = x^2 + y^2 r2=x2+y2
综上,我们一共需要5个畸变参数 ( k 1 , k 2 , k 3 , p 1 , p 2 ) (k_1, k_2, k_3, p_1, p_2) (k1,k2,k3,p1,p2)来描述透镜畸变。
[图像]畸变校正详解
核心示例代码 (from here)
for (int v = 0; v < height; v++) {
for (int u = 0; u < width; u++) {
double u_distorted = 0, v_distorted = 0;
double x = (u-cx)/fx;
double y = (v-cy)/fy;
double x2 = x*x, y2 = y*y, xy = x*y, r2 = x2 + y2;
double x_radial = x * (1 + k1*r2 + k2*r2*r2);
double y_radial = y * (1 + k1*r2 + k2*r2*r2);
double x_tangential = 2*p1*xy + p2*(r2 + 2*x2);
double y_tangential = 2*p2*xy + p1*(r2 + 2*y2);
double xd = x_radial + x_tangential;
double yd = y_radial + y_tangential;
u_distorted = xd*fx + cx;
v_distorted = yd*fy + cy;
// 最近邻插值
if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < width && v_distorted < height)
img_dst(v, u) = (*this)((int) v_distorted, (int) u_distorted);
else
img_dst(v, u) = 0;
}
}