文章目錄
1. 前言
前言,關於相機的畸變模型及其推導,很多文章都已經寫得很詳細了,我這裏只總結結論,把重點放在理解以及使用上。這篇文章總結了徑向切向畸變,魚眼畸變,FOV畸變;同時,還根據徑向切向畸變的模型,以Euroc數據集爲例,提供了畸變矯正的Matlab和C++代碼示例。
2. 針孔模型(pinhole model)
針孔相機模型(即直線投影模型,是相機在理想情況下的投影模型)是消費類相機中最常見的相機模型。在此模型中,圖像通過透視投影映射到平面上。當相機座標系(原點在相機光心,向前爲Z,向右爲X,向下爲Y)下的一個三維空間點通過針孔相機模型投影得到圖像座標系(圖像的左上角爲座標原點,向右爲x,向下爲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)
其中,式(2.1)中的與式中的含義相同,都是歸一化後的座標,且 。可以得到校準後的像素位置:
寫成矩陣的形式有:
利用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)中 這五個,但它們的對應關係是怎麼樣的呢。根據參考 https://www.ros.org/reps/rep-0104.html#plumbbob 中的文獻[2]:
雖然其中的字符定義和我們習慣性用的不太一致,但是二者含義是一樣的。從上面圖中可以看出,畸變參數中,第1,2,5個參數對應的是式(2.1)中的,第3,4個參數對應的是式(2.1)中的。因此我們可以知道:distortion_coefficients中的五個參數從前到後分別對應的是:。
說句題外話,將文獻[2]中的字符翻譯成和本文中的字符一致,可得到如式(2.3)所示的對應關係,其中定義了x和y像素軸之間的角度,但很多文章貌似都沒有提起這一項畸變,不知道是爲什麼。
4. 徑向切向畸變校準實例
根據上述畸變模型的含義,現在嘗試根據它來校準畸變後的圖像。我從Euroc數據集中,下載了示例圖片數據以及對應的參數文件,其中參數文件內容如下(該數據集的校準文件格式與上面提到的ROS校準工具生成的格式不太一致,但該有的參數都有,其中的校準參數中沒有參數):
# 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度時,針孔相機模型無法對圖像投影進行建模,所以需要該模型:
將矯正後的歸一化座標轉換回像素座標:
寫成矩陣的形式有:
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 畸變矯正模型:
其中是FOV畸變係數,將矯正後的歸一化座標轉換回像素座標:
參考:
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