当前位置: 首页 > news >正文

鱼眼相机模型与去畸变实现

1.坐标系说明

鱼眼相机模型涉及到世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换关系。对于分析鱼眼相机模型,假定世界坐标系下的坐标点P_W(x_w,y_w,z_w),经过外参矩阵的变换转到相机坐标系P(x_c,y_c,z_c),相机坐标再经过内参转换到像素坐标,具体如下

进一步进行变换得到如下

坐标(i, j)位置对应的就是无畸变图中的像素坐标。

那么在已知像素坐标时,根据上述表达式就能得到归一化的相机坐标 (\bar{x_c},\bar{y_c},1).实际计算时,可以用内参矩阵求逆也可以直接变换得到。

 xw = K_matrix_inv.dot(np.array([i, j, 1], dtype=float))x_d = xw[0]y_d = xw[1]x = float(i)y = float(j)x1 = (x - cx) / fx  # 求出ud ==> x1y1 = (y - cy) / fy  # 求出vd ==> y1# x == x1, y == y1

2.opencv实现

分析opencv鱼眼矫正最重要的函数是fisheye::initUndistortRectifyMap(),它能得到map1矩阵。对应opencv-python,

map1, map2 = cv2.initUndistortRectifyMap(camera_matrix, dist_coeffs, None, new_camera_matrix, (w, h), cv2.CV_32FC1)

map1是一个2通道矩阵,它在(i, j)处的二维向量元素(u, v) = (map1(i, j)[0], map1(i, j)[1])的意义如下:
将畸变图像中(u, v) = (map1(i, j)[0], map1(i, j)[1])的元素,复制到(i, j)处,就得到了无畸变图像。

 opencv官方给出的实现过程如下:

3.去畸变理论分析

鱼眼相机的入射与反射示意图如下图所示。对于相机坐标系下有一点 P(x,y,z),如果按照针孔相机模型投影,则不存在畸变,像点为P_0(a,b),发生畸变后的像点坐标为p'

在图中,r=\parallel OP_0\parallel,r_d=\parallel Op'\parallel.

在上图中不妨假设 f = 1,最终可以求得r_d和 r 的比值(与 f无关),从而可求得去畸变后的P_0点坐标(a,b) 以及入射角 \theta. 这里的(a,b,1)实际就是对应于P_0的齐次坐标。

实际的鱼眼镜头因为各种原因并不会精确的符合投影模型,为了方便鱼眼相机的标定,一般取r_d关于\theta泰勒展开式的前5项来近似鱼眼镜头的实际投影函数。具体来说,该近似结果最早由

Juho Kannala 和 Sami S. Brandt在《A Generic Camera Model and Calibration Method for Conventional, Wide-Angle, and Fish-Eye Lenses》论文中提出了一种一般的鱼眼模型,也是opencv和一般通常使用的模型,用入射角 \theta 的奇数次泰勒展开式来进行鱼眼模型的通用表示:

                        r_d =\theta(k_0+k_1\theta^2+k_2\theta^4+k_3\theta^6+k_4\theta^8)

通常设置k_0=1,使得相应的变化在后续的含k_1,k_2,k_3,k_4高次项目中体现,由此得到

                        r_d =\theta(1+k_1\theta^2+k_2\theta^4+k_3\theta^6+k_4\theta^8)

