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)位置。