魚眼相機模型
??最近涉及魚眼相機模型、標定使用等,作為記錄,更新很久不曾更新的博客。
文章目錄
- 魚眼相機模型
- 1 相機成像
- 2 魚眼模型
- 3 畸變
- 3.1 適用針孔和MEI
- 3.2 Kannala-Brandt魚眼模型
- 4 代碼實現
1 相機成像
針孔相機:所有光線從一個孔(光心)透過,入射角θ\thetaθ = 出射角θd\theta_{d}θd?。0-180°的光線匯聚的圖像是無窮大的,所以針孔相機的視場角一般都很小。
魚眼相機:類似于凸透鏡成像,光線被聚集,入射角θ\thetaθ > 出射角θd\theta_{d}θd?。光線匯聚的圖像變小,所以魚眼相機的視場角一般可以達到18-270°。
2 魚眼模型
常見模型,注意,這里的θ\thetaθ是入射角!!θd\theta_{d}θd?才是出射角。
VINS
、AVP-SLAM
中采用的MEI模型--------
注意,常規魚眼模型的去畸變和針孔相機不同,可以見
opencv
中解釋;但是MEI模型經過變換后,可以直接套用針孔相機模型
3 畸變
畸變包括徑向畸變(Radial Distortion)和切向畸變(Tangential Distortion)
魚眼相機本質是利用了相機的畸變獲取無窮遠處的投影,主要是徑向畸變
3.1 適用針孔和MEI
首先來看下去畸變的本質,如圖所示,一共是四步
① 相機坐標系下某一點,是投影到光心矢量射線(相機成像原理),與圖像產生交點。歸一化這個坐標(如果再乘以焦距就是圖像坐標系上的坐標了),獲取畸變的
xy
。(這里為什么不乘以f呢,本質是矯正這一條投影到光心的矢量射線,沒有本質區別,歸一化計算更簡單)
② 計算成像半徑
r
(相機成像半徑r理論為r=f*tan(θd)
,3.2中有提到,也有圖)
③ 基于畸變參數,計算去畸變后的
xy
,此時,該點再圖像坐標系中的位置被矯正
④ 然后基于去畸變后的
xy
再變換到像素坐標系下,就可以獲取一個矯正的像素坐標
但是實際上,我們只知道像素坐標,而非相機系坐標!所以實際中將像素坐標反變換到相機坐標系(歸一化),然后就可以按照這里的去畸變流程處理了。
? opencv中的MEI描述
3.2 Kannala-Brandt魚眼模型
參考opencv,注意,通用模型不是上面哪些等距模型,和哪些完全沒關系
相機系
Xc=RX+tXc = RX + t Xc=RX+t
把相機系坐標單獨取出來
x=Xc1y=Xc2z=Xc3x = Xc_1\\ y = Xc_2\\ z = Xc_3 x=Xc1?y=Xc2?z=Xc3?
歸一化,計算成像半徑、夾角
a=xzandb=yzr2=a2+b2θ=arctan?(r/1)a = \frac{x}{z} \quad \text{and} \quad b = \frac{y}{z} \quad r^2 = a^2 + b^2 \quad \theta = \arctan(r/1) a=zx?andb=zy?r2=a2+b2θ=arctan(r/1)
去畸變,注意這里的θdr\frac{\theta_d}{r}rθd??實際代碼是rdr\frac{r_d}{r}rrd??獲取的一個比例關系,
opencv
給出的公式有點誤導,可以參考原始論文(成像半徑rd=f?tan(θd)≈f?θdr_{d} = f*tan(\theta_{d}) ≈ f* \theta_{d}rd?=f?tan(θd?)≈f?θd?,歸一化,取f=1
,tanx
在x
接近0時候約等于x
)
θd=θ(1+k1θ2+k2θ4+k3θ6+k4θ8)x′=(θdr)ay′=(θdr)b\theta_d = \theta (1 + k_1 \theta^2 + k_2 \theta^4 + k_3 \theta^6 + k_4 \theta^8) \\ x' = \left(\frac{\theta_d}{r}\right) a \\ y' = \left(\frac{\theta_d}{r}\right) b θd?=θ(1+k1?θ2+k2?θ4+k3?θ6+k4?θ8)x′=(rθd??)ay′=(rθd??)b
獲取去畸變后的像素坐標(
α
是偏斜系數,默認為0)
u=fx(x′+αy′)+cxv=fyy′+cyu = f_x (x' + \alpha y') + c_x \\ v = f_y y' + c_y u=fx?(x′+αy′)+cx?v=fy?y′+cy?
注:通過上述模型,也就是棋盤格標定得到的去畸變圖像,相對于原圖,會小很多!距離中心越遠的區域,拉伸會很嚴重,校正后會被切除
4 代碼實現
可以參考opencv中映射矩陣來實現
bool UnDistortMap()
{if(is_init){return true;}// 畸變映射,每一張圖像的畸變映射是一致的cv::fisheye::initUndistortRectifyMap(mK, mD, cv::Matx33d::eye(), mK,cv::Size(Width, Height), CV_16SC2, m_undistortMapX, m_undistortMapY);// 通過調整cx,cy來增大去畸變后的視野// cv::fisheye::initUndistortRectifyMap(mK, mD, cv::Matx33d::eye(), mK,// cv::Size(mK.at<double>(0,2), mK.at<double>(1,2)), CV_16SC2, // m_undistortMapX, m_undistortMapY); // 或者直接把fxfy調小,縮小相機焦距,視野變大了(分辨率dx不變) if (m_undistortMapX.empty() || m_undistortMapY.empty()) {std::cerr << "Failed to compute undistort maps!" << std::endl;return false;}else{}is_init = true;return true;
}bool undistortImage(const cv::Mat& src, cv::Mat& dst)
{if(!is_init)return false;cv::remap(src, dst, m_undistortMapX, m_undistortMapY, cv::INTER_LINEAR); // 去畸變return true;
}
Computes undistortion and rectification maps for image transform by cv::remap(). If D is empty zero distortion is used, if R or P is empty identity matrixes are used.Parameters:
K – Camera matrix \f$K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{_1}.
D – Input vector of distortion coefficients k_1, k_2, k_3, k_4).
R – Rectification transformation in the object space: 3x3 1-channel, or vector: 3x1/1x3 1-channel or 1x1 3-channel
P – New camera matrix (3x3) or new projection matrix (3x4)
size – Undistorted image size.
m1type – Type of the first output map that can be CV_32FC1 or CV_16SC2 . See convertMaps() for details.
map1 – The first output map.
map2 – The second output map.