SLAM 学习笔记




相机成像模型

以下题目来自计算机视觉life从零开始一起学习SLAM系列

题目: 相机视场角比较小(比如手机摄像头)时,一般可以近似为针孔相机成像,三维世界中的直线成像也是直线。但是很多时候需要用到广角甚至鱼眼相机,此时会产生畸变,三维世界中的直线在图像里会弯曲。因此,需要做去畸变。 本题给定一张广角畸变图像,以及相机的内参,请完成图像去畸变过程。

框架链接:https://pan.baidu.com/s/17KNXoprrYmY87s_xcDYK_g 密码:z2f0

参考答案:

#include <opencv2/opencv.hpp>

using namespace std;
string image_file = "./test.png"; // 请确保路径正确

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

double k1 = -0.28340811, k2 = 0.07395907; // 畸变参数
double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;

cv::Mat image = cv::imread(image_file, CV_8UC1); // 图像是灰度图
int rows = image.rows, cols = image.cols;
cv::Mat image_undistort = cv::Mat(rows, cols, CV_8UC1); // 去畸变以后的图
cv::imshow("image distorted", image);
// 计算去畸变后图像的内容
for (int v = 0; v < rows; v++)
for (int u = 0; u < cols; u++) {

double u_distorted = 0, v_distorted = 0;
// 开始代码,注意(u,v)要先转化为归一化坐标

double x1 = (u-cx)/fx;
double y1 = (v-cy)/fy;
double r = sqrt(x1*x1 + y1*y1);

double x2 = x1*(1+k1*pow(r,2)+k2*pow(r,4));
double y2 = y1*(1+k1*pow(r,2)+k2*pow(r,4));

u_distorted = x2*fx + cx;
v_distorted = y2*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;
}
}

cv::imshow("image undistorted", image_undistort);
cv::waitKey();

return 0;
}

CMakeLists.txt:

cmake_minimum_required( VERSION 2.8 )
project( undistort )

set( CMAKE_CXX_FLAGS "-std=c++11" )

find_package( OpenCV REQUIRED )

include_directories( ${OpenCV_INCLUDE_DIRS} )

add_executable( undistort_image undistort_image.cpp )

target_link_libraries( undistort_image ${OpenCV_LIBS} )
讨论

投影顺序:

世界坐标系中的3D点->相机坐标系中的3D点->归一化平面(X/Z,Y/Z,1)->乘以内参矩阵得到像素坐标(u,v)。

( u v 1 ) = 1 Z ( f x 0 c x 0 f y c y 0 0 1 ) [ R t 0 T 1 ] ( x w y w z w 1 ) = 1 Z K T ( x w y w z w 1 ) \left(\begin{array}{l} u \\ v \\ 1 \end{array}\right)=\frac{1}{Z}\left(\begin{array}{ccc} f_{x} & 0 & c_{x} \\ 0 & f_{y} & c_{y} \\ 0 & 0 & 1 \end{array}\right)\left[\begin{array}{cc} \boldsymbol{R} & \boldsymbol{t} \\ \boldsymbol{0}^{T} & 1 \end{array}\right]\left(\begin{array}{c} x_{w} \\ y_{w} \\ z_{w} \\ 1 \end{array}\right)=\frac{1}{Z} \boldsymbol{K} T\left(\begin{array}{c} x_{w} \\ y_{w} \\ z_{w} \\ 1 \end{array}\right) ⎝⎛uv1⎠⎞=Z1⎝⎛fx000fy0cxcy1⎠⎞[R0Tt1]⎝⎜⎜⎛xwywzw1⎠⎟⎟⎞=Z1KT⎝⎜⎜⎛xwywzw1⎠⎟⎟⎞

畸变主要有径向畸变和切向畸变。

切向畸变切向畸变是由于透镜和CMOS或者CCD的安装位置误差导致。随着相机制造工艺的大大提升,这种情况很少出现了,我们一般也不考虑切向的畸变。

标定可以得到相机的所有畸变系数,用标定的畸变系数就能对畸变的图像进行去畸变。

去畸变公式:

x distorted = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) y distorted = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) r 2 = x 2 + y 2 \begin{array}{l} x_{\text {distorted }}=x\left(1+k_{1} r^{2}+k_{2} r^{4}+k_{3} r^{6}\right) \\ y_{\text {distorted }}=y\left(1+k_{1} r^{2}+k_{2} r^{4}+k_{3} r^{6}\right) \\ r^{2}=x^{2}+y^{2} \end{array} xdistorted =x(1+k1r2+k2r4+k3r6)ydistorted =y(1+k1r2+k2r4+k3r6)r2=x2+y2

课后题里面利用已有的去畸变图像,也就是假设已知x,y(不知道(x,y)处的像素值),然后带入右边式子,最后得到一个x_distorted, y_distorted的坐标,这个坐标对应的就是扭曲的图里的坐标,把这个坐标的像素值填入去畸变图像的(x,y)位置。