目录
- 1.背景
- 2.镜头成像畸变原因
- 3.去畸变方法
- 4. opencv去畸变函数
- 5.代码实现
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