相機畸變校準

1. 前言

前言,關於相機的畸變模型及其推導,很多文章都已經寫得很詳細了,我這裏只總結結論,把重點放在理解以及使用上。這篇文章總結了徑向切向畸變,魚眼畸變,FOV畸變;同時,還根據徑向切向畸變的模型,以Euroc數據集爲例,提供了畸變矯正的Matlab和C++代碼示例。

2. 針孔模型(pinhole model)

針孔相機模型(即直線投影模型,是相機在理想情況下的投影模型)是消費類相機中最常見的相機模型。在此模型中,圖像通過透視投影映射到平面上。當相機座標系(原點在相機光心,向前爲Z,向右爲X,向下爲Y)下的一個三維空間點(Xc,Yc,Zc)(X_c, Y_c, Z_c)通過針孔相機模型投影得到圖像座標系(圖像的左上角爲座標原點,向右爲x,向下爲y,單位爲像素)下的一個像素點(u,v)(u, v)時,它們的對應關係如下:
{x=fxXcZc+cx=fxx+cxy=fyYcZc+cy=fyy+cy(1.1)\left\{ \begin{aligned} x = f_x \frac{X_c}{Z_c} + c_x = f_x \cdot x + c_x \\ y = f_y \frac{Y_c}{Z_c} + c_y = f_y \cdot y + c_y \end{aligned} \right. \tag{1.1}
其中,x=XcZc,y=YcZcx = \frac{X_c}{Z_c}, y = \frac{Y_c}{Z_c}是歸一化的座標(沒有單位),上式子也可寫成齊次座標的形式:
[uv1]=1Zc[fx0cx0fycy001][XcYcZc](1.2) \left[\begin{matrix} u \\ v \\ 1 \end{matrix}\right] = \frac{1}{Z_c} \left[\begin{matrix} f_x & 0 & c_x \\0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} X_c \\ Y_c \\ Z_c \end{matrix}\right] \tag{1.2}
其中,fx,fy,cx,cyf_x, f_y, c_x, c_y 爲相機內參(單位:像素),上面模型的推導與相機內參的具體含義這裏不過多展開,詳情請見高博的《視覺SLAM十四講》,或者鏈接:SLAM之相機標定,需要說明的是,該鏈接中講的相機標定和畸變部分與高博的那本書一致,它同時還介紹了基於ROS的相機內參標定過程,以及校準的代碼。但是,那裏面只提到徑向切向畸變,校準出來幾個畸變參數也沒有詳細說明,而且代碼寫的有點小問題:(他寫的顯然是C++的代碼,但是下面那兩行卻實matlab的語法,而且“^”在C++中的含義是異或操作)

double x_distorted = x*(1+k1*r^2+k2*r^4)+2*p1*x*y+p2*(r^2+2*x^2);
double y_distorted = y*(1+k1*r^2+k2*r^4)+2*p2*x*y+p1*(r^2+2*y^2);

因此,我想在此基礎上做一點補充。

3. 針孔模型+徑向切向畸變(rectilinear projection distortion)

{xdistorted=x(1+k1r2+k2r4+k3r6)+2p1xy+p2(r2+2x2)ydistorted=y(1+k1r2+k2r4+k3r6)+2p2xy+p1(r2+2y2)(2.1)\left\{ \begin{aligned} x_{distorted} = x(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + 2p_1 xy + p_2(r^2 + 2x^2) \\ y_{distorted} = y(1 + k_1 r^2 + k_2 r^4 + k_3 r^6) + 2p_2 xy + p_1(r^2 + 2y^2) \end{aligned} \right. \tag{2.1}
其中,式(2.1)中的x,yx, y與式(1.1)(1.1)中的x,yx, y含義相同,都是歸一化後的座標,且 r=(x2+y2)r = \sqrt{(x^2 +y^2)} 。可以得到校準後的像素位置(udistorted,vdistorted)(u_{distorted}, v_{distorted})
{udistorted=fxxdistorted+cxvdistorted=fyydistorted+cy(2.2)\left\{ \begin{aligned} u_{distorted} = f_x x_{distorted} + c_x \\ v_{distorted} = f_y y_{distorted} + c_y \end{aligned} \right.\tag{2.2}

寫成矩陣的形式有:
[udistortedvdistorted1]=[fx0cx0fycy001][xdistortedydistorted1](2.3) \left[\begin{matrix} u_{distorted} \\ v_{distorted} \\ 1 \end{matrix}\right] = \left[\begin{matrix} f_x & 0 & c_x \\0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_{distorted} \\ y_{distorted} \\ 1 \end{matrix}\right] \tag{2.3}
利用ROS的 MonocularCalibration 校準得到兩個參數文件,這是同一個相機參數的兩種不同文件格式:一個ini格式和一個yaml格式的文件(yaml格式的文件是用於OpenCV校準程序),在參數文件中,它們的含義都比較明顯:

image_width: 640
image_height: 480
camera_name: narrow_stereo
camera_matrix:
rows: 3
cols: 3
data: [634.706989, 0.000000, 323.354857, 0.000000, 634.489915, 213.107721, 0.000000, 0.000000, 1.000000]
distortion_model: plumb_bob
distortion_coefficients:
rows: 1
cols: 5
data: [-0.068953, 0.342004, -0.002181, 0.005728, 0.000000]
rectification_matrix:
rows: 3
cols: 3
data: [1.000000, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000, 0.000000, 0.000000, 1.000000]
projection_matrix:
rows: 3
cols: 4
data: [650.866821, 0.000000, 325.423266, 0.000000, 0.000000, 650.506226, 212.983124, 0.000000, 0.000000, 0.000000, 1.000000, 0.000000]

上面的畸變模型參數值"plumb_bob"表示該相機的畸變模型是:徑向和切向變形的5參數多項式逼近。而 distortion_coefficients 中的五個參數肯定是式(2.1)中 k1,k2,k3,p1,p2k_1, k_2, k_3, p_1, p_2這五個,但它們的對應關係是怎麼樣的呢。根據參考 https://www.ros.org/reps/rep-0104.html#plumbbob 中的文獻[2]
Plumb Bob
雖然其中的字符定義和我們習慣性用的不太一致,但是二者含義是一樣的。從上面圖中可以看出,畸變參數中,第1,2,5個參數對應的是式(2.1)中的k1,k2,k3k_1,k_2,k_3,第3,4個參數對應的是式(2.1)中的p1,p2p_1, p_2。因此我們可以知道:distortion_coefficients中的五個參數從前到後分別對應的是:k1,k2,p1,p2,k3k_1, k_2, p_1, p_2, k_3
說句題外話,將文獻[2]中的字符翻譯成和本文中的字符一致,可得到如式(2.3)所示的對應關係,其中α\alpha定義了x和y像素軸之間的角度,但很多文章貌似都沒有提起這一項畸變,不知道是爲什麼。
[udistortedvdistorted1]=[fxαfxcx0fycy001][xdistortedydistorted1](2.3) \left[\begin{matrix} u_{distorted} \\ v_{distorted} \\ 1 \end{matrix}\right] = \left[\begin{matrix} f_x & \alpha f_x & c_x \\0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_{distorted} \\ y_{distorted} \\ 1 \end{matrix}\right] \tag{2.3}

4. 徑向切向畸變校準實例

根據上述畸變模型的含義,現在嘗試根據它來校準畸變後的圖像。我從Euroc數據集中,下載了示例圖片數據以及對應的參數文件,其中參數文件內容如下(該數據集的校準文件格式與上面提到的ROS校準工具生成的格式不太一致,但該有的參數都有,其中的校準參數中沒有k3k_3參數):

# General sensor definitions.
sensor_type: camera
comment: VI-Sensor cam0 (MT9M034)

# Sensor extrinsics wrt. the body-frame.
T_BS:
cols: 4
rows: 4
data: [0.0148655429818, -0.999880929698, 0.00414029679422, -0.0216401454975,
0.999557249008, 0.0149672133247, 0.025715529948, -0.064676986768,
-0.0257744366974, 0.00375618835797, 0.999660727178, 0.00981073058949,
0.0, 0.0, 0.0, 1.0]

# Camera specific definitions.
rate_hz: 20
resolution: [752, 480]
camera_model: pinhole
intrinsics: [458.654, 457.296, 367.215, 248.375] #fu, fv, cu, cv
distortion_model: radial-tangential
distortion_coefficients: [-0.28340811, 0.07395907, 0.00019359, 1.76187114e-05]

根據上述參數,對其中的畸變圖像進行校準,基於matlab的校準代碼如下:

close all; clear all; clc
img1 = imread('1403638225195097088.png');
intrinsic.fx = 458.654; intrinsic.fy = 457.296;
intrinsic.cx = 367.215; intrinsic.cy = 248.375;
intrinsic.k1 = -0.28340811; intrinsic.k2 = 0.07395907; intrinsic.k3 = 0;
intrinsic.p1 = 0.00019359; intrinsic.p2 = 1.76187114e-05;
img0 = calibration(img1, intrinsic, 1);

上面代碼中calibration函數內容如下所示:

function [image_undistorted] = calibration(image_distorted, intrinsic, is_show)
%calibration 用於根據相機內參,對圖像進行校準
%INPUT----------------------------------------
%   image_distorted : 輸入(失真)圖像矩陣;
%   intrinsic : 相機內參;
%   is_show : 是否顯示校準前後的圖像(默認爲true);
%OUTPUT---------------------------------------   
%   image_undistorted : 輸出的校準後的圖像矩陣;

if nargin <= 2
    is_show = 1;
end

fx = intrinsic.fx; fy = intrinsic.fy;  % x<-->u; y<-->v
cx = intrinsic.cx; cy = intrinsic.cy;
k1 = intrinsic.k1; k2 = intrinsic.k2; k3 = intrinsic.k3;
p1 = intrinsic.p1; p2 = intrinsic.p2;
image_undistorted = image_distorted;

[h, w] = size(image_distorted);
for v = 1 : h
    for u = 1 : w
        x = (u - cx) / fx;
        y = (v - cy) / fy;
        r = sqrt(x*x + y*y);
        x_d = x*(1+k1*r*r + k2*r*r*r*r + k3*r*r*r*r*r*r)+ 2*p1*x*y + p2*(r*r + 2*x*x);
        y_d = y*(1+k1*r*r + k2*r*r*r*r + k3*r*r*r*r*r*r)+ 2*p2*x*y + p1*(r*r + 2*y*y);
        u_d = fx*x_d+cx;
        v_d = fy*y_d+cy;
        if u_d >=1 && u_d <= w && v_d >=1 && v_d <= h
            image_undistorted(v, u) = image_distorted(floor(v_d), floor(u_d));
        else
            image_undistorted(v, u) = 0;
        end
    end
end

if is_show
    figure('Name', '校準前')
    imshow(image_distorted);
    figure('Name', '校準後')
    imshow(image_undistorted);
end
end

基於C++的校準代碼如下(只需將 SLAM之相機標定 中有問題的兩行代碼改過來就能實現校準的功能了):
使用方法:生成的可執行文件名 圖片路徑

#include <opencv2/opencv.hpp>

int main(int argc, char **argv) {

	if (argc < 2)
	{
		std::cout << "Usage: exe_name image_name \n";
		return -1;
	}
	std::string image_file(argv[1]); // 請確保路徑正確

	double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;  // 畸變參數
	double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;  // 內參

	cv::Mat image = cv::imread(image_file, 0);   // 圖像是灰度圖,CV_8UC1
	int rows = image.rows, cols = image.cols;
	cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1);   // 去畸變以後的圖

	// 計算去畸變後圖像的內容
	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 r = sqrt(x*x + y*y);

			double x_distorted = x * (1 + k1 * r*r + k2 * r*r*r*r) + 2 * p1*x*y + p2 * (r*r + 2*x*x);
			double y_distorted = y * (1 + k1 * r*r + k2 * r*r*r*r) + 2 * p2*x*y + p1 * (r*r + 2*y*y);
			u_distorted = fx * x_distorted + cx;
			v_distorted = fy * y_distorted + 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;
			}
		}

	// 校準前圖像:
	cv::imshow("圖像矯正前", image);
	// 校準後圖像
	cv::imshow("圖像矯正後", image_undistort);
	cv::waitKey();

	return 0;
}

校準前後的效果如圖所示:

5. 針孔模型+魚眼畸變(fisheye distortion)

魚眼相機模型是用於寬廣視場相機的相機模型。因爲當視野接近180度時,針孔相機模型無法對圖像投影進行建模,所以需要該模型:
{r=x2+y2θ=atan2((Xc2+Yc2),Zc)=atan2(r,1)=arctan(r)θd=θ(1+k1θ2+k2θ4+k3θ6+k4θ8)xd=θdrxyd=θdry(4.1)\left\{ \begin{aligned} r &= \sqrt{x^2 + y^2} \\ \theta &= atan2(\sqrt{(X_c^2 + Y_c^2)}, Z_c) = atan2(r, 1) = arctan(r) \\ \\ \theta_d &= \theta(1 + k_1 \theta^2 + k_2 \theta^4 + k_3 \theta^6 + k_4 \theta^8) \\ x_d &= \frac{\theta_d}{r} \cdot x \\ y_d &= \frac{\theta_d}{r} \cdot y \end{aligned} \right. \tag{4.1}

將矯正後的歸一化座標轉換回像素座標:
{ud=fx(xd+αyd)+cxvd=fyyd+cy(4.2)\left\{ \begin{aligned} u_d &= f_x ( x_d + \alpha y_d) + c_x \\ v_d &= f_y \cdot y_d + c_y \end{aligned} \right. \tag{4.2}

寫成矩陣的形式有:
[udvd1]=[fxαfxcx0fycy001][xdyd1](4.3) \left[\begin{matrix} u_{d} \\ v_{d} \\ 1 \end{matrix}\right] = \left[\begin{matrix} f_x & \alpha f_x & c_x \\0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_{d} \\ y_{d} \\ 1 \end{matrix}\right] \tag{4.3}

6. 針孔模型+FOV畸變(FOV distortion)

這是具有較大徑向變形的相機模型(例如魚眼相機)的替代表示,其中圖像點和圖像中心點(principal point)之間的距離大致與相機座標系下的3維空間點和光軸之間的角度成比例。該模型首先在論文“Straight Lines Have to be Straight: Automatic Calibration and Removal of Distortion from Scenes of Structured Environments.”中提出。
FOV 畸變矯正模型:
{r=(x2+y2)rd=1ωarctan(2rtan(ω2))xd=rdrxcyd=rdryc(5.1)\left\{\begin{aligned} r &= \sqrt{(x^2 + y^2)} \\ r_d &= \frac{1}{\omega} arctan(2r \cdot tan(\frac{\omega}{2})) \\ x_d &= \frac{r_d}{r} \cdot x_c \\ y_d &= \frac{r_d}{r} \cdot y_c \end{aligned} \right. \tag{5.1}

其中ω\omega是FOV畸變係數,將矯正後的歸一化座標轉換回像素座標:
[udvd1]=[fx0cx0fycy001][xdyd1](5.2) \left[\begin{matrix} u_{d} \\ v_{d} \\ 1 \end{matrix}\right] = \left[\begin{matrix} f_x & 0 & c_x \\0 & f_y & c_y \\ 0 & 0 & 1 \end{matrix}\right] \left[\begin{matrix} x_{d} \\ y_{d} \\ 1 \end{matrix}\right] \tag{5.2}



參考:
https://blog.csdn.net/learning_tortosie/article/details/79901255
http://wiki.ros.org/camera_calibration/Tutorials/MonocularCalibration
https://docs.ros.org/api/sensor_msgs/html/distortion__models_8h_source.html#l00045
http://wiki.ros.org/camera_calibration_parsers

https://www.ros.org/reps/rep-0104.html#plumbbob
http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/parameters.html
https://cggos.github.io/computervision/camera-models.html
https://zhuanlan.zhihu.com/p/93822726

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章