相机畸变模型

news2025/1/15 8:31:55

文章目录

    • 概述
    • 相机畸变类型
      • 径向畸变
      • 切向畸变
    • 畸变数学模型
      • 径向畸变模型
      • 切向畸变模型
      • 畸变数学模型总结
    • 去畸变数学过程
      • 去畸变步骤
    • 畸变测试
    • 结论
    • 参考

概述

相机畸变是图像处理和计算机视觉中的常见问题。由于透镜的物理特性,图像边缘的物体往往会呈现扭曲,这种现象称为畸变。畸变主要分为两种类型:径向畸变和切向畸变。本文档将详细介绍相机畸变的数学模型、产生原因、以及去畸变的数学过程。

相机畸变类型

径向畸变

径向畸变是由于透镜形状不规则引起的,导致光线在远离透镜中心的地方比靠近中心的地方更加弯曲。这种畸变通常表现为枕形畸变(中间凹陷)或桶形畸变(中间凸起)。径向畸变的数学模型可以用泰勒级数展开式的前几项来描述,通常使用前两项和,即 k 1 k_1 k1 k 2 k_2 k2,对于畸变很大的镜头,如鱼眼镜头,可能需要增加第三项 k 3 k_3 k3 来进行描述。

在这里插入图片描述

切向畸变

切向畸变是由于透镜不完全平行于图像平面引起的,通常是由于透镜安装时的偏差导致的。这种畸变可以通过两个额外的参数 p 1 p_1 p1 p 2 p_2 p2 来描述。
在这里插入图片描述
在这里插入图片描述

畸变数学模型

径向畸变模型

对于成像仪上的某点,根据其在径向方向上的分布位置,畸变后的坐标 ( x ^ , y ^ ) (\hat{x}, \hat{y}) (x^,y^) 可以通过以下公式调节:

x ^ = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) \hat{x} = x(1 + k_1r^2 + k_2r^4 + k_3r^6) x^=x(1+k1r2+k2r4+k3r6)

y ^ = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) \hat{y} = y(1 + k_1r^2 + k_2r^4 + k_3r^6) y^=y(1+k1r2+k2r4+k3r6)

其中, ( x , y ) (x, y) (x,y) 是无畸变的归一化图像坐标, r r r 是图像像素点到图像中心点的距离,计算公式为 r 2 = x 2 + y 2 r^2 = x^2 + y^2 r2=x2+y2

切向畸变模型

切向畸变的影响可以通过以下公式描述:

x ^ = x + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) \hat{x} = x + 2p_1xy + p_2(r^2 + 2x^2) x^=x+2p1xy+p2(r2+2x2)

y ^ = y + 2 p 2 x y + p 1 ( r 2 + 2 y 2 ) \hat{y} = y + 2p_2xy + p_1(r^2 + 2y^2) y^=y+2p2xy+p1(r2+2y2)

畸变数学模型总结

综合径向畸变和切向畸变,我们可以得到总体畸变模型:

x ^ = x ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 1 x y + p 2 ( r 2 + 2 x 2 ) \hat{x} = x(1 + k_1r^2 + k_2r^4 + k_3r^6) + 2p_1xy + p_2(r^2 + 2x^2) x^=x(1+k1r2+k2r4+k3r6)+2p1xy+p2(r2+2x2)

y ^ = y ( 1 + k 1 r 2 + k 2 r 4 + k 3 r 6 ) + 2 p 2 x y + p 1 ( r 2 + 2 y 2 ) \hat{y} = y(1 + k_1r^2 + k_2r^4 + k_3r^6) + 2p_2xy + p_1(r^2 + 2y^2) y^=y(1+k1r2+k2r4+k3r6)+2p2xy+p1(r2+2y2)

去畸变数学过程

去畸变的过程实际上是对上述畸变模型的逆过程。首先,我们需要从畸变图像中恢复出无畸变的归一化图像坐标 ( x , y ) (x, y) (x,y),然后通过相机的内参矩阵将这些坐标转换为像素坐标。

