1.摄像机成像原理简述

成像的过程实质上是几个坐标系的转换。首先空间中的一点由 世界坐标系 转换到 摄像机坐标系 ,然后再将其投影到成像平面 ( 图像物理坐标系 ) ,最后再将成像平面上的数据转换到图像平面 ( 图像像素坐标系 ) 。

图像像素坐标系 (uOv坐标系) 下的无畸变坐标 (U, V),经过 经向畸变切向畸变 后落在了uOv坐标系(Ud, Vd) 上。即就是说,真实图像 imgR畸变图像 imgD 之间的关系为:imgR(U, V) = imgD(Ud, Vd)

opencv相机标定的畸变矩阵 相机畸变公式_归一化

2.成像畸变

2.1. 畸变数学模型

摄像头成像畸变的数学模型 (符合的对应关系有问题,可能会造成一些干扰,公式主要看后面推导的过程)

opencv相机标定的畸变矩阵 相机畸变公式_#include_02

2.2. 公式推导

公式推导:

opencv相机标定的畸变矩阵 相机畸变公式_opencv相机标定的畸变矩阵_03

3.畸变校正

3.1. 理论推导

我们已知的是畸变后的图像,要得到没有畸变的图像就要通过畸变模型推导其映射关系。 真实图像 imgR畸变图像 imgD 之间的关系为:imgR(U, V) = imgD(Ud, Vd) 。通过这个关系,找出所有的 imgR(U, V)(U, V) 映射到 (Ud, Vd) 中的 (Ud, Vd)往往不是整数 (U和V是整数,因为它是我们要组成图像的像素坐标位置,以这正常图像的坐标位置去求在畸变图像中的坐标位置,取出对应的像素值,这也是正常图像的像素值)。 但是畸变的像素往往不是整数,所以需要通过插值来进行求解,详细见博客

opencv相机标定的畸变矩阵 相机畸变公式_插值_04

代码实现
#include <opencv2/opencv.hpp>
#include <string>

using namespace std;

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

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

    // 本程序需要你自己实现去畸变部分的代码。尽管我们可以调用OpenCV的去畸变,但自己实现一遍有助于理解。
    // 畸变参数
    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;
            // TODO 按照公式,计算点(u,v)对应到畸变图像中的坐标(u_distorted, v_distorted) (~6 lines)


            // start your code here

	/*****先计算出归一化平面上的坐标****/
	double xNormal = (u-cx)/fx;
	double yNormal = (v-cy)/fy;
	/*****再计算距离归一化原点的距离***/
	double r = xNormal*xNormal + yNormal*yNormal;
	/*****计算去畸变的过程*****/
	double xDistort = xNormal * (1+k1*r+k2*r*r) + 2*p1*xNormal*yNormal+ p2*(r+2+xNormal*xNormal);
	double yDistort = yNormal *(1+k1*r+k2*r*r) + p1*(r+2*yNormal*yNormal) + 2*p2*xNormal*yNormal;
	/*****计算从归一化平面到像素平面的坐标***/
	u_distorted = xDistort * fx + cx;
	v_distorted = yDistort * fy + cy; 
	/****OVER*****/
          
            // end your code here


            // 赋值 (最近邻插值)
            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;
}

矫正前:

opencv相机标定的畸变矩阵 相机畸变公式_opencv相机标定的畸变矩阵_05

矫正后 :

opencv相机标定的畸变矩阵 相机畸变公式_opencv相机标定的畸变矩阵_06