天天看点

学习笔记 -- opencv图像去畸变法一: 使用 getOptimalNewCameraMatrix + initUndistortRectifyMap + remap 矫正图像法一 完整代码:法二:使用 undistort()法三: 手动实现参考

法一: 使用 getOptimalNewCameraMatrix + initUndistortRectifyMap + remap 矫正图像

函数解析:

1、cv::getOptimalNewCameraMatrix()

“Return the new camera matrix based on the free scaling parameter”,即根据根据比例因子返回相应的新的相机内参矩阵。

Mat cv::getOptimalNewCameraMatrix	
(	
		InputArray 	cameraMatrix,                  // 相机内参矩阵
        InputArray 	distCoeffs,                    // 相机畸变参数
        Size 	        imageSize,                     // 图像尺寸
        double 	        alpha,                         // 缩放比例
        								//当alpha=1时,所有像素均保留,但存在黑色边框。
										//当alpha=0时,损失最多的像素,没有黑色边框。
        Size 	        newImgSize = Size(),           // 校正后的图像尺寸
        Rect * 	        validPixROI = 0,               // 输出感兴趣区域设置
        bool 	        centerPrincipalPoint = false   // 可选标志
)	
           

1.1相机内参矩阵:

学习笔记 -- opencv图像去畸变法一: 使用 getOptimalNewCameraMatrix + initUndistortRectifyMap + remap 矫正图像法一 完整代码:法二:使用 undistort()法三: 手动实现参考

fx, fy:使用像素来描述x, y轴方向焦距的长度, 单位像素

cx,cy,主点的实际位置,单位也是像素。

赋值方法:

//fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;
const cv::Mat K = (cv::Mat_<double>(3,3) << 458.654, 0,367.215, 0, 457.296, 248.375, 0,0,1);
           

1.2相机畸变参数:

5个畸变参数D:k1 , k2 , k3 , p1 , p2

​赋值方法:

//k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
const cv::Mat D = (cv::Mat_<double> ( 5,1 ) <<  -0.28340811, 0.07395907, 0.0, 0.00019359, 1.76187114e-05);
           

2、 cv::initUndistortRectifyMap()

用于计算原始图像和矫正图像之间的转换关系,将结果以映射的形式表达,映射关系存储在map1和map2中。

void cv::initUndistortRectifyMap	
(	    
		InputArray 	cameraMatrix,     // 原相机内参矩阵
        InputArray 	distCoeffs,       // 原相机畸变参数
        InputArray 	R,                // 可选的修正变换矩阵 
        InputArray 	newCameraMatrix,  // 新相机内参矩阵
        Size 	        size,             // 去畸变后图像的尺寸
        int 	        m1type,           // 第一个输出的映射(map1)的类型,CV_32FC1 or CV_16SC2
        OutputArray 	map1,             // 第一个输出映射
        OutputArray 	map2              // 第二个输出映射
)	
           

3、 cv::remap()

把原始图像中某位置的像素映射到矫正后的图像指定位置。

void cv::remap
(       
		InputArray    src,                        // 原始图像
        OutputArray   dst,                        // 矫正图像           
        InputArray    map1,                       // 第一个映射          
        InputArray    map2,                       // 第二个映射      
        int           interpolation,              // 插值方式
        int           borderMode=BORDER_CONSTANT, // 边界模式           
        const Scalar& borderValue=Scalar()        // 边界颜色,默认Scalar()黑色   
)
           

法一 完整代码:

//
// Created by daybeha on 2021/9/20.
//
//https://zhuanlan.zhihu.com/p/137053640
#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{
//    const cv::Mat K = ( cv::Mat_<double> ( 3,3 ) << 931.73, 0.0, 480.0, 0.0, 933.16, 302.0, 0.0, 0.0, 1.0 );
//    const cv::Mat D = ( cv::Mat_<double> ( 5,1 ) << -1.7165e-1, 1.968259e-1, 0.0, 0.0, -3.639514e-1 );


    // 内参
//    double fx = 458.654, fy = 457.296, cx = 367.215, cy = 248.375;
    const cv::Mat K = (cv::Mat_<double>(3,3) << 458.654, 0,367.215, 0, 457.296, 248.375, 0,0,1);
    // 畸变参数
//    double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
    const cv::Mat D = (cv::Mat_<double> ( 5,1 ) <<  -0.28340811, 0.07395907, 0.0, 0.00019359, 1.76187114e-05);


    const string str = "/home/daybeha/Documents/My Codes/Visual Slam/learning code/ch5/imageBasics/";
    const int nImage = 5;
//    const int nImage = 1;
//    const int ImgWidth = 752;
//    const int ImgHeight = 480;
//
//    cv::Mat map1, map2;
//    cv::Size imageSiz(ImgWidth, ImgHeight);
//    const double alpha = 1;

    cv::Mat map1, map2;
    cv::Mat image = cv::imread("../../imageBasics/distorted.png");
    int rows = image.rows, clos = image.cols;
    cv::Size imageSize(clos, rows);


//    当alpha=1时,所有像素均保留,但存在黑色边框
//    当alpha=0时,损失最多的像素,没有黑色边框
//    const double alpha = 1;
    const double alpha = 0;  //


    cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);
    initUndistortRectifyMap(K, D, cv::Mat(), NewCameraMatrix, imageSize, CV_16SC2, map1, map2);
//
//    for(int i=0; i<nImage; i++)
//    {
//        string InputPath = str + to_string(i) + ".png";
//        cv::Mat RawImage = cv::imread(InputPath);
//        cv::imshow("RawImage", RawImage);
//
//        cv::Mat UndistortImage;
//        remap(RawImage, UndistortImage, map1, map2, cv::INTER_LINEAR);
//        cv::imshow("UndistortImage", UndistortImage);
//
//        string OutputPath = str + to_string(i) + "_un" + ".png";
//        cv::imwrite(OutputPath, UndistortImage);
//        cv::waitKey(0);
//    }

    cv::imshow("Distorted Image", image);

    cv::Mat UndistortImage;
    remap(image, UndistortImage, map1, map2, cv::INTER_LINEAR);
    cv::imshow("UndistortImage", UndistortImage);

//    string OutputPath = str + to_string(i) + "_un" + ".png";
//    cv::imwrite(OutputPath, UndistortImage);
    string OutputPath = "../../imageBasics/undistorted.png";
    cv::imwrite(OutputPath, UndistortImage);

    cv::waitKey(0);


    return 0;
}
           

法二:使用 undistort()

未完待续……

法三: 手动实现

先看SLAM十四讲中的相关讲解

……

参考

关于OpenCV中的去畸变

相机标定——相机的内参矩阵IntrinsicMatrix参数解释

Step1:模型 16个相机参数(内参、外参、畸变参数)

视觉SLAM十四讲(第二版)

继续阅读