图像去畸变

现实生活中的图像总存在畸变。原则上来说,针孔透视相机应该将三维世界中的直线投影成直线,但是当我们使用广角和鱼眼镜头时,由于畸变的原因,直线在图像里看起来是扭曲的。如下图所示:

可以明显看到实际的柱子、箱子的直线边缘在图像中被扭曲成了曲线。这就是由相机畸变造成的。在这里,我们只考虑径向畸变和切向畸变,畸变模型是叠加在归一化平面(投影模型)上的。径向切向畸变公式合起来写如下:

其中,

  • $x_{distorted},y_{distorted}$表示畸变后的投影模型上的坐标

  • $x,y$表示畸变前的投影模型上的坐标

  • $r^2=x^2+y^2$

去畸变思路:构建一个空白的图像(去畸变后的图像),然后遍历空白图像的每个像素点,通过像素点$\rightarrow$归一化平面坐标$\rightarrow$畸变模型$\rightarrow$畸变图像上的像素坐标,从而得到了去畸变后的图像与畸变图像像素坐标之间对应关系,由此问题得解。

++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 计算去畸变后图像的内容
for (int v = 0; v < rows; v++)
for (int u = 0; u < cols; u++) {

double u_distorted = 0, v_distorted = 0;
//按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted)
double x=(u-cx)/fx;
double y=(v-cy)/fy;//归一化坐标
double r2=x*x+y*y;
double x_distorted=x*(1+k1*r2+k2*r2*r2)+2*p1*x*y+p2*(r2+2*x*x);
double y_distorted=y*(1+k1*r2+k2*r2*r2)+p1*(r2+2*y*y)+2*p2*x*y;
u_distorted=x_distorted*fx+cx;
v_distorted=y_distorted*fy+cy;

// 赋值 (最近邻插值)
if (u_distorted >= 0 && v_distorted >= 0 && u_distorted < cols && v_distorted < rows) {
image_undistort.at<uchar>(v, u) = image.at<uchar>((int) v_distorted, (int) u_distorted);
} else {
image_undistort.at<uchar>(v, u) = 0;
}
}

可以看到去畸变后,箱子和柱子边缘的线明显变直了: