原始图片畸变矫正以及resize后的图片畸变矫正

1. 利用opencv对原始图片进行畸变矫正

原始图片进行畸变矫正主要用到了opencv中的cv::getOptimalNewCameraMatrix函数、cv::fisheye::initUndistortRectifyMap(针孔模型用cv::initUndistortRectifyMap函数)函数以及cv::remap函数。下面详细介绍这三个函数的作用:

1.1 cv::getOptimalNewCameraMatrix函数

参数说明:

Mat cv::getOptimalNewCameraMatrix	
(	InputArray 	cameraMatrix,                  // 相机内参矩阵
        InputArray 	distCoeffs,                    // 相机畸变参数
        Size 	        imageSize,                     // 图像尺寸
        double 	        alpha,                         // 缩放比例
        Size 	        newImgSize = Size(),           // 校正后的图像尺寸
        Rect * 	        validPixROI = 0,               // 输出感兴趣区域设置
        bool 	        centerPrincipalPoint = false   // 可选标志
)	

这个函数的功能是,“Return the new camera matrix based on the free scaling parameter”,即根据根据比例因子返回相应的新的相机内参矩阵。
这里的"比例因子"就是函数的第四个参数(alpha),这个参数的范围是(0, 1)。调节alpha的值能够控制得到的新矩阵中的fx和fy的大小。
当alpha=1的时候,原图像中的所有像素能够得到保留,因此这个时候得到的矫正后的图像是带黑框的,如后面图1所示。
当alpha=0时,得到的图像是不带黑色边框的,相对于原图像,此时的图像损失了部分像素,如后面图2所示。alpha的值控制着具体损失多少像素。

alpha和newImageSize是两个互不干扰的参数,alpha只管是否对图像进行裁剪,而newImageSize只负责把图像进行缩放,这二者都会对返回的新的相机参数造成影响.

1.2 cv::initUndistortRectifyMap函数

参数说明:

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              // 第二个输出映射
)	

这个函数用于计算原始图像和矫正图像之间的转换关系,将结果以映射的形式表达,映射关系存储在map1和map2中。
在单目相机例子中,newCameraMatrix可以用cv::getOptimalNewCameraMatrix来计算,或者直接与cameraMatrix相等。在双目相机例子中,newCameraMatrix一般是用cv::stereoRectify计算而来的。
cv::initUndistortRectifyMap是针对针孔模型的相机进行矫正的函数,对于鱼眼相机,需要使用cv::fisheye::initUndistortRectifyMap函数获取原始图像和矫正图像之间的转换关系。

1.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()黑色   
)

函数功能:把原始图像中某位置的像素映射到矫正后的图像指定位置。
这里的map1和map2就是上面cv::initUndistortRectifyMap()计算出来的结果。

以上就是利用opencv进行原始图像矫正的步骤,除此之外,还可以使用 cv::undistort()函数直接进行原始图片矫正,该函数内部调用了initUndistortRectifyMap和remap函数。

整体代码实现:

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

using namespace std;
using namespace cv;

int main()
{
    // 读入原始图像
    Mat img = imread("fish_eye.jpg");

    // 设置相机参数
    Mat K = (Mat_<double>(3, 3) << 1000, 0, 320, 0, 1000, 240, 0, 0, 1); // 内参矩阵
    Mat D = (Mat_<double>(1, 4) << 0.1, 0.2, 0.3, -0.1); // 畸变系数

    // 畸变矫正
    Mat mapx, mapy;
    Mat new_K = getOptimalNewCameraMatrix(K, D, img.size(), 1, img.size());
    initUndistortRectifyMap(K, D, Mat(), new_K, img.size(), CV_32FC1, mapx, mapy);
    Mat new_img;
    remap(img, new_img, mapx, mapy, INTER_LINEAR);

    // 显示矫正后的图像
    namedWindow("fish_eye", WINDOW_NORMAL);
    namedWindow("corrected", WINDOW_NORMAL);
    imshow("fish_eye", img);
    imshow("corrected", new_img);
    waitKey();

    return 0;
}

2 对resize后的图片进行矫正

对resize之后的图片进行畸变矫正,需要对内参矩阵进行处理:

在知道原始相机内参 (fx, 0, cx, 0, fy, cy, 0, 0, 1) 的情况下,可以通过以下公式计算resize后的相机内参 (fx′, 0, cx′, 0, fy′,cy′, 0, 0,1):

在这里插入图片描述

其中,w 和 h 是原始图片的宽和高,w′和 h′是resize后图片的宽和高。

实现代码如下:

#include <opencv2/opencv.hpp>
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/highgui.hpp>

int main(){

 input:
// 原始内参矩阵:
cv::Mat intrinsic_matrix_cv = ...;
// 原始畸变系数
cv::Mat dist_coeffs = ...;
// resize后的图片
cv::Mat img_resized = ...;
// resize后的图片的尺寸与原始图像的尺寸的比例关系
double raw_cols_scale = resized_img_cols/static_cast<double>(raw_img_cols);
double raw_rows_scale = resized_img_rows/static_cast<double>(raw_img_rows);

// 矫正后的图像
cv::Mat undistort_img;
cv::Mat mapx;
cv::Mat mapy;
// 依据resize后的图片的尺寸以及原始图像的尺寸的比例关系,计算resize后的图片的内参矩阵: 
cv::Mat resized_intrinsic_matrix_cv = cv::Mat::eye(3, 3, CV_64F);
resized_intrinsic_matrix_cv.at<double>(0,0) = intrinsic_matrix_cv.at<double>(0,0) * raw_cols_scale;
resized_intrinsic_matrix_cv.at<double>(1,1) = intrinsic_matrix_cv.at<double>(1,1) * raw_rows_scale;
resized_intrinsic_matrix_cv.at<double>(0,2) = intrinsic_matrix_cv.at<double>(0,2) * raw_cols_scale;
resized_intrinsic_matrix_cv.at<double>(1,2) = intrinsic_matrix_cv.at<double>(1,2) * raw_rows_scale;
// 根据比例因子计算新的内参矩阵
cv::Mat new_intrinsic_matrix_cv = cv::getOptimalNewCameraMatrix(resized_intrinsic_matrix_cv, dist_coeffs, img_resized.size(), 0,  img_resized.size());
// 计算resized图像和矫正图像之间的转换关系,将结果以映射的形式表达,映射关系存储在mapx和mapy中。
cv::fisheye::initUndistortRectifyMap(resized_intrinsic_matrix_cv, dist_coeffs, cv::Mat(), new_intrinsic_matrix_cv, img_resized.size(), CV_32F, mapx, mapy);
// 把resized_img图像中某位置的像素映射到矫正后的图像指定位置。
cv::remap(img_resized, undistort_img, mapx, mapy, cv::InterpolationFlags::INTER_LINEAR);

// 显示resize后的图片和畸变矫正后的图片
cv::imshow("Resized image", img_resized);
cv::imshow("Undistorted image", undistort_img);
cv::waitKey(0);
cv::destroyAllWindows();

return 0;
}
  • 2
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值