首页 > 其他分享 >4.3.2 图像去畸变

4.3.2 图像去畸变

时间:2024-08-10 09:38:23浏览次数:9  
标签:undistortImage 4.3 rosnoetic image 图像 畸变 distorted cv

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系列。

从如下网站中下载源代码:

Releases - OpenCV

页面下滑,选择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标准(如nullptrchrono),因此需要设置编译器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

相关文章

  • 图像增强方法
    2.1直方图均衡化(HistogramEqualization)介绍直方图均衡化是一种图像处理技术,用于增强图像的对比度。通过调整图像的灰度值分布,使得图像的细节更加清晰。原理直方图均衡化通过累积分布函数(CDF)重新分配灰度值,使得图像的像素值分布更加均匀,从而提升图像的整体对比度。公......
  • vit的图像预处理过程
    在VisionTransformer(ViT)中,图像的预处理过程主要包括将图像转换为适合Transformer模型输入的格式。以下是从原始图像到模型输入所进行的主要操作步骤:1.图像尺寸调整(Resize)将输入图像调整为固定大小,通常是正方形(例如,224x224像素)。这是为了统一所有输入图像的尺寸,使得后......
  • 信息学奥赛一本通 1128 图像模糊处理
    1128:图像模糊处理时间限制:1000ms      内存限制:65536KB提交数:69990   通过数: 30350【题目描述】给定n行m列的图像各像素点的灰度值,要求用如下方法对其进行模糊化处理:1.四周最外侧的像素点灰度值不变;2.中间各像素点新灰度值为该像素点及其上下左......
  • 【深度学习】基于YOLOV5模型的图像识别-目标检测的性能指标详解与计算方法
    目标检测是计算机视觉中的重要任务,主要目的是在图像中识别并定位特定的物体。YOLO(YouOnlyLookOnce)系列模型作为目标检测领域的代表性方法之一,凭借其高效和准确的特点,广泛应用于实际场景中。本文通过详细介绍目标检测的性能指标及其计算方法,帮助读者更好地理解和评估YOLO......
  • 图像数据处理2
    1.2图像类型与图像数据1.2.1RGB真彩色图像(RGBimage,truecolorimage)RGB图像,也称为真彩色图像,是由三个相同维度的二维数组组成,每个数组分别代表图像颜色中的红色(R)、绿色(G)、蓝色(B)分量。每个像素的颜色由这三个分量的组合决定,而每个分量通常占用8位,因此每个像素总共由24位表......
  • OpenCV图像滤波(6)高斯滤波函数GaussianBlur()的使用
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述函数使用高斯滤波器对图像进行模糊处理。该函数使用指定的高斯核对源图像进行卷积。支持原位过滤。高斯模糊是一种有效的图像平滑技术,可以减少图像中的噪声和细节。函数原型vo......
  • OpenCV图像滤波(7)cv::getDerivKernels() 函数的使用
    操作系统:ubuntu22.04OpenCV版本:OpenCV4.9IDE:VisualStudioCode编程语言:C++11算法描述函数返回用于计算空间图像导数的滤波系数。该函数计算并返回用于空间图像导数的滤波系数。当ksize=FILTER_SCHARR时,生成Scharr3x3核(参见Scharr)。否则,生成Sobel核(参见Sob......
  • 【11月杭州,邀您投稿参会】2024年计算机视觉与图像处理国际学术会议 (CVIP 2024)
    【重要信息】会议官网:iccvip.org大会时间:2024年11月15日-17日大会地点:中国杭州一轮截稿日期:2024年8月21日接受/拒稿通知:投稿后1周内收录检索:EICompendex,Scopus【大会简介】2024年计算机视觉与图像处理国际学术会议(CVIP2024)将于2024年11月15日-17日在中国杭州举......
  • 医学图像分割的基准:TransUnet(用于医学图像分割的Transformer编码器)器官分割
    1、TransUnet介绍TransUnet是一种用于医学图像分割的深度学习模型。它是基于Transformer模型的图像分割方法,由AI研究公司HuggingFace在2021年提出。医学图像分割是一项重要的任务,旨在将医学图像中的不同结构和区域分离出来,以便医生可以更好地诊断和治疗疾病。传统的医学......
  • 在国产芯片上实现YOLOv5/v8图像AI识别-【2.3】RK3588上使用C++启用多线程推理更多内容
    本专栏主要是提供一种国产化图像识别的解决方案,专栏中实现了YOLOv5/v8在国产化芯片上的使用部署,并可以实现网页端实时查看。根据自己的具体需求可以直接产品化部署使用。B站配套视频:https://www.bilibili.com/video/BV1or421T74f基础背景对于国产化芯片来说,是采用NPU进......