去畸变步骤

  1. 确定畸变参数:通过相机标定过程获得的畸变参数 k 1 , k 2 , k 3 , p 1 , p 2 k_1, k_2, k_3, p_1, p_2 k1,k2,k3,p1,p2
  2. 归一化坐标:将像素坐标转换为归一化图像坐标。
  3. 逆畸变计算:使用畸变参数和归一化坐标,通过逆畸变模型计算出无畸变的归一化坐标。
  4. 像素坐标转换:将无畸变的归一化坐标通过相机内参矩阵转换回像素坐标。

畸变测试


TEST(TestDistortion, AddDistortion)
{
    cv::Mat white_image = cv::Mat::ones(500, 500, CV_8UC1) * 255;
    // cv::Mat white_image = cv::imread("/home/xx/Pictures/house.jpeg", cv::IMREAD_GRAYSCALE);
    cv::Mat image = white_image;
    // make grid on white image
    for (int i = 0; i < 500; i += 50)
    {
        cv::line(white_image, cv::Point(0, i), cv::Point(500, i), cv::Scalar(0, 0, 0), 1);
        cv::line(white_image, cv::Point(i, 0), cv::Point(i, 500), cv::Scalar(0, 0, 0), 1);
    }
    cv::Mat distorted_image = cv::Mat::zeros(image.size(), image.type());
    float cx = 0.0f;
    float cy = 0.0f;
    // 径向畸变参数 radial distortion
    float k1 = 0.0;
    float k2 = 0.0;
    // 切向畸变参数 Tangential distortion
    float p1 = -0.1;
    float p2 = 0.0;
    for (int row = 0; row < image.rows; row++)
    {
        for (int col = 0; col < image.cols; col++)
        {
            float x = (col - image.cols / 2.0f) / (float)image.cols;
            float y = (row - image.rows / 2.0f) / (float)image.rows;
            float rho = sqrt((x - cx) * (x - cx) + (y - cy) * (y - cy));
            float rho2 = rho * rho;
            float rho4 = rho2 * rho2;
            float x_distortion = (1 + k1 * rho2 + k2 * rho4) * x + 2 * p1 * x * y + p2 * (rho2 + 2 * x * x);
            float y_distortion = (1 + k1 * rho2 + k2 * rho4) * y + 2 * p2 * x * y + p1 * (rho2 + 2 * y * y);
            int u = x_distortion * image.cols + image.cols / 2.0f;
            int v = y_distortion * image.rows + image.rows / 2.0f;
            // std::cout<<"x_distortion: "<<x_distortion<<" y_distortion: "<<y_distortion<<std::endl;
            // std::cout << "u: " << u << " v: " << v << std::endl;
            if (u >= 0 && u < image.cols && v >= 0 && v < image.rows)
            {
                distorted_image.ptr<uchar>(row)[col] = image.ptr<uchar>(v)[u];
            }
            else
            {
                distorted_image.ptr<uchar>(row)[col] = 0;
            }
        }
    }

    cv::imshow("image", image);
    cv::imshow("distorted_image", distorted_image);
    cv::waitKey(0);
}

请自行调整 k 1 , k 2 , p 1 , p 2 k_1,k_2,p_1,p_2 k1,k2,p1,p2查看不同的畸变效果。
实例:

// 径向畸变参数 radial distortion
float k1 = 0.7;
float k2 = 0.3;
// 切向畸变参数 Tangential distortion
float p1 = -0.1;
float p2 = 0.0;

在这里插入图片描述
在这里插入图片描述

结论

相机畸变模型是理解和校正图像畸变的基础。通过掌握畸变的数学模型和去畸变过程,我们可以有效地矫正图像中的畸变,提高图像处理和计算机视觉任务的准确性。在实际应用中,如相机标定、三维重建、机器视觉等领域,去畸变技术都是不可或缺的一环。

参考

  1. https://www.qinxing.xyz/posts/b7ea425d/
  2. https://zhaoxuhui.top/blog/2018/04/17/CameraCalibration.html

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2214771.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

