学习笔记 -- opencv图像去畸变

法一: 使用 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相机内参矩阵:

请添加图片描述

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()
{
    // 内参
//    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()

函数功能:直接对图像进行畸变矫正。

其内部调用了initUndistortRectifyMap和remap函数。

void cv::undistort	
(	
		InputArray 	src,                        // 原始图像
        OutputArray 	dst,                    // 矫正图像
        InputArray 	cameraMatrix,               // 原相机内参矩阵
        InputArray 	distCoeffs,                 // 相机畸变参数
        InputArray 	newCameraMatrix = noArray() // 新相机内参矩阵
)	

如果有多个图片需要矫正,那么推荐使用法一。
因为initUndistortRectifyMap() 只需计算一次即可,不需要每次循环都计算,因此可以将initUndistortRectifyMap() 放在循环外面。而法二undistort()函数内部调用了initUndistortRectifyMap和remap,所以每张图像都计算1次initUndistortRectifyMap,这会大大降低效率,增加程序耗时。

(以下程序是copy的, 待修正……)

#include <iostream>
#include <opencv2/opencv.hpp>

using namespace std;

int main()
{
    // 内参
    const cv::Mat K = (cv::Mat_<double>(3,3) << 458.654, 0,367.215, 0, 457.296, 248.375, 0,0,1);
    // 畸变参数
    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 ImgWidth = 960;
    const int ImgHeight = 640;

    cv::Mat map1, map2;
    cv::Size imageSize(ImgWidth, ImgHeight);
    const double alpha = 1;
    cv::Mat NewCameraMatrix = getOptimalNewCameraMatrix(K, D, imageSize, alpha, imageSize, 0);

    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;
        cv::undistort(RawImage, UndistortImage, K, D, K);
//        cv::undistort(RawImage, UndistortImage, K, D, NewCameraMatrix);
        cv::imshow("UndistortImage", UndistortImage);

        string OutputPath = str + to_string(i) + "_un2" + ".png";
        cv::imwrite(OutputPath, UndistortImage);
        cv::waitKey(0);
    }

    return 0;
}

法三: 手动实现

先看SLAM十四讲中的相关讲解
请添加图片描述

……

参考

关于OpenCV中的去畸变

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

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

视觉SLAM十四讲(第二版)

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

昼行plus

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值