本文参考文献:Lens distortion correction using ideal image coordinates;但是最小化方法不同,本文采用了非线性优化,而且原文非线性优化方程似乎不太对

基本步骤

步骤一:提取mark点

提取mark点坐标,尽量让图像中心对齐某一个mark点中心,视野布满mark点,这一步不多介绍

步骤二:构建标准mark点

基本方法:以离图像中心最近的一个mark点为中心,选择其领域的8个mark点,计算平均角度,并以中心点4领域mark点距离平均值为Gap,构建理想mark点,此时理想点应该是等间距及绝对平行和垂直的

步骤三: 初始化畸变参数及图像中心

本文计算像素当量,是利用步骤2中Gap和物理距离直接计算的,而且没有考虑角度这个参数,原文不是很理解,有懂的大家可以一起交流
畸变参数初始化参见:a flexible new technique for camera calibration

步骤四: 非线性优化

畸变模型如下所示

畸变模型是建立在无畸变坐标系下面的,就是用无畸变求解畸变坐标下的坐标是正向解,反之是反向解,反向解会比较麻烦,但是原文最优化方程中确实畸变点矫正过后的点跟理想点的欧式距离,这个在编程的时候就会比较麻烦,如果修改为理想点经畸变后的畸变点跟实际畸变点欧式距离,就会比较容易实现

最优化代价函数如下所示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 计算误差向量
int len = pt.ptDistor.size();
for (int i = 0; i < len; i++)
{
double xu = (pt.ptIdeal[i].x - x0) * s;
double yu = (pt.ptIdeal[i].y - y0) * s;
double r2 = xu * xu + yu * yu;
double xd = xu * (1 + r2 * k1 + r2 * r2 * k2);
double yd = yu * (1 + r2 * k1 + r2 * r2 * k2);


double xd2 = xd / s + x0;
double yd2 = yd / s + y0;
fvec[i] = (pt.ptDistor[i].x - xd2) * (pt.ptDistor[i].x - xd2) + (pt.ptDistor[i].y - yd2) * (pt.ptDistor[i].y - yd2);
}

实验结果

1
2
3
4
5
6
7
8
9

单幅标定图像标定远心镜头结果:
单像素精度:0.0185945mm / pixcel
畸变中心:[2214.1,1615.39]
畸变参数:[K1=-8.11779e-007, k2=-4.63523e-011]

矫正前最大误差:5.02904像素; RMS:0.125305
矫正后最大误差:0.595392像素; RMS:0.0222714

从结果来看,畸变矫正后最大误差0.6像素,精度还算ok,

畸变矫正:生成map矩阵

畸变矫正,是需要用到双线性插值的,这个操作会消耗很多资源,我们可以将畸变矫正后的坐标计算出来,保存下来,生成两个map矩阵和索引矩阵,类似于opencv remap函数,同时为了避免浮点操作,将数据放大成整数,这样线性插值部分都编程了整数操作,也会加快速度,实验表明采用这种方法,单幅3840*2748的灰度图像在(i5 7500 15w,无GPU)的笔记本上,控制在30ms,已经达到了实时模式