自动驾驶apa中的鱼眼相机标定,图像去畸变。来来回回做了几次。先前对原理一直了解不够深入。最近集中研究了一下,分几篇文章分别介绍一下原理,实现代码。
(一)相机成象原理
在介绍鱼眼相机之前,先简单了解一下普通相机的成象原理。

复杂一点的成象图:

理想情况下,相机坐标系的点坐标和成象平面上的点坐标之间满足相似三角形的关系

小孔成象的原理参考:相机(Camera)成像原理详解_相机成像原理-CSDN博客 讲的非常详细。
(二)鱼眼相机结构
鱼眼相机相比单目相机,成象更复杂。先看一下鱼眼相机的结构:

图片来自:https://zhuanlan.zhihu.com/p/511284263
鱼眼镜头是由十几个不同的透镜组合而成的,在成像过程中,入射光线经过不同程度的折射,投影到尺寸有限的成像平面上,使得鱼眼镜头与普通镜头相比拥有更大的视野。
结构中前面的类似凸的镜头发生折射,使入射角减小,其余镜头相当于一个成像镜头。
鱼眼镜头设计的目的是要获取更大的视野,鱼眼镜头的视场角可以超过180,可达到180-270度。
(三)鱼眼相机模型成象原理

鱼眼相机模型成象原理
经过P点的入射光线没有透镜的话,本应交于相机成像平面的e点。然而,经过鱼眼相机的折射,光线会交于相机成像平面的d点,因此在成象图像整体上呈现出像素朝图像中心点聚集的态势。
去畸变的过程涉及到几个坐标系:

转换处理流程如下:
RT(外参) 畸变参数去畸变 相机模型
物理坐标 ----------------------------> 相机坐标 -------------------------------> 去畸变后的入射角----------->
相机内参
成象平面坐标------------------------->图像坐标
梳理整体流程

(四)鱼眼去畸变的流程
算法流程 |
---|
1. 首先,相机坐标系的点P,将其转化到归一化平面p,(Xc, Yc, Zc)=>(Xc / Zc, Yc/Zc, 1),入射角为![]() |
数学公式演算参考:

进一步说明一下,畸变模型Kannala-Brandt矫正的是入射角度,相机经过透镜的多层折射,原本成象点在e,经过非线性折射后对应的成象点在d.d对应的理想情况下的入射角为
d.如何推算出
d,这里需要用到畸变模型KB。
|-----------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| 容易困惑的点: | 注解 |
| 根据相似三角形: rd / r = xd / xc = yd / yc 但是往往网上给出的都是: | 这里涉及到相机模型: 这里 rd = f *
d, 其中rd是投影点到中心O点的距离。在归一化平面上f = 1, rd = f *
d =
d
|
| 入射角, 畸变矫正后为
d,然后满足三角形相似 | 对一个点,有多个入射角度。从坐标上看OP'连线,只有一点线段,夹角固定。入射角度修正后,貌似不经过p'点。如何有相似三角形的说法? 实际根据小孔成象,一个点有多条角度的光线透过小孔。
|
(五)代码展示相机坐标到图像坐标的转换
最后展示一段C++代码,实现相机坐标到图像坐标的转换:
cpp
// https://zhuanlan.zhihu.com/p/511284263
// https://github.com/WordZzzz/fisheye_calibration
void distortFishEye3dTo2d(Point3d& src3d, Point2d& dst2d, const cv::Mat& intrinsic, const cv::Mat& distortion, double apha=0){
const double fx=intrinsic.at<double>(0,0),fy=intrinsic.at<double>(1,1);
const double cx=intrinsic.at<double>(0,2),cy=intrinsic.at<double>(1,2);
const double k1=distortion.at<double>(0,0);
const double k2=distortion.at<double>(0,1);
const double k3=distortion.at<double>(0,2);
const double k4=distortion.at<double>(0,3);
if(src3d.z<=0)
{
dst2d.x=-1;
dst2d.y=-1;
return;
}
//转归一化平面
double a = src3d.x / src3d.z;
double b = src3d.y / src3d.z;
double r=a*a+b*b;
r = sqrt(r);
double theta = atan(r);
double theta_d=1*theta+k1*pow(theta,3)+k2*pow(theta,5)+k3*pow(theta,7)+k4*pow(theta,9);
double inv_r =1.0/r;
double cdist = theta_d * inv_r;
double xd=a*cdist;
double yd=b*cdist;
double u = fx*(xd + apha * yd)+cx;
double v = fy*yd+cy;
dst2d.x=u;
dst2d.y=v;
}
最后,感谢各位网友的分享。后续会继续分享标定和avm算法。
参考:
一文详解分析鱼眼相机投影成像模型和畸变模型 - feng..liu - 博客园
鱼眼相机成像原理与畸变校正算法详解-CSDN博客 数学公式推导参考
https://zhuanlan.zhihu.com/p/138585667