https://zhuanlan.zhihu.com/p/137053640
https://xgyopen.github.io/2018/12/06/2018-12-06-imv-calibrate-camera/
在opencv中,有关图像或像素点(角点)去畸变的函数有
cv::undistort(),
cv::getOptimalNewCameraMatrix(),
cv::initUndistortRectifyMap(),
cv::remap()
cv::undistortPoints()。
- 其中undistort可以直接对图像去畸变,
- getOptimalNewCameraMatrix、initUndistortRectifyMap和remap配合也可以对图像去畸变,他们之间有相同之处,又有各自特性
- 而undistortPoints是只针对像素点去畸变。
下面就使用方法及细节进行梳理,并给出代码示例,以便加深印象。
通用畸变去除流程:
步骤:
cv::getOptimalNewCameraMatrix()(根据根据比例因子返回相应的新的相机内参矩阵)
-----> cv::initUndistortRectifyMap()(计算原始图像和矫正图像之间的转换关系)
-----> cv::remap()(把原始图像中某位置的像素映射到矫正后的图像指定位置)
一步到位
cv::getOptimalNewCameraMatrix()
----> cv::undistort()(其内部调用了initUndistortRectifyMap和remap函数。)
代码示例
使用 undistort 矫正图像
#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 );
const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";
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;
}
缺点:
如果有多个图片需要矫正,那么不推荐使用cv::undistort的方法,因为initUndistortRectifyMap函数本来只需要计算一次就行,但cv::undistort需要每次循环都计算。所以相当于你n张图像计算了n次initUndistortRectifyMap,这会大大降低效率,增加程序耗时。
使用 getOptimalNewCameraMatrix + initUndistortRectifyMap + remap 矫正图像
#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 ); // 相机畸变参数
const string str = "/home/jiang/4_learn/WeChatCode/ImageUndistort/data/";
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);
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);
}
return 0;
}
当alpha=1时,所有像素均保留,但存在黑色边框。
当alpha=0时,损失最多的像素,没有黑色边框。
参考
https://zhuanlan.zhihu.com/p/137053640