(34)FFT与信号频谱(双边谱)

文章目录 前言一、仿真代码二、仿真结果画图 前言 本文首先使用MATLAB生成一段余弦信号&#xff0c;然后对其进行FFT变换&#xff0c;给出了信号的双边幅度谱。 一、仿真代码 代码如下&#xff08;示例&#xff09;&#xff1a; %% 生成余弦波 % 指定信号的参数&#xff0c;…

k8s中的微服务

一、什么是微服务 用控制器来完成集群的工作负载&#xff0c;那么应用如何暴漏出去&#xff1f;需要通过微服务暴漏出去后才能被访问 Service是一组提供相同服务的Pod对外开放的接口。 借助Service&#xff0c;应用可以实现服务发现和负载均衡。 service默认只支持4层负载均…

Java 输入与输出(I\O)详解

一、Java 输入与输出&#xff08;I\O)系统概述 Java 输入/输出流&#xff08;Input/Output&#xff0c;简称I/O&#xff09;是Java语言用于读写数据的API&#xff0c;它提供了一系列类和接口&#xff0c;用于读取和写入各种类型的数据信息。 输入/输出&#xff08;I/O&#xff…

SpringBoot项目热部署-devtools

DevTools 会使用两个类加载器&#xff08;一个用于加载不变的类&#xff0c;一个用于加载可能会变化的类&#xff09;&#xff0c;每次重启只重新加载管理变化的类的加载器&#xff0c;因此会快很多 1.导入依赖 <dependency> <groupId>org.springframework.boot&l…

动态设置placeholder-class.默认搜索图标在中间获取焦点之后再左边

默认状态:placeholder和图标在中间位置 获取焦点&#xff1a;placeholder和图标在左边光标前面位置 动态设置placeholder-class <view class"search"><input type"search" class"select-input" input-align"center" v-model.…

算法题---动态规划

题目展示&#xff1a; 动态规划的题目我们一半分为5个步骤去分析&#xff0c;第一&#xff0c;状态表示&#xff1b;第二&#xff0c;动态转移方程&#xff1b;第三&#xff0c;初始化&#xff1b;第四&#xff0c;填表顺序&#xff1b;第五&#xff0c;返回值。 状态表示 这…

[权威出版|稳定检索]2024年大数据经济与公共管理国际会议(BDEPM 2024)

2024年大数据经济与公共管理国际会议 2024 International Conference on Big Data Economy and Public Management 【1】大会信息 会议名称&#xff1a;2024年大数据经济与公共管理国际会议 会议简称&#xff1a;BDEPM 2024 大会时间&#xff1a;请查看官网 大会地点&#xf…

网络协议原理

文章目录 TCP通信原理TCP与UDP的对比应用层应用层协议 --- tcp协议定制直接传递对象自定义协议现在要解决的问题业务处理 json的使用使用json进行序列化和反序列化操作 总结 TCP通信原理 tcp是面向字节流的 同时他也是面向连接的 所以TCP的服务器编写代码如图所示: 客户端的编…

Scala入门基础(10)高级函数

一.什么是高阶函数 二.map函数 三.foreach函数 四.filter函数 五.flatten函数 正文&#xff1a; 一.什么是高阶函数 高阶函数&#xff1a;是一个特殊的函数&#xff0c;特殊之处在于&#xff1a;它指使用其他函数作为参数或返回值 &#xff08;演示&#xff09; 二.map函…

maven项目打jar包之后如何指定外部配置文件运行java类

在maven项目中,常常会用到一些配置文件,一旦打成jar包之后,想要用外部的配置文件运行,怎么做呢? 一、配置文件config.ini 在maven项目中的src/main/resources目录下存放了一个配置文件config.ini。这个文件是默认的配置文件。 db.url=jdbc:mysql://localhost:3306/qyxx?u…

【JavaScript】LeetCode:66-70

