1.背景

由于相机的镜头并不完全理想,成像时会产生线条扭曲、失真等。对双目图像、鸟瞰图等进行处理时,首先要矫正去畸变。

2.镜头成像畸变原因

相机的镜头前有一块透镜,由于透镜的形状,当光线穿过透镜时,靠近光轴的光线折射比远离光轴的折射要小,就会产生径向畸变,此时真实世界中的直线在图像中会被弯曲,往外弯曲是枕形畸变,如下图(b),往里弯曲是桶形畸变,如下图(c)
在这里插入图片描述
由于透镜不可能完全与相机里的成像面平行,就会造成切向畸变

3.去畸变方法

假设归一化平面上的点P(x, y),可用极坐标(r, θ)表示,r就是P与归一化平面原点之间的距离,径向畸变就可以视为坐标点沿着距离方向发生改变,可以用畸变参数k1,k2,k3来修正;切向畸变可以看作坐标点的水平夹角发生改变。用多项式进行畸变拟合:
在这里插入图片描述
将这些畸变后的点在像素平面上的坐标计算出来:
在这里插入图片描述
然后把畸变后的像素放回原本的位置,即去除了畸变。

4. opencv去畸变函数

void undistort( InputArray src, OutputArray dst,
                             InputArray cameraMatrix,
                             InputArray distCoeffs,
                             InputArray newCameraMatrix = noArray() );

src 输入图像
dst 输出图像
cameraMatrix 相机内参
distCoeffs 畸变系数矩阵 顺序是[k1, k2, p1, p2]

5.代码实现

int main()
{
	cv::Mat img = cv::imread("C:\\Users\\Administrator\\Desktop\\20210706221702710.png");
	cv::Mat k = cv::Mat::eye(3, 3, CV_32FC1);   // 内参矩阵
	k.at<float>(0, 0) = 458.654;
	k.at<float>(0, 1) = 0;
	k.at<float>(0, 2) = 367.215;
	k.at<float>(1, 0) = 0;
	k.at<float>(1, 1) = 457.296;
	k.at<float>(1, 2) = 248.375;
	k.at<float>(2, 2) = 1;

	cv::Mat d = cv::Mat::zeros(1, 4, CV_32FC1); // 畸变系数矩阵 顺序是[k1, k2, p1, p2]
	d.at<float>(0, 0) = -0.28340811;
	d.at<float>(0, 1) = 0.07395907;
	d.at<float>(0, 2) = 0.00019359;
	d.at<float>(0, 3) = 1.76187114e-05;

	cv::Mat img_distort, img_absdiff;
	cv::undistort(img, img_distort, k, d);
	cv::absdiff(img, img_distort, img_absdiff);
		
	cv::imshow("img", img);
	cv::imshow("img_distort", img_distort);
	cv::imshow("img_absdiff", img_absdiff);

	cv::waitKey(0);

	return 0;
}

原图:
一张工厂灰度图,由于畸变导致部分直线条明显被弯曲了
在这里插入图片描述
矫正后的图:
矫正后的图像如下,可见弯曲的线都恢复正常了,但原图部分像素没有还原(落在了矫正后图像的外面)
在这里插入图片描述

参考:https://blog.csdn.net/qq_41035283/article/details/118531027

GitHub 加速计划 / opencv31 / opencv
77.38 K
55.71 K
下载
OpenCV: 开源计算机视觉库
最近提交(Master分支:2 个月前 )
c3747a68 Added Universal Windows Package build to CI. 7 天前
9b635da5 - 7 天前
Logo

旨在为数千万中国开发者提供一个无缝且高效的云端环境,以支持学习、使用和贡献开源项目。

更多推荐