相机去畸变

news2024/11/27 23:56:37

1. 背景

在做图像感知工作过程中会遇到需要处理相机畸变的情况,如SLAM、3D重建等,则需要了解一些常见相机模型的成像过程,以及依据成像过程实现去除相机成像的畸变。

注意:这篇文章并不涉及太多相机参数畸变原理,更多侧重在使用对应相机模型如何实现图像去畸变。

2. pinhole相机模型

针孔模型是较为经典的模型,它的畸变建模比较简单,一般使用两种畸变参数:径向畸变(radial distortion)和切向畸变(tangential distortion)。当然在一些资料中还存在棱镜畸变(prism distortion),只是这个畸变参数不经常使用。这里对于径向畸变使用 [ k 1 , k 2 , … , k n ] [k_1,k_2,\dots,k_n] [k1,k2,,kn]表示,其中 n n n是畸变的阶数(下同),切向畸变使用 [ p 1 , p 2 ] [p_1,p_2] [p1,p2],棱镜畸变使用 [ s 1 , s 2 , s 3 , s 4 ] [s_1,s_2,s_3,s_4] [s1,s2,s3,s4]表示。

则对于针孔相机下的去畸变可以描述为如下计算过程:
在这里插入图片描述
ref:

  1. opencv文档——Camera Calibration and 3D Reconstruction

pinhole模型畸变去除参考代码:

def undistort_pinhole_image(image_data:np.array, cam_I:np.array, cam_D:np.array, desire_cam_I:np.array):
    H, W = image_data.shape[:2]
    # get camera infos
    fx, fy, cx, cy = cam_I[0, 0], cam_I[1, 1], cam_I[0, 2], cam_I[1, 2]
    k1, k2, p1, p2, k3 = cam_D[:5]
    # get new camera world points
    x, y = np.meshgrid(np.arange(W), np.arange(H))
    x = (x.reshape((-1, 1)) - desire_cam_I[0, 2]) / desire_cam_I[0, 0]
    y = (y.reshape((-1, 1)) - desire_cam_I[1, 2]) / desire_cam_I[1, 1]
    z = np.ones_like(x)
    # normalize
    x = x / z
    y = y / z
    xx = x * x
    yy = y * y
    xy = x * y
    rr = xx + yy
    # Radial distortion 径向畸变
    rd_x = x * (1. + k1*rr + k2*rr*rr + k3*rr*rr*rr)
    rd_y = y * (1. + k1*rr + k2*rr*rr + k3*rr*rr*rr)
    # tangential distortion 切向畸变
    td_x = 2 * p1 * xy + p2 * (rr + 2 * xx)
    td_y = 2 * p2 * xy + p1 * (rr + 2 * yy)
    # rectified points
    r_x = rd_x + td_x
    r_y = rd_y + td_y
    # map to distored image
    map_u = (r_x * fx + cx).reshape((H, W)).astype(np.float32)
    map_v = (r_y * fy + cy).reshape((H, W)).astype(np.float32)
    img_undistored = cv2.remap(image_data, map_u, map_v, cv2.INTER_CUBIC)

    return img_undistored

2. omni-directional相机模型

全向相机是将点投影到单位球,之后再进行畸变矫正的过程,这里会使用 ξ \xi ξ进行单位球转换。对于其去畸变的过程参考代码如下:

def undistort_omni_image(image_data:np.array, cam_I:np.array, cam_D:np.array, desire_cam_I:np.array):
    H, W = image_data.shape[:2]
    # get camera infos
    fx, fy, cx, cy, xi = cam_I[0, 0], cam_I[1, 1], cam_I[0, 2], cam_I[1, 2], cam_I[0, 1]
    k1, k2, p1, p2 = cam_D[:4]
    # get new camera world points
    x, y = np.meshgrid(np.arange(W), np.arange(H))
    x = (x.reshape((-1, 1)) - desire_cam_I[0, 2]) / desire_cam_I[0, 0]
    y = (y.reshape((-1, 1)) - desire_cam_I[1, 2]) / desire_cam_I[1, 1]
    z = np.ones_like(x)
    # normalize
    rz = z + xi * np.sqrt(x*x + y*y + z*z)
    x = x / rz
    y = y / rz
    xx = x * x
    yy = y * y
    xy = x * y
    rr = xx + yy
    # Radial distortion 径向畸变
    rd_x = x * (1. + k1*rr + k2*rr*rr)
    rd_y = y * (1. + k1*rr + k2*rr*rr)
    # tangential distortion 切向畸变
    td_x = 2 * p1 * xy + p2 * (rr + 2 * xx)
    td_y = 2 * p2 * xy + p1 * (rr + 2 * yy)
    # rectified points
    r_x = rd_x + td_x
    r_y = rd_y + td_y
    # map to distored image
    map_u = (r_x * fx + cx).reshape((H, W)).astype(np.float32)
    map_v = (r_y * fy + cy).reshape((H, W)).astype(np.float32)
    img_undistored = cv2.remap(image_data, map_u, map_v, cv2.INTER_CUBIC)

    return img_undistored