文章目录 66 组合总和67 括号生成68 单词搜索69 分割回文串70 N皇后 66 组合总和 回溯sum&#xff1a;当前组合的数字和。递归终止条件&#xff1a;sum > target。收集结果条件&#xff1a;sum target&#xff0c;找到了满足条件的组合。注意&#xff1a;因为可以重复取数&…

亚洲最具影响力人物颜廷利:心理健康对身体健康的重要影响

在当代社会&#xff0c;面对疾病与痛苦&#xff0c;人们往往在西医与中医之间做出选择。21世纪世界上知名度最高的人物颜廷利教授的精辟见解指出了这两种医学体系的根本差异&#xff1a;西医以其高昂的费用&#xff0c;针对生理上的疾苦提供快速而直接的解决之道&#xff1b;相…

Python应用指南:利用高德地图API获取公交可达圈

参考文章&#xff1a;城市公交可达圈绘制方法&#xff08;一&#xff09; - 知乎 (zhihu.com) 本篇文章我们聚焦于通过公共交通出行方式&#xff08;包括公交、地铁、公交地铁的组合&#xff09;来获取一定时间内可以到达的范围。为了实现这一目标&#xff0c;我们将使用高德地…

在 Android 应用程序中实现与WebSocket 服务器的实时通信

&#x1f604;作者简介&#xff1a; 小曾同学.com,一个致力于测试开发的博主⛽️&#xff0c;主要职责&#xff1a;测试开发、CI/CD 如果文章知识点有错误的地方&#xff0c;还请大家指正&#xff0c;让我们一起学习&#xff0c;一起进步。 &#x1f60a; 座右铭&#xff1a;不…

spring-boot学习(2)

上次学习截止到拦截器 1.构建RESfun服务 PathVariable通过url路径获取url传递过来的信息 2.MyBatisPlus 第三行的mydb要改为自己的数据库名 第四&#xff0c;五行的账号密码改成自己的 MaooerScan告诉项目自己的这个MyBatisPlus是使用在哪里的&#xff0c;包名 实体类的定义…

PL/SQL Developer15和Oracle Instant Client安装配置详细图文教程

一、下载介质 1、Oracle Instant Client Oracle Instant Client Downloads | Oracle 中国 2、PL/SQL DEVELOPER PL/SQL Developer - Allround Automations Free trial - Allround Automations 二、安装介质。 1、安装plsqldev1504x64.msi。 一路默认下一步。 选择输入许可信…

实跑 YOLO V11在 OAK内部运行的效果

哈喽&#xff0c;各位OAK中国的朋友们! 大家好我是张伯生 今天&#xff0c;我想给大家演示一下最新发布的Yolo V11神经网络 下面我将演示的一个程序是&#xff1a;同时在我们的OAK相机上跑Yolo V11和RGB-D&#xff0c;也就是彩色相机和深度图的一个叠加的一个效果 RGB-D和Yo…

java_for循环

基本语法 for 关键字&#xff0c;表示循环控制for 有四要素: (1)循环变量初始化(2)循环条件(3)循环操作(4)循环变量迭代循环操作 , 这里可以有多条语句&#xff0c;也就是我们要循环执行的代码如果 循环操作(语句) 只有一条语句&#xff0c;可以省略 {}, 建议不要省略 流程图 …

电气学习知识点

文章目录 NPN和PNP输出 NPN和PNP输出 NPN和PNP&#xff08;两种不同类型的三极管&#xff09;都是集电极输出。&#xff08;集电极开路输出&#xff09; 下图b:基极、c集电极、e发射极 NPN示意图&#xff08;集电极连接负载 — 正方形&#xff09; NPN的电流流向是从集电极…

Elasticsearch设置 X-Pack认证,设置账号和密码

前言 以下Elasticsearch版本&#xff1a;7.9.3 ES自带的X-Pack密码验证&#xff1a; X-Pack是elasticsearch的一个扩展包&#xff0c;将安全&#xff0c;警告&#xff0c;监视&#xff0c;图形和报告功能捆绑在一个易于安装的软件包中&#xff0c;所以我们想要开启账号密码验证…