1.简介
图像畸变是指图像中出现的形变或失真,通常由于光学系统的非理想性(透镜和成像平面很难做到完全平行)或摄像机的透镜特性引起。图像畸变通常分为两种:径向畸变和切向畸变。
2.切向畸变
切向畸变(Tangential Distortion)通常是由于镜头与图像传感器之间的距离不正确造成的。这种畸变表现为图像边缘的直线向外延伸形成倾斜,使得物体的角部出现切割或拉伸的效果。
切向畸变有两种形式:
- 第一类切向畸变:当透镜靠图像传感器太近时发生,导致图像边缘的直线向外弯曲。
- 第二类切向畸变:当透镜离图像传感器太远时发生,导致图像边缘的直线向内弯曲。
好了,说人话。“切向畸变”就是矢量端点沿切线方向发生的变化,也就是角度的变化dt。还有一种解释是由于摄像机制造上的缺陷使得透镜本身与图像平面不平行而产生的。
注意,通常假设这些畸变呈多项式关系,以下是其数学模型:
其中,是畸变点在图像上的原始坐标,是校正后的新坐标,、为切向畸变系数,为极坐标系下畸变点到坐标原点的距离(即镜头中心到图像点的距离)。
3.径向畸变
径向畸变(Radial Distortion)主要是由于镜头内部的透镜元素对通过它们的光线施加了不均匀的放大率造成的。这种畸变通常在图像的边缘更为明显,因为边缘的光线通过镜头时光轴形成的角度较大。径向畸变通常有以下两种形式。
3.1桶形畸变
桶形畸变(Barrel Distortion)是当径向畸变导致图像中心的放大率高于边缘时发生的。结果是图像中心部分的直线向外弯曲,形成一种“桶”状的膨胀效果。桶形畸变常见于广角镜头。
3.2枕形畸变
枕形畸变(Pincushion Distortion)与桶形畸变相反,当边缘的放大率高于中心时,会发生枕形畸变。这种情况下,图像边缘的直线向内弯曲,好像被“挤压”进图像中心,形成枕形效果。枕形畸变常见于长焦镜头。
这是最经典的一张图,大家可以简单记作:桶形畸变(向外弯曲),枕形畸变(向内弯曲)。以下是其数学模型:
其中,是畸变点在图像上的原始坐标,是校正后的新坐标,为径向向畸变系数,为极坐标系下畸变点到坐标原点的距离(即镜头中心到图像点的距离)。
4.C++实现
以下代码均在ubuntu20.04上验证通过,使用的OpenCV C++版本为3.4.15。代码主要调用了OpenCV库中的undistort函数,并利用我的另一篇博客(相机标定及C++实现-CSDN博客)得到的相机内参和畸变系数来对图像进行校正。
在运行代码前可以按照我的相机标定那篇博客创建build,images,src文件夹和CMakeLists.txt文件,以下是放在src文件夹下的源代码:
#include<iostream>
#include<opencv2/opencv.hpp>
using namespace std;
int main(int argc, char **argv)
{
if(argc < 2)
{
cout<<"输入正确的图片路径"<<endl;
return -1;
}
//读取图片
cv::Mat image = cv::imread(argv[1],cv::IMREAD_COLOR);
//图像是否读取成功
if(image.empty())
{
cout<<"图片读取失败"<<endl;
return -1;
}
//读取相机内参和畸变系数,这里的相机内参和畸变系数是相机标定的结果,需要提前标定
cv::Mat cameraMatrix, distCoeffs;
cameraMatrix = (cv::Mat_<double>(3,3)<<533.0082745226835, 0, 341.891649034585,
0, 533.0298665139785, 234.6399491136406,
0, 0, 1);
distCoeffs = (cv::Mat_<double>(1,5)<<-0.2797096204667459, 0.02806520133705146, 0.001221734842500993, 3.843081231723055e-05, 0.128566132396488);
//去除畸变
cv::Mat undistortedImage;
//使用相机内参和畸变系数进行去畸变
cv::undistort(image,undistortedImage,cameraMatrix,distCoeffs,cv::Mat());
//显示原图和去畸变后的图片
cv::imshow("originalImage",image);
cv::imshow("undistortedImage",undistortedImage);
cv::waitKey(0);
return 0;
}
以下是CMakeLists.txt中的代码,注意按照你的源代码文件名修改倒数第二行src/undistort.cpp这句代码。
#设置当前cmake运行的最低版本
cmake_minimum_required(VERSION 3.2)
# 设置项目名称
project(undistort)
# 设置C++标准为11
set(CMAKE_CXX_STANDARD 11)
# 查找OpenCV库
find_package(OpenCV REQUIRED)
#包含OpenCV的头文件
include_directories(${OpenCV_INCLUDE_DIRS})
# 添加可执行文件
add_executable(undistort src/undistort.cpp)
# 链接OpenCV库
target_link_libraries(undistort ${OpenCV_LIBS})
进入到build文件夹下,打开终端,输入以下命令:
cmake ..
make
具体运行结果如下:
上面ls命令下绿色的undistort就是我们的可执行文件,这个可执行文件名和我们CMakeLists.txt文件中最后两行是相对应的。接着在build文件夹下执行我们的可执行文件(undistort)
./undistort ./../images/left01.jpg
运行结果如下,看着有点效果。