图像点畸变矫正

Posted by     "LETTER" on Friday, November 14, 2025

畸变是发生在世界点通过透镜投影到相机坐标系这个过程中的,所以去畸变操作是在相机坐标系下进行的,一般去畸变流程为:

  • 像素点通过内参矩阵转换到归一化相机平面,基本相机模型为:
K=[fx0cx0fycy001]PnPn=K1Puv \begin{matrix} K = \begin{bmatrix} f_x&0&c_x\\0&f_y&c_y\\0&0&1 \end{bmatrix}P_n\\ P_n = K^{-1} P_{uv} \end{matrix}
  • 在归一化相机平面通过畸变模型去畸变。

Radial-Tangential

畸变矫正实现

[xy]=[x(1+K1r2+K2r4+K3r6)(1+K4r2+K5r4+K6r6)+2P1xy+P2(r2+2x2)+S1r2+S3r4y(1+K1r2+K2r4+K3r6)(1+K4r2+K5r4+K6r6)+2P2xy+P1(r2+2y2)+S2r2+S4r4] \begin{bmatrix} x' \\ y' \end{bmatrix} = \left[ \begin{array}{l} x \frac{(1+K_1r^2+K_2r^4+K_3r^6)}{(1+K_4r^2+K_5r^4+K_6r^6)} + 2P_1xy + P_2(r^2+2x^2) + S_1r^2+S_3r^4 \\ y \frac{(1+K_1r^2+K_2r^4+K_3r^6)}{(1+K_4r^2+K_5r^4+K_6r^6)} + 2P_2xy + P_1(r^2+2y^2) + S_2r^2+S_4r^4 \end{array} \right]

上式为opencv支持的对归一化平面上的点进行畸变校正的过程,包含三种畸变:

  • 径向畸变:[k1 k2 k3]基础的径向畸变多项式系数,[k4 k5 k6]高阶径向畸变多项式系数,一般用于广角镜头
  • 切向畸变:[p1 p2]主要的切向畸变系数,[ $\tau_x$ $\tau_y$]是为兼容内部模型而引入的切向畸变系数,有时也被称为倾斜畸变(Tilting Distortion),它们提供了对切向畸变更精细的描述,尤其是在需要高精度标定的场合,该模型也被称为薄棱镜畸变模型的一部分,但其数学形式与s系数不同。
  • 薄棱镜畸变:[s1 s2 s3 s4]

一般支持参数类型为

  • [k1 k2 p1 p2]
  • [k1 k2 p1 p2 k3]
  • [k1 k2 p1 p2 k3 k4 k5 k6]
  • [k1 k2 p1 p2 k3 k4 k5 k6 s1 s2 s3 s4]
  • [k1 k2 p1 p2 k3 k4 k5 k6 s1 s2 s3 s4 $\tau_x$ $\tau_y$]

Equidistant

Kannala-Brandt, Radially Symmetric Model, opencv中的fisheye, kalibr中的 pinhole + equidistant 都是指该模型

畸变矫正实现

r2=x2+y2θ=arctan(r)θd=θ(k0+k1θ2+k2θ4+k3θ6+k4θ8)x=θdrx, y=θdry \begin{matrix} r^2 = x^2 + y^2\\ \theta = arctan(r)\\ \theta _d = \theta(k_0 + k_1 \theta^2 + k_2 \theta^4 + k_3 \theta^6 + k_4 \theta^8)\\ x'=\frac{\theta_d}{r}x, \ y'=\frac{\theta_d}{r}y \end{matrix}

代码

CamBase

测试结果

  • 内置算法

    ============================================================
    Radtan Model Test
    ============================================================
    Radtan (Internal) Correctness Test:
    Original Point:      (0.3, -0.2)
    Distorted Pixel:     (772.204, 271.3)
    Final Undistorted:   (0.3, -0.2)
    Round-trip Error:    2.271766e-08
    [SUCCESS] Low error.
    
    Radtan (Internal) Speed Test (100000 points):
    distort() time:   0.295156 ms
    undistort() time: 2.670738 ms
    
    ============================================================
    Equi (Fisheye) Model Test
    ============================================================
    Equi (Internal) Correctness Test:
    Original Point:      (0.300000, -0.200000)
    Distorted Pixel:     (732.269954, 298.525131)
    Final Undistorted:   (0.300000, -0.200000)
    Round-trip Error:    1.494683e-16
    [SUCCESS] Low error.
    
    Equi (Internal) Speed Test (100000 points):
    distort() time:   1.358781 ms
    undistort() time: 7.232002 ms
    
  • opencv

    ============================================================
    Radtan Model Test
    ============================================================
    Radtan (OpenCV) Correctness Test:
    Original Point:      (0.3, -0.2)
    Distorted Pixel:     (772.204, 271.3)
    Final Undistorted:   (0.3, -0.2)
    Round-trip Error:    2.271766e-08
    [SUCCESS] Low error.
    
    Radtan (OpenCV) Speed Test (100000 points):
    distort() time:   0.297319 ms
    undistort() time: 54.243528 ms
    
    ============================================================
    Equi (Fisheye) Model Test
    ============================================================
    Equi (OpenCV) Correctness Test:
    Original Point:      (0.300000, -0.200000)
    Distorted Pixel:     (732.269954, 298.525131)
    Final Undistorted:   (0.300000, -0.200000)
    Round-trip Error:    1.494683e-16
    [SUCCESS] Low error.
    
    Equi (OpenCV) Speed Test (100000 points):
    distort() time:   1.251700 ms
    undistort() time: 37.757270 ms