ref:

  1. Omnidirectional Camera Calibration
  2. cv::omnidir::projectPoints()

3. Kannala Brandt相机模型

在该相机模型中引入射光线与主轴的夹角用于描述成像畸变,也就是偏离主轴越远畸变的程度越大,因而使用畸变参数 [ k 1 , k 2 , k 3 , k 4 ] [k_1,k_2,k_3,k_4] [k1,k2,k3,k4]与入射光线主轴夹角 θ \theta θ便可使用上述几个变量完成鱼眼相机去畸变,其去畸变的流程如下:

在这里插入图片描述
ref:

  1. Fisheye camera model

畸变去除参考代码:

def undistort_kb_image(image_data:np.array, cam_I:np.array, cam_D:np.array, desire_cam_I:np.array):
    H, W = image_data.shape[:2]
       
    fx, fy, cx, cy = cam_I[0, 0], cam_I[1, 1], cam_I[0, 2], cam_I[1, 2]
    k1, k2, k3, k4 = cam_D[:4]
    x, y = np.meshgrid(np.arange(W), np.arange(H))
    x = (x.reshape((-1, 1)) - desire_cam_I[0, 2]) / desire_cam_I[0, 0]
    y = (y.reshape((-1, 1)) - desire_cam_I[1, 2]) / desire_cam_I[1, 1]
    z = np.ones_like(x)
    # normalize
    x /= z
    y /= z
    rr = x*x + y*y
    theta = np.arctan(np.sqrt(rr))
    theta_d = theta * (1 + k1*theta*theta + k2*theta*theta*theta*theta +\
                       k3*theta*theta*theta*theta*theta*theta*theta*theta + \
                        k4*theta*theta*theta*theta*theta*theta*theta*theta*theta*theta)
    t_x = (theta_d/(np.sqrt(rr)+1.e-6)) * x
    t_y = (theta_d/(np.sqrt(rr)+1.e-6)) * y
    # map to distored image
    map_u = (t_x * fx + cx).reshape((H, W)).astype(np.float32)
    map_v = (t_y * fy + cy).reshape((H, W)).astype(np.float32)
    img_undistored = cv2.remap(image_data, map_u, map_v, cv2.INTER_CUBIC)

	return img_undistored

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

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

相关文章

Vicuna模型权重合成及模型部署

第一式:Vicuna模型部署 1.环境搭建1.1 构建虚拟环境1.2 安装FastChat1.2.1 利用pip直接安装1.2.2 从github下载repository然后安装 2.Vicuna Weights合成2.1 下载vicuna delta weights2.2 下载原始llama weights2.3 合成真正的working weights2.3 填坑手册 3. 使用命…

第九章 os模块

1. os模块介绍 os 模块是Python 内置的与操作系统中的文件系统相关的模块,该模块依赖于操作系统。通常情况下,如不特别指出,该模块提供的方法、属性在Windows 和UNIX 系统上都是可用的。其中,UNIX 系统包括Linux 和Mac OS X 说明…

软件加密类型及原理特点总结

目录 一、软件加密目的 二、加密方式介绍 2.1 硬件加密 2.2 软件加密 三、软件加密方式 3.1非对称加密算法 3.2对称加密算法 四、数字签名 五、软件破解方式 参考文献 一、软件加密目的 防止软件被复制使用并恶意破坏,给企业和个人带来经济损失。 二、加密方…

杂记 | 使用Docker和Nginx为网站添加HTTPS访问功能

文章目录 01 准备工作1.1 HTTPS介绍1.2 准备工作 02 编写nginx.conf03 使用docker启动nginx 01 准备工作 1.1 HTTPS介绍 HTTPS(Hypertext Transfer Protocol Secure)是一种通过加密通信保护网站数据传输的协议。它是 HTTP 协议的安全版本,通…

ROS下写服务

话题和服务的对比: 1.话题 话题是单向的,而且不需要等待服务端上线,直接发就行,数据的实时性比较高。 频率高,实时性强的传感器数据的传递一般使用话题实现。 话题通信是ROS中使用频率最高的一种通信模式&#xff0c…

人工智能之后,量子计算将成为下一趋势

光子盒研究院 人工智能显然是席卷科技行业的最新热潮,但一个更大的趋势可能即将到来,那就是量子计算——只要它能解决令人不安的网络安全问题。 量子计算的进展似乎注定要使今天的基于电子芯片的超级计算机逊色。这些机器在亚原子水平上工作,…

excel爬虫相关学习1:简单的excel爬虫

目录 1 什么是excel 爬虫 2 EXCEL爬虫 2.1 excel 爬虫的入口 2.2 需要配置的信息 2.2.1 如何获得 ua信息 2.3 获取的信息 2.3.1 获取信息的基本内容 2.3.2 获取过程 2.3.3 我们只用关注“表视图 ” 即可 2.4 EXCEL获得的爬虫数据 加载到excel里 2.5 数据到了excel表后…