结合发生畸变后对应的归一化相机坐标(x',y',1),可以求出(a,b).

                                \left\{\begin{matrix} u=f_xx'+c_x \\ \\ v=f_yy'+c_y \end{matrix}\right. \Rightarrow \left\{\begin{matrix} x'=(u-c_x)/f_x \\ \\ y'=(v-c_y)/f_y\end{matrix}\right.

                                                \left\{\begin{matrix} \frac{a}{r}= \frac{x'}{r_d} \\ \\ \frac{b}{r}= \frac{y'}{r_d}\end{matrix}\right.\Rightarrow \left\{\begin{matrix} a=\frac{r}{r_d}x' \\ \\ b=\frac{r}{r_d}y' \end{matrix}\right.

注意,这里的r_d\neq \theta_d,根据示意图可知,无论采用通用模型还是等距投影模型,都严格存在如下

                                                \left\{\begin{matrix} tan(\theta)= \frac{OP_0}{f}=\frac{r}{f} \\ \\ tan(\theta_d)= \frac{Op'}{f}=\frac{r_d}{f}\end{matrix}\right.

对于 f=1,则有:

                                                        \left\{\begin{matrix}\theta = arctan(r) \\ \\ \theta_d = arctan(r_d)\end{matrix}\right.

实际计算过程,都是已知无畸变的像素坐标(i,j) 推导得到畸变后的像素坐标(u,v),再借助remap函数完成像素插值。当需要通过已知的畸变像素坐标反向投影得到无畸变点的像素时,也就是已知(u,v),采用上述关系得到 (x',y') ,此时已知r_d, 需要求出对应的\theta。所以畸变矫正的本质问题是求解关于\theta 的一元高次方程

                                        r_d =\theta(1+k_1\theta^2+k_2\theta^4+k_3\theta^6+k_4\theta^8)

常见求解一元高次方程的方法有二分法、不动点迭代、牛顿迭代法。这里采用牛顿迭代法求解。

                                令 f(\theta) =\theta+k_1\theta^3+k_2\theta^5+k_3\theta^7+k_4\theta^9-r_d,

                                                                \theta_0=r_d

                                                        \theta_{n+1}=\theta_{n}-\frac{f(\theta_n)}{f'(\theta_{n})}

循环迭代直到f(\theta)\approx 0(具体精度根据需要自行设置,比如设置阈值1e-6),或达到迭代次数上限。求得 \theta 之后,未畸变像点 P_0的坐标满足

                                                        \left\{\begin{matrix} a=\frac{r}{r_d}x' \\ \\ b=\frac{r}{r_d}y' \end{matrix}\right.

详见下文4.3代码。

4.代码实现

4.1 调用opencv

def undistort_imgs_fisheye(camera_matrix, dist_coeffs,img):# 注意:OpenCV 没有直接提供逆畸变的函数,但我们可以使用 cv2.initUndistortRectifyMap 和 cv2.remap 来模拟w = int(img.shape[1])h = int(img.shape[0])border_width  = int(w/4)border_height = int(h/4)img_bordered = cv2.copyMakeBorder(img, border_height, border_height, border_width, border_width, cv2.BORDER_ISOLATED)h_new, w_new = img_bordered.shape[:2]new_camera_matrix1, roi = cv2.getOptimalNewCameraMatrix(camera_matrix, dist_coeffs[:4], (w_new, h_new), 0.5, (w, h))# 计算去畸变和逆畸变的映射map1, map2 = cv2.fisheye.initUndistortRectifyMap(camera_matrix, dist_coeffs[:4], np.eye(3), new_camera_matrix1, (w_new, h_new), cv2.CV_16SC2)#根据CV_16SC2, map1此时是一个2通道的矩阵,每个点(i, j)都是一个2维向量, u = map1(i, j)[0], v= map1(i, j)[1],畸变图中坐标为(u, v)的像素点,在无畸变图中应该处于(i, j)位置。undistort_img = cv2.remap(img_bordered, map1, map2, cv2.INTER_LINEAR, borderMode=cv2.BORDER_CONSTANT)return undistort_img

4.2 表达式实现

def undistort_imgs_fisheye_equid(params_matrix, distort, img):fx = params_matrix[0][0]fy = params_matrix[1][1]cx = params_matrix[0][2]cy = params_matrix[1][2]distortion_params = distortkk = distortion_paramswidth  = int(img.shape[1] * 1)height = int(img.shape[0] * 1)print("w is: {}, h is: {}".format(width,height))mapx = np.zeros((width, height), dtype=np.float32)mapy = np.zeros((width, height), dtype=np.float32)for i in tqdm(range(0, width), desc="calculate_maps"):for j in range(0, height):x = float(i)  #x是去畸变后的像素坐标y = float(j)  #y是去畸变后的像素坐标a = (x - cx) / fx  # x ==> ab = (y - cy) / fy  # y ==> br = np.sqrt(a**2 + b**2)theta = np.arctan2(r,1)rd = (1.0 *theta + kk[0] * theta**3 + kk[1] * theta**5 + kk[2] * theta**7 + kk[3] * theta**9)scale = rd/r if r!=0 else 1.0x2 = fx * a * scale + cx # width // 2y2 = fy *b * scale + cy # height // 2mapx[i, j] = x2mapy[i, j] = y2distorted_image = cv2.remap(img,mapx.T,mapy.T,interpolation=cv2.INTER_LINEAR,borderMode=cv2.BORDER_CONSTANT,)return distorted_image, params_matrix

4.3 反向投影


def diff(k2, k3, k4, k5, theta):theta_2 = theta * thetatheta_4 = theta_2 * theta_2theta_6 = theta_4 * theta_2theta_8 = theta_6 * theta_2rd_diff = 1 + 3 * k2 * theta_2 + 5 * k3 * theta_4 + 7 * k4 * theta_6 + 9 * k5 * theta_8return rd_diffdef distort_theta(k2, k3, k4, k5, theta):theta_2 = theta * thetatheta_3 = theta * theta_2theta_5 = theta_3 * theta_2theta_7 = theta_5 * theta_2theta_9 = theta_7 * theta_2theta_d = theta + k2 * theta_3 + k3 * theta_5 + k4 * theta_7 + k5 * theta_9return theta_ddef newton_itor_theta(k2, k3, k4, k5, r_d):theta = r_dmax_iter = 500for i in range(max_iter):diff_t0 = diff(k2, k3, k4, k5, theta)f_t0 = distort_theta(k2, k3, k4, k5, theta) - r_dtheta = theta - f_t0 / diff_t0if abs(f_t0) < 1e-6:breakreturn thetadef distort_imgs_fisheye_new(params_matrix, distort, img):undistorted_image = np.zeros((img.shape))fx = params_matrix[0][0]fy = params_matrix[1][1]cx = params_matrix[0][2]cy = params_matrix[1][2]K_matrix_inv = np.linalg.inv(params_matrix)width  = int(img.shape[1] * 1)height = int(img.shape[0] * 1)mapx = np.zeros((width, height), dtype=np.float32)mapy = np.zeros((width, height), dtype=np.float32)for i in tqdm(range(0, width), desc="calculate_maps"):for j in range(0, height):xw = K_matrix_inv.dot(np.array([i, j, 1], dtype=float))x_d = xw[0]y_d = xw[1]x = float(i)y = float(j)x1 = (x - cx) / fx  # 求出ud ==> x1y1 = (y - cy) / fy  # 求出vd ==> y1phi = np.arctan2(y_d, x_d)r_d = np.sqrt(x_d ** 2 + y_d ** 2)theta = newton_itor_theta(distort[0],distort[1],distort[2],distort[3],r_d)r = np.tan(theta)# r_d = np.tan(theta_d)a = x_d * r/r_db = y_d * r/r_du = a*fx + cxv = b*fy + cymapx[i, j] = umapy[i, j] = vreturn mapx, mapy

相关文章:

鱼眼相机模型与去畸变实现

1.坐标系说明 鱼眼相机模型涉及到世界坐标系、相机坐标系、图像坐标系、像素坐标系之间的转换关系。对于分析鱼眼相机模型&#xff0c;假定世界坐标系下的坐标点,经过外参矩阵的变换转到相机坐标系&#xff0c;相机坐标再经过内参转换到像素坐标&#xff0c;具体如下 进一步进…...

【Unity功能集】TextureShop纹理工坊(七)魔棒工具

项目源码:在终章发布 索引 魔棒工具PS魔棒工具魔棒工具功能点提炼TextureShop魔棒工具根据色差选取非连续区域中间镂空边框的流动虚线取消选区魔棒工具 魔棒工具,也既是通过颜色色差,在图像上选出自定义选区的工具(了解PS魔棒工具)。 PS魔棒工具 我们先来看看PS中的魔棒…...

ASP.NET Core Web API Hangfire

ASP.NET Core Web API Hangfire 前言一、安装二、相关代码1.代码片段2.代码片段3.运行效果 三、测试代码1.即发即弃作业2.延迟作业3.重复作业4.延续作业5.页面调度作业 前言 &#x1f468;‍&#x1f4bb;&#x1f468;‍&#x1f33e;&#x1f4dd;记录学习成果&#xff0c;以…...

E-commerce .net+React(一)——项目初始化

文章目录 项目地址一、创建.Net环境1.1环境配置1.1.1 使用vscode创建webapi1.1.2 Clean architecture结构创建1.1.3 将创建好结构的项目添加到git里1.1.4 EF Core配置1. 在infrastructure里安装EF所需环境2. 创建Product数据模型3. 创建EF Core的DbContext 数据库上下文4. 创建…...

算法每日双题精讲 —— 滑动窗口(水果成篮,找到字符串中所有字母异位词)

&#x1f31f;快来参与讨论&#x1f4ac;&#xff0c;点赞&#x1f44d;、收藏⭐、分享&#x1f4e4;&#xff0c;共创活力社区。 &#x1f31f; 别再犹豫了&#xff01;快来订阅我们的算法每日双题精讲专栏&#xff0c;一起踏上算法学习的精彩之旅吧&#xff01;&#x1f4aa;…...

C++ 设计模式:享元模式(Flyweight Pattern)

链接&#xff1a;C 设计模式 链接&#xff1a;C 设计模式 - 单例模式 享元模式&#xff08;Flyweight Pattern&#xff09;是一种结构型设计模式&#xff0c;它通过共享尽可能多的相同对象来减少内存使用和提高性能。享元模式适用于大量细粒度对象的场景&#xff0c;这些对象之…...

Docker+Portainer 离线安装

1. Docker安装 步骤一&#xff1a;官网下载 docker 安装包 步骤二&#xff1a;解压安装包; tar -zxvf docker-24.0.6.tgz 步骤三&#xff1a;将解压之后的docker文件移到 /usr/bin目录下; cp docker/* /usr/bin/ 步骤四&#xff1a;将docker注册成系统服务; vim /etc/sy…...

Linux第100步_Linux之设置LCD作为终端控制台和LCD背光调节

KMS是Kemmel Mode Setting的缩写&#xff0c;内核显示模式设置。它主要负责显示的控制&#xff0c;包括屏幕分辨率、屏幕刷新率和颜色深度等等。 CRTC是指显示控制器&#xff0c;在DRM里有多个显存&#xff0c;通过操作CRTC来控制要显示那个显存。 KMS包含了FB框架。DRM驱动默…...

Chapter09 国际化i18n 和 数据校验:Validation

文章目录 1 Java国际化2 Spring6国际化3 使用Spring6国际化4 数据校验&#xff1a;Validation实验一&#xff1a;通过Validator接口实现实验二&#xff1a;Bean Validation注解实现实验三&#xff1a;基于方法实现校验实验四&#xff1a;实现自定义校验 1 Java国际化 示例&…...

活动预告 | Microsoft 安全在线技术公开课:通过扩展检测和响应抵御威胁

课程介绍 通过 Microsoft Learn 免费参加 Microsoft 安全在线技术公开课&#xff0c;掌握创造新机遇所需的技能&#xff0c;加快对 Microsoft Cloud 技术的了解。参加我们举办的“通过扩展检测和响应抵御威胁”技术公开课活动&#xff0c;了解如何更好地在 Microsoft 365 Defen…...

Unresolved plugin: ‘org.apache.maven.plugins:maven-site-plugin:3.12.1‘

问题 使用idea 社区办加载项目提示下面问题&#xff1a; Unresolved plugin: org.apache.maven.plugins:maven-site-plugin:3.12.1 问题解决 maven插件地址&#xff1a; https://maven.apache.org/plugins/maven-dependency-plugin/plugins.html Maven 中央仓库地址&#…...

5个开源RAG框架对比

还在为RAG应用开发头疼吗&#xff1f;别急&#xff0c;今天给大家推荐五款完全开源免费的RAG框架&#xff0c;覆盖自动优化、多模态处理、本地部署、生产环境支持等多种场景&#xff0c;助你轻松搞定RAG开发&#xff01;&#x1f447; 1. AutoRAG&#xff1a;自动优化&#xff…...

活动预告 | Microsoft Power Platform 在线技术公开课:实现业务流程自动化

课程介绍 参加“Microsoft Power Platform 在线技术公开课&#xff1a;实现业务流程自动化”活动&#xff0c;了解如何更高效地开展业务。参加我们举办的本次免费培训活动&#xff0c;了解如何借助 Microsoft AI Builder 和 Power Automate 优化工作流。结合使用这些工具可以帮…...

【分布式文件存储系统Minio】2024.12保姆级教程

文章目录 1.介绍1.分布式文件系统2.基本概念 2.环境搭建1.访问网址2.账号密码都是minioadmin3.创建一个桶4.**Docker安装miniomc突破7天限制**1.拉取镜像2.运行容器3.进行配置1.格式2.具体配置 4.查看桶5.给桶开放权限 3.搭建minio模块1.创建一个oss模块1.在sun-common下创建2.…...

解决ssh和git秘钥认证失败问题

已正确上传公钥到远程服务器&#xff0c;但是本地的连接认证还是使用默认秘钥文件名id_rsa或者默认用户名&#xff0c;导致了认证失败&#xff0c;总结了以下解决办法&#xff1a; 1、ssh秘钥认证 远程登录的时候可能ssh客户端默认使用id_rsa文件名秘钥&#xff0c;但是之前生…...

AI安全的挑战:如何让人工智能变得更加可信

引言 随着人工智能&#xff08;AI&#xff09;技术在各个领域的广泛应用&#xff0c;尤其是在医疗、金融、自动驾驶和智能制造等行业&#xff0c;AI正在重塑我们的工作和生活方式。从提高生产效率到实现个性化服务&#xff0c;AI带来了前所未有的便利。然而&#xff0c;在享受这…...

腾讯通RTX升级迁移攻略,兼容Linux内核国产系统及移动端

一、腾讯通RTX继续使用的主要难题 腾讯通RTX停更后&#xff0c;用户不仅无法继续获得更新、技术支持和资源下载&#xff0c;还面临着以下无法解决的使用问题&#xff1a; ● 不兼容国产系统与移动端&#xff1a;腾讯通RTX仅支持Windows和Mac操作系统&#xff0c;无法在基于Li…...

用css实现瀑布流布局

上效果 知识理解 column-count: 4; column-gap: 15px;实现固定四行瀑布流布局 columns: 200px auto;column-gap: 15px;由浏览器根据容器的宽度自动调整&#xff0c;尽可能一行多个200px宽度的列数 <!DOCTYPE html> <html lang"en"><head><me…...

FortiAl为擎重塑网络与安全运营未来

在当今数字化浪潮汹涌的时代&#xff0c;网络安全运营的重要性愈发凸显&#xff0c;而人工智能的迅猛发展则如同一股强劲的东风&#xff0c;为这一领域带来了革命性的变革。Fortinet攻防专家邹国雄在《FortiAI&#xff1a;以生成式人工智能&#xff08;GenAI&#xff09;简化Fo…...

优化租赁小程序提升服务效率与用户体验的策略与实践

内容概要 在这个快速发展的商业环境中&#xff0c;租赁小程序成为了提升服务效率和用户体验的重要工具。通过对用户需求的深入挖掘&#xff0c;我们发现他们对于功能的便捷性、响应速度和界面的友好性有着极高的期待。因此&#xff0c;针对这些需求&#xff0c;完善租赁小程序…...

OpenClaw+Qwen3.5-9B智能爬虫:合规数据采集与结构化存储方案

OpenClawQwen3.5-9B智能爬虫&#xff1a;合规数据采集与结构化存储方案 1. 为什么需要智能爬虫&#xff1f; 去年我接手了一个市场调研项目&#xff0c;需要从30多个电商平台抓取商品价格和评论数据。传统爬虫开发让我吃尽苦头——每个网站结构不同&#xff0c;反爬策略各异&…...

2026知识付费SaaS平台实测对比:创客匠人综合首选,拆解行业标杆的硬核实力

随着知识付费市场规模持续扩张&#xff0c;艾媒咨询数据显示&#xff0c;2026年中国知识付费市场规模将突破3000亿元&#xff0c;用户规模超6.4亿人。面对激烈的竞争&#xff0c;如何选择一款功能全面、稳定可靠的SaaS平台成为内容创作者和机构的核心痛点。功能卡顿、获客成本高…...

Linux网络驱动实验

直接参考【正点原子】I.MX6U嵌入式Linux驱动开发指南V1.81 本文仅作为个人笔记使用&#xff0c;方便进一步记录自己的实践总结。 网络驱动是 linux 里面驱动三巨头之一&#xff0c;linux 下的网络功能非常强大&#xff0c;嵌入式 linux 中也常常用到网络功能。前面我们已经讲过…...

如何用Synonyms实现智能问答系统:面向初学者的完整指南

如何用Synonyms实现智能问答系统&#xff1a;面向初学者的完整指南 【免费下载链接】Synonyms :herb: 中文近义词&#xff1a;聊天机器人&#xff0c;智能问答工具包 项目地址: https://gitcode.com/gh_mirrors/sy/Synonyms Synonyms是一个强大的中文近义词工具包&#…...

如何用OHHTTPStubs彻底改变iOS网络测试:从入门到精通的完整指南

如何用OHHTTPStubs彻底改变iOS网络测试&#xff1a;从入门到精通的完整指南 【免费下载链接】OHHTTPStubs AliSoftware/OHHTTPStubs: OHHTTPStubs是一个iOS和macOS的Objective-C和Swift库&#xff0c;用于在单元测试或者开发阶段模拟网络请求。它允许开发者设置HTTP stubs&…...

ANDON系统赋能自行车制造实现异常闭环管理

传统自行车制造业面临着多工位协同效率低、异常响应滞后等痛点。以某自行车制造工厂为例&#xff0c;其生产线涵盖车架组装、轮组调试、整车检测等多环节&#xff0c;传统异常管理存在响应滞后、协同混乱、数据缺失三大瓶颈。引入ANDON系统后&#xff0c;通过构建“工位触发-网…...

手把手教你实现西门子1200自动洗车博途仿真 自动洗车博图PLC程序洗车机控制HMI组态

西门子1200自动洗车博途仿真 自动洗车博图PLC程序洗车机控制HMI组态 、商品包含内容&#xff1a;①三种液体博途PLC与HMI仿真工程?(博途V14或以上) 一份&#xff1b;②三种液体配套有IO点表PLC接线图主电路图控制流程图 (CAD源文件可编辑);③三种液体博途仿真工程配套视频讲解…...

CloudCompare点云处理实战指南(一):从基础操作到高程赋色

1. 初识CloudCompare&#xff1a;点云处理的瑞士军刀 第一次打开CloudCompare时&#xff0c;你可能和我当初一样被满屏的英文界面吓到。但别担心&#xff0c;这款开源软件就像点云界的Photoshop&#xff0c;功能强大却容易上手。我处理过上千个激光雷达扫描项目&#xff0c;从建…...

基于MATLAB与机器学习(SVM)的裂缝检测识别系统,附GUI界面、特征参数计算与Excel...

基于MATLAB和机器学习&#xff08;向量机&#xff09;的裂缝检测&#xff08;识别&#xff09;系统程序&#xff0c;带GUI界面&#xff0c;对裂缝主要参数&#xff08;长度&#xff0c;宽度&#xff0c;面积&#xff09;进行计算&#xff0c;已经训练好分类器&#xff0c;包含裂…...

android studio panda3 配置镜像链接失败,求教

安装了android studio panda3 配置镜像如下&#xff1a;buildscript {repositories {maven { url https://maven.aliyun.com/nexus/content/groups/public/ }maven { url https://maven.aliyun.com/repository/public/ }maven { url https://maven.aliyun.com/repository/googl…...