学习笔记 -- 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十四讲(第二版)
推荐阅读
-
数字图像处理学习笔记 (XI) - 通过 Python 代码实现图像增强的线性变换、对数变换、幂律变换、分段线性变换、灰度分层、直方图均衡化、平滑滤波器、锐化滤波器
-
数字图像处理学习笔记 (X) - 空间滤波
-
数字图像处理学习笔记 (I) - 数字图像处理概述
-
图像处理|二维傅立叶变换学习笔记(实用版)
-
软件杯 深度学习图像修复算法 - opencv python 机器视觉
-
大创项目推荐用于昆虫识别的深度学习+opencv+python -图像识别 昆虫识别
-
基于 FCN 和互信息的医学图像配准技术研究(学习笔记)
-
学习笔记 -- opencv 图像去失真
-
相机失真、内部和外部参照、不失真图像、OpenCV 中的相机校准
-
OpenCV: 鱼眼相机去畸变 = 图像去畸变 + 点去畸变