4.3.2 图像去畸变
参考教程:
相机标定(4) 矫正畸变 undistort()和initUndistortRectifyMap()-CSDN博客
学习笔记 -- opencv图像去畸变_opencv 畸变参数-CSDN博客
下面我们将演示图像去畸变的过程,在OpenCV中提供了一个函数cv::undistort()用于对图像进行去畸变,为了加深我们的印象,我们从公式出发重新写一个畸变函数。
1. 安装OpenCV
1.1 下载OpenCV
参考教程:
无法定位软件包libjasper-dev的解决办法-CSDN博客
视觉slam14讲ch5 opencv安装 ubuntu20.04_libvtk5-dev-CSDN博客
OpenCV提供了大量的开源图像算法,是计算机视觉领域使用极广的图像处理算法库。在Ubuntu系统下,OpenCV有从源代码安装和只安装库文件两种方式可以选择:
(1)从源代码安装,是指从OpenCV网站下载所有的OpenCV源代码,并在机器上编译以便使用。好处是可以选择的版本比较丰富,而且也能看到源代码,不过需要花费一些编译时间。
(2)只安装库文件,是指通过Ubuntu安装由Ubuntu社区人员已经编译好的库文件,无须重新编译一遍。
因为我们使用较新版本的OpenCV,所以必须选择从源代码安装的方式来安装它。一来,可以调整一些编译选项,匹配编程环境(例如,需不需要GPU加速等);再者,可以使用一些额外的功能。OpenCV目前维护三个主要版本,分为OpenCV2.4系列、OpenCV 3系列和OpenCV 4系列。当前使用OpenCV 3系列。
从如下网站中下载源代码:
页面下滑,选择OpenCV – 3.4.16
版本,点击”Sources
“进行下载
下载得到如下的压缩包
将opencv-3.4.16.zip
文件拖拽至虚拟机的home
文件夹下:
点击opencv-3.4.16.zip
文件,右键,选择“提取到此处
”
1.2 配置依赖项并编译
编译之前,先来安装OpenCV的依赖项:
rosnoetic@rosnoetic-VirtualBox:~$ sudo add-apt-repository "deb http://security.ubuntu.com/ubuntu xenial-security main"
rosnoetic@rosnoetic-VirtualBox:~$ sudo apt update
rosnoetic@rosnoetic-VirtualBox:~$ sudo apt upgrade
rosnoetic@rosnoetic-VirtualBox:~$ sudo apt-get install build-essential libgtk2.0-dev libvtk6-dev libjpeg-dev libtiff5-dev libjasper-dev libopenexr-dev libtbb-dev libcanberra-gtk-module
事实上,OpenCV的依赖项很多,缺少某些编译项会影响它的部分功能。OpenCV在cmake阶段检查依赖项是否会安装,并调整自己的功能。如果电脑上有GPU并且安装了相关依赖项,OpenCV也会把GPU加速打开。不过当前,上述依赖项已经足够了。
安装完依赖项后进行编译:
rosnoetic@rosnoetic-VirtualBox:~$ cd opencv-3.4.16/
rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16$ mkdir build
rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16$ cd build/
rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ cmake ..
接着进行编译
rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ make -j4
整个编译过程大概需要二十分钟到一小时不等。
make之后,调用sudo make install将OpenCV安装到电脑上(而不是仅仅编译)。
rosnoetic@rosnoetic-VirtualBox:~/opencv-3.4.16/build$ sudo make install
2. 操作OpenCV图像
2.1 编写undistortImage函数
2.1.1 创建文件夹
通过终端创建一个名为undistortImage
的文件夹以保存我们的VSCode
项目,在/undistortImage
目录下打开vscode
。
rosnoetic@rosnoetic-VirtualBox:~$ mkdir -p undistortImage
rosnoetic@rosnoetic-VirtualBox:~$ cd undistortImage/
rosnoetic@rosnoetic-VirtualBox:~/undistortImage$ code .
2.1.2 编写源代码
新建文件undistortImage.cpp
在undistortImage.cpp
粘贴如下代码并保存(Ctrl+S)
// 载入opencv的头文件
#include <opencv2/opencv.hpp>
// 载入string的头文件
#include <string>
// 使用std命名空间
using namespace std;
// 导入畸变图片地址
string image_path = "distorted.png";
// 定义main函数程序主入口
int main(int argc, char argv){
// 图像畸变参数
double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
// 相机内参
double fx = 485.654, fy = 457.296, cx = 367.215, cy = 248.375;
// 使用cv::imread读取image_path地址下的图片文件,并使用cv::Mat进行接收,图像是灰度图
cv::Mat image = cv::imread(image_path,0);
// 我们使用了cv::Mat类型进行了接收imgae,可以通过rows和cols读取image的行数和列数
int rows = image.rows, cols = image.cols;
// 使用cv::Mat创建图像,其中输入行数rows和列数cols,cv_8UC1表示图像为灰度图信息,并使用cv::Mat进行接收
// 从中我们可以看到cv::Mat既可以定义类型,也可以创建矩阵
cv::Mat image_undistort = cv::Mat(rows, cols,CV_8UC1);
/*
接着我们计算去畸变后的图像位置点,这里是一个有意思的点:
我们分析当前没有畸变的点,经过畸变之后所对应的位置,然后将该位置的点的像素值填充到
没有畸变的图像位置中
畸变前的位置点为(x, y),畸变后的点位置为(x_distorted, y_distorted)
x_distorted = x(1 + k1*r^2 + k2*r^4 + k3*r^6) +p1*( 2*x*y) +p2* (r^2+2x^2)
y_distorted = y(1+ k1*r^2 + k2*r^4 + k3*r^6) + p1 * (r^2+2y^2) + p2*(2*x*y)
*/
// 使用for循环进行遍历
// 在像素坐标系中u对应着列cols,v对应着行,我们在矩阵的遍历时首先遍历行,然后再遍历列
for (int v = 0;v < rows;v++){
for (int u = 0;u < cols; u++){
// 计算u和v对应到图像坐标系中的坐标
double x = (u - cx) / fx, y = (v - cy) / fy;
// 计算(x,y)和原点之间的距离
double r = sqrt(x * x + y * y);
// 依据公式计算畸变后的(x,y)所在的位置
double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (2 * x* y) + p2 * (r * r + 2*x*x);
double y_distorted = y * (1 + k1 *r *r + k2 *r *r * r *r ) + p1 * (r*r + 2*y*y)+ p2 * (2*x*y);
// 将畸变后的(x_distorted,y_distorted)重新映射回像素坐标系
double u_distorted = fx * x_distorted + cx;
double v_distorted = fy * y_distorted + cy;
// 接着分析畸变后的点是否超过了图像边界范围,所以需要进行if语句的判断,
// 如果超过了,则对应位置的像素点为0
//如果没有超过,则提取畸变图像中(u_distorted,v_distorted)点的像素值将其填充到未畸变图像的(u,v)处
if (u_distorted < cols && u_distorted >= 0 && v_distorted < rows && v_distorted >= 0){
// 由于像素点的坐标是整型,因此需要通过(int)强制将double类型转化为整型,然后使用at<uchar>读取image的像素值,并将其填充到image_undistorted的(u,v)处
image_undistort.at<uchar>(v,u) = image.at<uchar>((int)v_distorted, (int)u_distorted);
}else{
// 将像素值设置为0
image_undistort.at<uchar>(v,u) = 0;
}
}
}
// 绘制畸变去除前后的图像
// 使用cv::imshow函数展示畸变图像
cv::imshow("distorted", image);
// 使用cv::imshow函数展示去除畸变后的图像
cv::imshow("undistorted",image_undistort);
// 等待输入回车,即可关闭窗口
cv::waitKey();
return 0;
}
2.2 新建CMakeLists.txt文件
新建CMakeLists.txt
文件
在CMakeLists.txt
中添加如下内容:
# 使用cmake之前需要指定cmake的最低版本
cmake_minimum_required(VERSION 2.8)
# 为我们的项目文件命名一个名称
project(UNDISTORTIMAGE)
# 使用set设置C++版本CMAKE_CXX_FLAGS,当前指定的时C++11的版本
set(CMAKE_CXX_FLAGS,"-std=c++11")
# 我们的程序文件中使用了opencv的库,因此我们首先需要找到opencv所在的位置
find_package(OpenCV REQUIRED)
# 添加OpenCV的头文件目录OpenCV_INCLUDE_DIRS到我们的头文件目录include_directories中
include_directories(${OpenCV_INCLUDE_DIRS})
# 添加可执行文件undistortImage.cpp,并将其命名为undistortImage
add_executable(undistortImage undistortImage.cpp)
# 将我们的可执行文件undistortImage连接到Opencv的库文件中
# 库文件是为了让用户看不到源代码,而将源文件编译成库文件,库文件是二进制文件
target_link_libraries(undistortImage ${OpenCV_LIBS})
由于程序中使用了C++11
标准(如nullptr
和chrono
),因此需要设置编译器set(CMAKE_CXX_FLAGS "-std=c++11")
。
2.3 cmake编译
ctrl+alt+T
打开终端,执行如下指令进行cmake
编译
rosnoetic@rosnoetic-VirtualBox:~$ cd undistortImage/
rosnoetic@rosnoetic-VirtualBox:~/undistortImage$ mkdir build
rosnoetic@rosnoetic-VirtualBox:~/undistortImage$ cd build/
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ cmake ..
接着make
对工程进行编译
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ make
2.4 运行
将distorted.png
文件拖拽至undistortImage/build
文件夹下
进一步的调用可执行文件:
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ ./undistortImage
依次显示如下内容:
可以看到原来弯的窗变成了直的窗。
3. 使用opencv自带的去畸变函数
3.1 编写use_undistort函数
新建文件use_undistort.cpp
在use_undistort.cpp
粘贴如下代码并保存(Ctrl+S)
// 载入opencv的头文件
#include <opencv2/opencv.hpp>
// 载入string的头文件
#include <string>
// 使用std命名空间
using namespace std;
// 导入畸变图片地址
string image_path = "distorted.png";
// 定义main函数程序主入口
int main(int argc, char argv){
// 图像畸变参数
double k1 = -0.28340811, k2 = 0.07395907, p1 = 0.00019359, p2 = 1.76187114e-05;
// 相机内参
double fx = 485.654, fy = 457.296, cx = 367.215, cy = 248.375;
// 使用cv::imread读取image_path地址下的图片文件,并使用cv::Mat进行接收,图像是灰度图
cv::Mat image = cv::imread(image_path,0);
// 我们使用了cv::Mat类型进行了接收imgae,可以通过rows和cols读取image的行数和列数
int rows = image.rows, cols = image.cols;
// 使用cv::Mat创建图像,其中输入行数rows和列数cols,cv_8UC1表示图像为灰度图信息,并使用cv::Mat进行接收
// 从中我们可以看到cv::Mat既可以定义类型,也可以创建矩阵
cv::Mat image_undistort = cv::Mat(rows, cols,CV_8UC1);
/*
接着我们计算去畸变后的图像位置点,这里是一个有意思的点:
我们分析当前没有畸变的点,经过畸变之后所对应的位置,然后将该位置的点的像素值填充到
没有畸变的图像位置中
畸变前的位置点为(x, y),畸变后的点位置为(x_distorted, y_distorted)
x_distorted = x(1 + k1*r^2 + k2*r^4 + k3*r^6) +p1*( 2*x*y) +p2* (r^2+2x^2)
y_distorted = y(1+ k1*r^2 + k2*r^4 + k3*r^6) + p1 * (r^2+2y^2) + p2*(2*x*y)
*/
// 使用for循环进行遍历
// 在像素坐标系中u对应着列cols,v对应着行,我们在矩阵的遍历时首先遍历行,然后再遍历列
for (int v = 0;v < rows;v++){
for (int u = 0;u < cols; u++){
// 计算u和v对应到图像坐标系中的坐标
double x = (u - cx) / fx, y = (v - cy) / fy;
// 计算(x,y)和原点之间的距离
double r = sqrt(x * x + y * y);
// 依据公式计算畸变后的(x,y)所在的位置
double x_distorted = x * (1 + k1 * r * r + k2 * r * r * r * r) + p1 * (2 * x* y) + p2 * (r * r + 2*x*x);
double y_distorted = y * (1 + k1 *r *r + k2 *r *r * r *r ) + p1 * (r*r + 2*y*y)+ p2 * (2*x*y);
// 将畸变后的(x_distorted,y_distorted)重新映射回像素坐标系
double u_distorted = fx * x_distorted + cx;
double v_distorted = fy * y_distorted + cy;
// 接着分析畸变后的点是否超过了图像边界范围,所以需要进行if语句的判断,
// 如果超过了,则对应位置的像素点为0
//如果没有超过,则提取畸变图像中(u_distorted,v_distorted)点的像素值将其填充到未畸变图像的(u,v)处
if (u_distorted < cols && u_distorted >= 0 && v_distorted < rows && v_distorted >= 0){
// 由于像素点的坐标是整型,因此需要通过(int)强制将double类型转化为整型,然后使用at<uchar>读取image的像素值,并将其填充到image_undistorted的(u,v)处
image_undistort.at<uchar>(v,u) = image.at<uchar>((int)v_distorted, (int)u_distorted);
}else{
// 将像素值设置为0
image_undistort.at<uchar>(v,u) = 0;
}
}
}
// 绘制畸变去除前后的图像
// 使用cv::imshow函数展示畸变图像
cv::imshow("distorted", image);
// 使用cv::imshow函数展示去除畸变后的图像
cv::imshow("undistorted",image_undistort);
// 等待输入回车,即可关闭窗口
cv::waitKey();
return 0;
}
2.2 新建CMakeLists.txt文件
在CMakeLists.txt
中添加如下内容:
# 添加可执行文件use_undistort.cpp,并将其命名为use_undistort
add_executable(use_undistort use_undistort.cpp)
# 为可执行文件连接到opencv的库文件
target_link_libraries(use_undistort ${OpenCV_LIBS})
2.3 cmake编译
ctrl+alt+T
打开终端,执行如下指令进行cmake
编译
rosnoetic@rosnoetic-VirtualBox:~$ cd undistortImage/build/
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ cmake ..
接着make
对工程进行编译
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ make
2.4 运行
进一步的调用可执行文件:
rosnoetic@rosnoetic-VirtualBox:~/undistortImage/build$ ./use_undistort
依次显示如下内容:
可以看到原来弯的窗变成了直的窗。
标签:undistortImage,4.3,rosnoetic,image,图像,畸变,distorted,cv From: https://www.cnblogs.com/windandchimes/p/18351960