双目视觉:reprojectImageTo3D函数

前言

reprojectImageTo3D 是 OpenCV 中用于从视差图生成三维点云的函数。它的原理是利用视差图和相机的校准参数,通过三角测量法,计算每个像素对应的三维坐标。以下内容根据源码分析所写,觉得可以的话,点赞收藏哈!!

一、基础知识

齐次坐标:齐次坐标是一种数学表示方法,它在计算机图形学和计算机视觉中被广泛使用,特别是在处理3D空间中的点和变换时。齐次坐标的主要作用有以下几点:

  • 统一表示:齐次坐标允许我们使用一个统一的表示方法来处理点和向量。在笛卡尔坐标系中,点和向量是不同的概念,但通过引入齐次坐标,我们可以将它们表示为相同的形式。例如,一个3D点(x,y,z)可以表示为齐次坐标(x,y,z,1),而一个3D向量(a,b,c)可以表示为齐次坐标(a,b,c,0)。
  • 简化变换:齐次坐标简化了3D空间中的线性变换,如旋转、平移和缩放。在笛卡尔坐标系中,平移不能通过矩阵乘法来表示(矩阵大小💥💥💥),但通过引入齐次坐标,平移可以表示为一个4x4矩阵与齐次坐标向量的乘法。例如,一个平移变换T=(tx​,ty​,tz​)可以表示为以下矩阵:

视差图:在立体视觉系统中,两个相机(称为立体相机)被放置在一定的距离(称为基线)上,同时拍摄同一场景。由于两个相机的位置不同,它们拍摄到的同一物体在两个图像中的位置会有所不同。这种位置差异就是视差(Xr-Xl💥💥💥)。视差图的大小等于图像大小,最大值为1024,最小值为0。

二、推导过程

(1)双目相机的坐标系

在双目视觉中,两个相机的几何模型如下:

  • 左相机的光心位于原点 [0,0,0]其像平面位于 Z=f。 
  • 右相机的光心位于 [Tx,0,0],即两个相机光心的水平基线距离为 Tx​。 
  • 像素点 (x,y) 是在左图像的像素坐标系中的位置,d=xleft−xright是视差。

(2)齐次坐标的引入

为了方便将像素坐标 (x,y)和视差 d直接映射到三维空间,引入齐次坐标系。齐次坐标将三维点扩展为四维表示:[X, Y, Z, W]。其中, [X/W,Y/W,Z/W]是三维坐标,W 是归一化因子。重点内容哈! 仅此一家哈!!💥💥💥

(3)数学公式

使用重投影矩阵 Q 与齐次坐标(x,y,d,1) 进行矩阵乘法。这一步将2D点转换为3D空间中的一个点。将得到的4维向量(X,Y,Z,W) 归一化,即除以 W 分量,得到3D空间中的点(X/W,Y/W,Z/W)。

三、源码

void cv::reprojectImageTo3D( InputArray _disparity,OutputArray __3dImage, InputArray _Qmat,bool handleMissingValues, int dtype )
{CV_INSTRUMENT_REGION();Mat disparity = _disparity.getMat(), Q = _Qmat.getMat();int stype = disparity.type();CV_Assert( stype == CV_8UC1 || stype == CV_16SC1 ||stype == CV_32SC1 || stype == CV_32FC1 );CV_Assert( Q.size() == Size(4,4) );if( dtype >= 0 )dtype = CV_MAKETYPE(CV_MAT_DEPTH(dtype), 3);if( __3dImage.fixedType() ){int dtype_ = __3dImage.type();CV_Assert( dtype == -1 || dtype == dtype_ );dtype = dtype_;}if( dtype < 0 )dtype = CV_32FC3;elseCV_Assert( dtype == CV_16SC3 || dtype == CV_32SC3 || dtype == CV_32FC3 );__3dImage.create(disparity.size(), dtype);Mat _3dImage = __3dImage.getMat();const float bigZ = 10000.f;Matx44d _Q;Q.convertTo(_Q, CV_64F);int x, cols = disparity.cols;CV_Assert( cols >= 0 );std::vector<float> _sbuf(cols);std::vector<Vec3f> _dbuf(cols);float* sbuf = &_sbuf[0];Vec3f* dbuf = &_dbuf[0];double minDisparity = FLT_MAX;// NOTE: here we quietly assume that at least one pixel in the disparity map is not defined.// and we set the corresponding Z's to some fixed big value.if( handleMissingValues )cv::minMaxIdx( disparity, &minDisparity, 0, 0, 0 );for( int y = 0; y < disparity.rows; y++ ){float* sptr = sbuf;Vec3f* dptr = dbuf;if( stype == CV_8UC1 ){const uchar* sptr0 = disparity.ptr<uchar>(y);for( x = 0; x < cols; x++ )sptr[x] = (float)sptr0[x];}else if( stype == CV_16SC1 ){const short* sptr0 = disparity.ptr<short>(y);for( x = 0; x < cols; x++ )sptr[x] = (float)sptr0[x];}else if( stype == CV_32SC1 ){const int* sptr0 = disparity.ptr<int>(y);for( x = 0; x < cols; x++ )sptr[x] = (float)sptr0[x];}elsesptr = disparity.ptr<float>(y);if( dtype == CV_32FC3 )dptr = _3dImage.ptr<Vec3f>(y);for( x = 0; x < cols; x++){double d = sptr[x];Vec4d homg_pt = _Q*Vec4d(x, y, d, 1.0);dptr[x] = Vec3d(homg_pt.val);dptr[x] /= homg_pt[3];if( fabs(d-minDisparity) <= FLT_EPSILON )dptr[x][2] = bigZ;}if( dtype == CV_16SC3 ){Vec3s* dptr0 = _3dImage.ptr<Vec3s>(y);for( x = 0; x < cols; x++ ){dptr0[x] = dptr[x];}}else if( dtype == CV_32SC3 ){Vec3i* dptr0 = _3dImage.ptr<Vec3i>(y);for( x = 0; x < cols; x++ ){dptr0[x] = dptr[x];}}}
}

