天天看點

學習筆記 -- 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十四講(第二版)

繼續閱讀