解决关于由于找不到vcruntime140_1.dll丢失的解决方法(有效的解决方法)

vcruntime140_1.dll是什么什么文件呢?为什么电脑在运行一些游戏的时候会出现丢失vcruntime140_1.dll,然后游戏运行失败?这个dll文件是电脑重要的运行库文件。丢失了会导致很多程序无法运行。 本教程操作系统:Windows vcruntime140_1.dll丢失…

AN10834-MIFARE ISOIEC 14443 PICC selection.pdf

AN10834-MIFARE ISOIEC 14443 PICC selection.pdf 1简介 在读卡器(系统)和智能卡之间交换数据之前,必须正确选择智能卡。该卡选择过程(卡激活)在用于非接触式接近系统的ISO14443-3中进行了描述。非接触式应用的急剧增…

k8s部署成功后却显示结点一直处于NotReady状态解决方案

直接说结论:原因是服务器的/opt/cni/bin/目录中没有flannel插件,安装flannel 到/opt/cni/bin/目录下即可。具体步骤往下看。 [rootK8SMaster ~]# journalctl -f -u kubelet.service 先看下报错,发现我一直显示NotReady的原因是由于 [faile…

windows系统安装显卡驱动软件和CUDA11.1的详细教程

深度学习目标检测框架在进行图像计算时需要GPU进行加速,需要用到硬件GPU显卡,目标检测框架和硬件GPU建立联系需要通过①显卡驱动软件;②CUDA软件依次建立联系。这两个软件,可直接从NVIDIA官网下载,版本没有非常严格的需…

【玩转Linux操作】详细讲解Linux的 at定时任务

🎊专栏【玩转Linux操作】 🍔喜欢的诗句:更喜岷山千里雪 三军过后尽开颜。 🎆音乐分享【Counting Stars】 欢迎并且感谢大家指出小吉的问题🥰 文章目录 🍔基本介绍⭐怎么保证atd进程启动了 🍔at命…

Unity3D期末大作业(捕鱼达人)【免费开源】

目录 1 游戏简介 2 游戏各模块 2.1 主界面 2.2 加载界面 2.3 主游戏场景 2.4 游戏内道具 2.4.1 炮塔 2.4.2 技能 2.4.3 宝箱 2.4.4 鱼类 3 参考教程 4 项目地址 4.1 运行环境 4.2 源工程文件链接 4.3 结课报告 1 游戏简介 大部分人都玩过这个游戏吧,这…

chatgpt赋能python:使用Python来寻找两个列表不同元素的方法

使用Python来寻找两个列表不同元素的方法 在编写Python程序时,我们经常需要比较两个列表的元素,找出它们之间的不同之处。在搜索引擎优化(SEO)方面,这种比较对于找出两个网站内容的差异也非常有用。在这篇文章中&…

chatgpt赋能python:Python找出三个整数中的最大数

Python 找出三个整数中的最大数 在编程中,经常需要寻找一组数中的最大值。Python 提供了多种方法来实现此目的。本文将针对三个整数寻找最大值进行说明。 方法一:使用if语句 首先,我们可以使用if语句进行比较,找出最大值。 de…

开发日记-凌鲨中的评估体系

软件项目很难进行很好的管理,本质上是无法有效的评估项目成员的贡献,无法有效的评估技术债务。 由于人性的复杂,大多数的评估规则都能被绕过。比如: 代码行数的指标,造成大量冗余和无用代码。千行代码BUG率&#xff…

react知识点汇总一

以下是一些React中经典的知识点: 什么是React?它有哪些特点和优势? React是一个由Facebook开发的UI框架,用于构建单页面应用程序。它的特点和优势包括: 组件化:React的应用程序主要由多个组件组成&#…

【C++语法堂】STL标准库学习_list容器

目录 STL标准库学习_list 【1】List的介绍及使用 【2】List常用的接口 【2.1】构造函数 【2.2】析构函数 【2.3】迭代器相关 【2.4】容量相关 【2.5】元素访问相关 【2.6】修改相关 【2.7】运行相关 【2.8】观察相关 【2.9】非成员函数重载 【3】list模拟实现 【…

io.netty学习(六)字节缓冲区 ByteBuf(上)

目录 前言 ByteBuf类 ByteBuffer 实现原理 ByteBuffer 写入模式 ByteBuffer 读取模式 ByteBuffer 写入模式切换为读取模式 clear() 与 compact() 方法 ByteBuffer 使用案例 总结 前言 网络数据传输的基本单位是字节,缓冲区就是存储字节的容器。在存取字节…

双目结构光 实现高度测量

这里使用了两个大恒金星相机,一个投影仪。 相机镜头以及投影仪的架设: 相机镜头以及投影仪的架设: 注意相对位置的摆放,投影仪的光源照亮范围要超过相机的视野。 相机与光源调整好位置后,调整成像效果。两个镜头的光…