四、总结

像素坐标到三维点

  • 像素坐标 (x,y)和视差 d 提供了物体的二维位置和深度信息。 
  • 重投影矩阵 Q将这些信息通过矩阵运算映射到三维空间。 

视差与深度关系

  • 视差 d 越大,深度 Z 越小(物体越近。 
  • 齐次坐标中的 W 用于归一化三维坐标。

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

苍穹外卖04——Redis初入门 在店铺打烊or营业状态管理功能中的使用

Redis入门 redis简介 它以键值对的形式存储数据在内存中,并且以极高的性能和灵活性而著称,通常用于缓存、消息代理以及持久化数据。 - 基于内存存储,读写性能高- 适合存储热点数据(热点商品、资讯、新闻)- 企业应用广泛Windows版下载地址:https://github.com/microsoft…

No.1十六届蓝桥杯备战|第一个C++程序|cin和cout|命名空间

第一个C程序 基础程序 使用DevC5.4.0 写一个C程序 在屏幕上打印hello world #include <iostream> using namespace std;int main() {cout << "hello world" << endl;return 0; } 运行这个C程序 F9->编译 F10->运行 F11->编译运行 mai…

springboot实战(19)(条件分页查询、PageHelper、MYBATIS动态SQL、mapper映射配置文件、自定义类封装分页查询数据集)

引言&#xff1a; 该类博客的学习是基于b站黑马视频springbootvue视频学习&#xff01;具体围绕项目——"大事件"进行实战学习。 目录 一、功能介绍&#xff08;需求&#xff09;。 1、文章列表功能基本介绍。 2、条件分页查询功能与注意。 3、前端页面效果。&#x…

LoRA微调系列笔记

系列文章目录 第一章&#xff1a;LoRA微调系列笔记 第二章&#xff1a;Llama系列关键知识总结 第三章&#xff1a;LLaVA模型讲解与总结 文章目录 系列文章目录LoRA&#xff1a;Low-Rank Adaptation of Large Language Models目的&#xff1a;依据&#xff1a;优势&#xff1a;…

Python - 游戏:飞机大战;数字华容道

Pygame是一个利用SDL库的写的游戏库&#xff0c;SDL呢&#xff0c;全名Simple DirectMedia Layer&#xff0c;是一位叫做Sam Lantinga的大牛写的 SDL是用C写的&#xff0c;不过它也可以使用C进行开发&#xff0c;当然还有很多其它的语言&#xff0c;Pygame就是Python中使用它的…

【JVM】总结篇-字节码篇

字节码篇 Java虚拟机的生命周期 JVM的组成 Java虚拟机的体系结构 什么是Java虚拟机 虚拟机&#xff1a;指以软件的方式模拟具有完整硬件系统功能、运行在一个完全隔离环境中的完整计算机系统 &#xff0c;是物理机的软件实现。常用的虚拟机有VMWare&#xff0c;Visual Box&…

GitHub 及 GitHub Desktop 详细使用教程(通俗易懂)

目录 Δ前言 一、Github教程 1.什么是Github&#xff1f; 2.仓库和对仓库的操作&#xff1a; 2.1 Repository&#xff08;仓库&#xff09; 2.2 Fork&#xff08;派生&#xff09; 2.3 Star&#xff08;收藏&#xff09; 2.4 Watch&#xff08;追番&#xff09; 2.5 Issue&am…

OpenLinkSaas使用手册-待办事项和通知中心

在OpenLinkSaas工作台上&#xff0c;你可以查看待办事项和未读通知。 待办事项 目前待办事项支持: 个人待办项目待办:在项目中指派给你的任务/缺陷Git待办:在Git仓库中指标给你的Issue,目前只有在AtomGit和Gitee账号登录时才支持。 通知中心 通知中心支持Git通知和邮件通知两种…

springboot集成阿里云短信服务

springboot集成阿里云短信服务 一.阿里云账号准备 流程:注册阿里云账号>短信服务>新增资质>新建签名>新建模版>申请秘钥>用代码测试 1.注册阿里云账号 2、登录成功后&#xff0c; ① 在首页搜索短信服务 ② 打开第一个搜索结果 ③ 免费开通 ④ 可以根据…

试题转excel;word转excel;大风车excel(1.1更新)

最近更新了大风车excel1.1版本 主要优化在算法层面&#xff1a; 1.0版本试题解析的成功率为95%&#xff0c;现在1.1版本已经优化到解析成功率为99% 一、问题描述 一名教师朋友&#xff0c;偶尔会需要整理一些高质量的题目到excel中 以往都是手动复制搬运&#xff0c;几百道…

python实现自动登录12306抢票 -- selenium

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 python实现自动登录12306抢票 -- selenium 前言其实网上也出现了很多12306的代码&#xff0c;但是都不是最新的&#xff0c;我也是从网上找别人的帖子&#xff0c;看B站视频&…

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型

机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型 目录 机器学习之正则化惩罚和K折交叉验证调整逻辑回归模型1 过拟合和欠拟合1.1 过拟合1.2 欠拟合 2 正则化惩罚2.1 概念2.2 函数2.3 正则化种类 3 K折交叉验证3.1 概念3.2 图片理解3.3 函数导入3.4 参数理解 4 训练模型K折交…

文件本地和OSS上传

这里写目录标题 前端传出文件后端本地存储阿里云OSS存储上传Demo实现上传ConfigurationProperties 前端传出文件 <!DOCTYPE html> <html lang"en"> <head><meta charset"UTF-8"><title>上传文件</title> </head&g…

《Vue3实战教程》37:Vue3生产部署

如果您有疑问&#xff0c;请观看视频教程《Vue3实战教程》 生产部署​ 开发环境 vs. 生产环境​ 在开发过程中&#xff0c;Vue 提供了许多功能来提升开发体验&#xff1a; 对常见错误和隐患的警告对组件 props / 自定义事件的校验响应性调试钩子开发工具集成 然而&#xff…

python制作打字小游戏

import pygame # 导入游戏模块 安装pygame import sys # 导入系统指令模块 import random # 导入随机数模块 pygame.init() #初始化游戏环境 wndpygame.display.set_mode((800,565)) #指定窗口大小 pygame.mixer.music.load(素材/SurvivalGame.mp3) #素…

抖音短视频矩阵系统源码开发全流程解析

在项目开发过程中&#xff0c;调整配置文件至关重要&#xff0c;这些文件包括数据库连接、API密钥及全局参数等。通过正确配置这些信息&#xff0c;可确保应用程序的稳定性和安全性。灵活调整配置以适应具体需求有助于短视频矩阵系统项目的顺利推进。 在开发环境中&#xff0c…

前端路由layout布局处理以及菜单交互(三)

上篇介绍了前端项目部署以及基本依赖的应用&#xff0c;这次主要对于路由以及布局进行模块化处理 一、 创建layout模块 1、新建src/layout/index.vue <template><el-container class"common-layout"><!-- <el-aside class"aside">&l…

戴尔/Dell 电脑按什么快捷键可以进入 Bios 设置界面?

BIOS&#xff08;基本输入输出系统&#xff09;是计算机硬件与操作系统之间的桥梁&#xff0c;它负责初始化和测试系统硬件组件&#xff0c;并加载启动操作系统。在某些情况下&#xff0c;如调整启动顺序、更改系统时间或日期、修改硬件配置等&#xff0c;您可能需要进入BIOS进…

《从入门到精通:蓝桥杯编程大赛知识点全攻略》(一)-递归实现指数型枚举、递归实现排列型枚举

本篇博客将聚焦于通过递归来实现两种经典的枚举方法&#xff1a;指数型枚举和排列型枚举。这两种枚举方式在计算机科学和算法竞赛中都有广泛应用&#xff0c;无论是在解题中&#xff0c;还是在实际工作中都极具价值。 目录 前言 斐波那契数列递归 递归实现指数型枚举 算法思…

idea 的 springboot项目spring-boot-devtools 自动编译 配置热部署

1&#xff0c;设置一 2&#xff0c;设置二 设置二&#xff08;旧版本&#xff09; CtrlShiftAlt/ 点击弹出框中Registry... 引入&#xff08;如果报错&#xff0c;换不同的版本&#xff09; <dependency><groupId>org.springframework.boot</groupId><a…