深度图和RGB图对齐
坐标系间的转换_坐标系转换-CSDN博客
深度图与彩色图的配准与对齐_彩色 深度 配准-CSDN博客
kinect 2.0 SDK学习笔记(四)--深度图与彩色图对齐_mapdepthframetocolorspace-CSDN博客
相机标定(三)-相机成像模型_相机小孔成像模型-CSDN博客
1.原理部分
立体视觉往往会设计到:世界坐标系、相机坐标系、图像坐标系和像素坐标系。
世界坐标系是为了更好的描述相机的位置,双目立体视觉中一般将世界坐标系原点定在左相机或者右相机又或者两者x轴方向的中点。
①首先从世界坐标系到相机坐标系
世界坐标系中的某一个点通过平移旋转可以获得相机坐标系的位置。
详细推理请看第一篇博客。
②从相机坐标系到图像坐标系,透视变换,从3d到2d,投影点的单位是mm,将它转换到像素坐标系单位才会变成pixel。
图像坐标系的原点为相机光轴与成像平面的交点,通常情况下是成像平面的中点或者叫principal point。图像坐标系的单位是mm,属于物理单位,而像素坐标系的单位是pixel。
一个三维中的坐标点,的确可以在图像中找到一个对应的像素点,但是反过来,通过图像中的一个点找到它在三维中对应的点就很成了一个问题,因为我们并不知道等式左边的Zc的值。
2.深度图和彩色图的配准
深度图和彩色图的配准又叫对齐,之所以需要进行配准,是因为深度图中的坐标点是在深度相机坐标系下获得,彩色图的坐标点是在RGB相机坐标系下获得的。
需要先使用张正友标定等标定法,对深度相机和RGB相机分别进行标定,获得相机的内外参矩阵。
设P_ir为在深度摄像头坐标下某点的空间坐标,p_ir为该点在像平面上的投影坐标(x、y单位为像素,z等于深度值,单位为毫米),H_ir为深度摄像头的内参矩阵,由小孔成像模型可知:(公式一)
小孔成像模型实际上是透视投影(perspective projection)的一种最简单的形式。假设我们要将真实世界中的三维点( X , Y , Z ) 投影为二维图像上的点p = ( x , y ) 则有:
设P_rgb为在RGB摄像头坐标下同一点的空间坐标,p_rgb为该点在RGB像平面上的投影坐标,H_rgb为RGB摄像头的内参矩阵。由于深度摄像头的坐标和RGB摄像头的坐标不同,他们之间可以用一个旋转平移变换联系起来,即:(公式二)
其中R为旋转矩阵,T为平移向量。最后再用H_rgb对P_rgb投影,即可得到该点对应的RGB坐标(空间坐标到像素坐标的关系):(公式三)
p_ir和p_rgb使用的都是齐次坐标,在构造p_ir时,应将原始的像素坐标(x,y)乘以深度值,而最终的RGB像素坐标必须将p_rgb除以z分量,即(x/z,y/z),且z分量的值即为该点到RGB摄像头的距离(单位为毫米)。
如何求联系两个坐标系的旋转矩阵和平移向量。这就要用到摄像头的外参了。
外参矩阵实际上也是由一个旋转矩阵R_ir(R_rgb)和平移向量T_ir(T_rgb)构成的,它表示将一个世界坐标系下的点P变换到摄像头坐标系下,分别对深度摄像头和RGB摄像头进行变换,有以下关系:(公式四) 世界坐标系与相机坐标系的关系,用到外参矩阵。
上式中先将P用P_ir、R_ir和T_ir的表达式表示,再代入第二个公式,可得:
上式可以看出,这是在将P_ir变换为P_rgb,对比之前的式子:
可以求出:
这就是最终两个深度相机坐标系和RGB坐标系之间的坐标转换关系,就是博客三中获得的关系式,但是当时看他的博客,没看懂它是怎么出来的公式,现在才明白。建议大家看第二篇博客更好懂一点,但是每个人理解能力不一样,说不定有的人看第三篇更好懂,个人看法。
小孔成像模型:
因此,我们只需在同一场景下,得到棋盘相对于深度摄像头和RGB摄像头的外参矩阵,即可算出联系两摄像头坐标系的变换矩阵(注意,所有旋转矩阵都是正交阵,因此可用转置运算代替求逆运算)。虽然不同场景下得到的外参矩阵都不同,计算得到的R和T也有一些变化。
import cv2
import numpy as np
import oppenni as opp
from openni import openni2dframe_data = cv2.imread('depth.png',)
frame = cv2.imread('frame.png')#
#dframe_data = np.array(frame.get_buffer_as_triplet()).reshape([480, 640, 2])
dpt1 = np.asarray(dframe_data[:, :, 0], dtype='float32')
dpt2 = np.asarray(dframe_data[:, :, 1], dtype='float32')dpt2 *= 255
#对于为什么要乘于255的解答
#深度图像的深度值 是按照16位长度(两字节)的数据格式存储的,也可以认为前八位是高字节,后八位是低字节。
#因此一张深度图像如果是 640480分辨率的话,那么图像字节大小 就是 640480*2,其中一个字节是8位(255)
# 乘以 255 是为了将低字节部分从0-255的范围转换到0-65535的范围,这样就可以与高字节部分相加得到完整的16位深度值
dpt = dpt1 + dpt2
#cv2里面的函数,就是类似于一种筛选
'假设我们需要让我们的深度摄像头感兴趣的距离范围有差别地显示,那么我们就需要确定一个合适的alpha值,公式为:有效距离*alpha=255,' \
'假设我们想让深度摄像头8m距离内的深度被显示,>8m的与8m的颜色显示相同,那么alpha=255/(8*10^3)≈0.03,' \
'假设我们想让深度摄像头6m距离内的深度被显示,>6m的与6m的颜色显示相同,那么alpha=255/(6*10^3)≈0.0425'
cv2.imshow('depth_src', dpt)
dim_gray = cv2.convertScaleAbs(dpt, alpha=0.17)
#对深度图像进行一种图像的渲染,目前有11种渲染方式,大家可以逐一去试下
depth_colormap = cv2.applyColorMap(dim_gray, 2) # 有0~11种渲染的模式
cv2.imshow('depth', depth_colormap)
ret, frame = cap.read()
cv2.imshow('color', frame)key = cv2.waitKey(1)
if int(key) == ord('q'):break # rgb相机的内参矩阵(旋转矩阵 平移矩阵) 相机坐标系到图像坐标系
RK_rgb = np.array([(0.999993, 0.00372933, -0.000414306), (-0.00372927, 0.999993, 0.000135122), (0.000414807, -0.000133576, 1)])
#TK_rgb = np.array([-0.0148581, -8.0544e-05, 2.60393e-05])# 深度相机的内参矩阵
RK_dep = np.array([(0.999993, 0.00372933, -0.000414306), (-0.00372927, 0.999993, 0.000135122), (0.000414807, -0.000133576, 1)])
#TK_dep = np.array([-0.0148581, -8.0544e-05, 2.60393e-05])# rgb相机的外参矩阵(旋转矩阵 平移矩阵) 世界坐标系到相机坐标系
R_rgb = np.array([(0.999993, 0.00372933, -0.000414306), (-0.00372927, 0.999993, 0.000135122), (0.000414807, -0.000133576, 1)])
T_rgb = np.array([-0.0148581, -8.0544e-05, 2.60393e-05])# 深度相机的外参矩阵
R_dep = np.array([(0.999993, 0.00372933, -0.000414306), (-0.00372927, 0.999993, 0.000135122), (0.000414807, -0.000133576, 1)])
T_dep = np.array([-0.0148581, -8.0544e-05, 2.60393e-05])Rir_rgb = np.dot(R_rgb @ np.linalg.inv(R_dep)) # 两个相机坐标系之间的变换矩阵
Tir_rgb = T_rgb-R_rgb@np.linalg.inv(R_dep)@T_dep
R = RK_rgb@Rir_rgb@np.linalg.inv(RK_dep) # 像素点之间的变换关系矩阵
T = RK_rgb@Tir_rgb# 形状
result = np.zeros((dpt.shape[0], dpt.shape[1], 3), dtype=np.uint8)
i = 0
# 遍历的深度图 深度图在rgb图上对齐 找到对应的像素点
for row in range(dpt.shape[0]):for col in range(dpt.shape[1]):depth_value = dpt[row, col] # 获取深度值if depth_value != 0 and depth_value != 65535:# 投影到彩色坐标系上的坐标uv_depth = np.array([col, row, 1.0]) # 齐次坐标 uv_color = depth_value / 1000.0 * np.dot(R, uv_depth) + T / 1000.0 # Z_rgb*p_rgb=R*Z_ir*p_ir+T;; (除以1000,是为了从毫米变米) 深度坐标系下的其次标点加上旋转平移获得egb坐标系下的点print("uv_color is:", uv_color, '\n', uv_color.shape)X = int(uv_color[0] / uv_color[2]) # 除以齐次坐标的最后一个元素获得像素值Y = int(uv_color[1] / uv_color[2]) # // Z_rgb*p_rgb -> p_rgbif 0 <= X < frame.shape[0] and 0 <= Y < frame.shape[1]:result[row, col] = frame[Y, X]else:result[row, col] = [0, 0, 0]i += 1
cv2.imwrite(save_path+'registrationResult.png', result)
cv2.imwrite(save_path+'src_depth.png', dpt)
cv2.imwrite(save_path+'color_depth.png', depth_colormap)
cv2.imwrite(save_path+'rgb.png', frame)
代码是根据其他博客和相关技术写的,还未进行测试,如果有什么问题,大家可以提出来,马上修改。
相关文章:

深度图和RGB图对齐
坐标系间的转换_坐标系转换-CSDN博客 深度图与彩色图的配准与对齐_彩色 深度 配准-CSDN博客 kinect 2.0 SDK学习笔记(四)--深度图与彩色图对齐_mapdepthframetocolorspace-CSDN博客 相机标定(三)-相机成像模型_相机小孔成像模型…...
滑动窗口与TCP的缓冲区(buff)的关系
滑动窗口与TCP的缓冲区(buff)有直接关联。 滑动窗口机制是TCP协议中用于流量控制和拥塞控制的重要机制。滑动窗口实际上是一个操作系统开辟的缓存空间,用于指定无需等待确认应答即可继续发送数据的最大值。这个窗口大小(win&…...

一款好用的搜索软件——everthing(搜索比文件资源管理器快)
everthing官网链接 在官网选择下载 1.下载后双击打开 2.点击OK(需要其他语言自己选择) 3.选择安装位置(路径最好别带中文和空格) 继续点击下一步 4. 点击下一步 5.继续点击安装 6.然后就完成了 7.点击打开然后就可以搜索了...
C#WPF的App.xaml启动第一个窗体的3种方式
WPF的App.xaml启动第一个窗体的3种方式 1.使用App.xaml的StartupUri属性启动(推荐使用) 在App.xaml文件中,你可以设置StartupUri属性来指定启动时显示的第一个窗口: <Application x:Class"浅看一眼WPF.App"xmlns&…...

【JAVA毕设】基于JAVA的酒店管理系统
一、项目介绍 本系统前端框架采用了比较流行的渐进式JavaScript框架Vue.js。使用Vue-Router实现动态路由,Ajax实现前后端通信,Element-plus组件库使页面快速成型。后端部分:采用SpringBoot作为开发框架,同时集成MyBatis、Redis、…...
聚类--机器学习西瓜书阅读笔记(六)
无监督学习:通过对无标记训练样本的学习,揭示数据内在规律和性质。 聚类试图将数据集中的样本划分为若干不相交的子集,聚类过程自动形成簇结构,簇对应的语义需要子集命名把握。 聚类过程可以作为单独的过程,寻找数据…...

OpenHarmony(1)开发环境搭建
一:开源项目 OpenHarmony是由开放原子开源基金会(OpenAtom Foundation)孵化及运营的开源项目,目标是面向全场景、全连接、全智能时代,基于开源的方式,搭建一个智能终端设备操作系统的框架和平台࿰…...

Triton服务在ASR语音识别系统中的实现
Triton服务在ASR语音识别系统中的实现 一、引言二、环境准备1. 硬件环境2. 软件环境 三、模型选择与训练1. 数据准备2. 模型架构3. 模型训练 四、模型转换与优化1. 模型转换2. 模型优化 五、配置Triton服务1. 安装Triton服务2. 创建模型仓库 一、引言 自动语音识别(…...

Typora一款极简Markdown文档编辑、阅读器,实时预览,所见即所得,多主题,免费生成序列号!
文章目录 Typora下载安装Typora序列号生成 Typora是一款Markdown编辑器和阅读器,风格极简,实时预览,所见即所得,支持MacOS、Windows、Linux操作系统,有图片和文字、代码块、数学公式、图表、目录大纲、文件管理、导入导…...

python机器人编程——用python调用API控制wifi小车的实例程序
目录 一、前言二、一个客户端的简单实现2.1 首先定义一个类及属性2.2 其次定义连接方法2.3 定义一些回调函数2.4 定义发送小车指令方法2.5 定义一个正常关闭方法 三、python编程控制小车的demo实现四、小结PS.扩展阅读ps1.六自由度机器人相关文章资源ps2.四轴机器相关文章资源p…...

面试学习整理-线程池
线程池 简介JUC包线程池介绍线程池最常问也最常用-参数线程执行分析-线程是怎么运行的进程和线程的区别Executors工厂类提供四种线程池Executors和ThreaPoolExecutor创建线程池的区别两种提交任务的方法spring集成的线程池 简介 线程池作为实际使用和面试较多的技能区, 学习是…...
Debian会取代CentOS成为更主流的操作系统吗?
我们知道,其实之前的话,国内用户对centos几乎是情有独钟的偏爱,很多人都喜欢选择centos系统,可能是受到一些原因的影响导致的吧,比如他相当于免费的红帽子系统,或者一些教程和网上的资料都推荐这个系统&…...

网络安全领域推荐证书介绍及备考指南
在网络安全领域,拥有专业认证不仅可以证明个人的专业能力,还能帮助在实际工作中应用先进的技术和知识。以下是几种热门的网络安全证书介绍及备考指南。 1. OSCP (Offensive Security Certified Professional) 证书简介 OSCP是针对渗透测试领域的入门级…...

SpringBoot项目ES6.8升级ES7.4.0
SpringBoot项目ES6.8.15 升级到 ES7.4.0 前言 由于公司内部资产统一整理,并且公司内部部署有多个版本的es集群,所以有必要将目前负责项目的ES集群升级到公司同一版本7.4.0。es6到es7的升级变化还是挺大的,因此在这里做一下简单记录…...

深度学习 之 模型部署 使用Flask和PyTorch构建图像分类Web服务
引言 随着深度学习的发展,图像分类已成为一项基础的技术,被广泛应用于各种场景之中。本文将介绍如何使用Flask框架和PyTorch库来构建一个简单的图像分类Web服务。通过这个服务,用户可以通过HTTP POST请求上传花朵图片,然后由后端…...

MFC工控项目实例二十六创建数据库
承接专栏《MFC工控项目实例二十五多媒体定时计时器》 用选取的型号为文件名建立文件夹,再在下面用测试的当天的时间创建文件夹,在这个文件中用测试的时/分/秒为数据库名创建Adcess数据库。 1、在StdAfx.h文件最下面添加代码 #import "C:/Program F…...

springmvc源码流程解析(一)
Springmvc 是基于servlet 规范来完成的一个请求响应模块,也是spring 中比较大的一个 模块,现在基本上都是零xml 配置了,采用的是约定大于配置的方式,所以我们的springmvc 也是采用这种零xml 配置的方式。 要完成这种过程ÿ…...
【论文阅读】SRGAN
学习资料 论文题目:基于生成对抗网络的照片级单幅图像超分辨率(Photo-Realistic Single Image Super-Resolution Using a Generative Adversarial Network)论文地址:https://arxiv.org/abs/1609.04802代码:GitHub - xiph/daala: Modern video compression for the interne…...

kubelet PLEG实现
概述 kubelet的主要作用是确保pod状态和podspec保持一致,这里的pod状态包括pod中的container状态,个数等。 为了达到这个目的,kubelet需要从多个来源watch pod spec的变化,并周期从container runtime获取最新的container状态。比如…...

leetcode49:字母异位词分组
给你一个字符串数组,请你将 字母异位词 组合在一起。可以按任意顺序返回结果列表。 字母异位词 是由重新排列源单词的所有字母得到的一个新单词。 示例 1: 输入: strs ["eat", "tea", "tan", "ate", "nat", &…...

网络六边形受到攻击
大家读完觉得有帮助记得关注和点赞!!! 抽象 现代智能交通系统 (ITS) 的一个关键要求是能够以安全、可靠和匿名的方式从互联车辆和移动设备收集地理参考数据。Nexagon 协议建立在 IETF 定位器/ID 分离协议 (…...

手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
day52 ResNet18 CBAM
在深度学习的旅程中,我们不断探索如何提升模型的性能。今天,我将分享我在 ResNet18 模型中插入 CBAM(Convolutional Block Attention Module)模块,并采用分阶段微调策略的实践过程。通过这个过程,我不仅提升…...

.Net框架,除了EF还有很多很多......
文章目录 1. 引言2. Dapper2.1 概述与设计原理2.2 核心功能与代码示例基本查询多映射查询存储过程调用 2.3 性能优化原理2.4 适用场景 3. NHibernate3.1 概述与架构设计3.2 映射配置示例Fluent映射XML映射 3.3 查询示例HQL查询Criteria APILINQ提供程序 3.4 高级特性3.5 适用场…...
鱼香ros docker配置镜像报错:https://registry-1.docker.io/v2/
使用鱼香ros一件安装docker时的https://registry-1.docker.io/v2/问题 一键安装指令 wget http://fishros.com/install -O fishros && . fishros出现问题:docker pull 失败 网络不同,需要使用镜像源 按照如下步骤操作 sudo vi /etc/docker/dae…...
JAVA后端开发——多租户
数据隔离是多租户系统中的核心概念,确保一个租户(在这个系统中可能是一个公司或一个独立的客户)的数据对其他租户是不可见的。在 RuoYi 框架(您当前项目所使用的基础框架)中,这通常是通过在数据表中增加一个…...

springboot整合VUE之在线教育管理系统简介
可以学习到的技能 学会常用技术栈的使用 独立开发项目 学会前端的开发流程 学会后端的开发流程 学会数据库的设计 学会前后端接口调用方式 学会多模块之间的关联 学会数据的处理 适用人群 在校学生,小白用户,想学习知识的 有点基础,想要通过项…...
SQL慢可能是触发了ring buffer
简介 最近在进行 postgresql 性能排查的时候,发现 PG 在某一个时间并行执行的 SQL 变得特别慢。最后通过监控监观察到并行发起得时间 buffers_alloc 就急速上升,且低水位伴随在整个慢 SQL,一直是 buferIO 的等待事件,此时也没有其他会话的争抢。SQL 虽然不是高效 SQL ,但…...
uniapp 集成腾讯云 IM 富媒体消息(地理位置/文件)
UniApp 集成腾讯云 IM 富媒体消息全攻略(地理位置/文件) 一、功能实现原理 腾讯云 IM 通过 消息扩展机制 支持富媒体类型,核心实现方式: 标准消息类型:直接使用 SDK 内置类型(文件、图片等)自…...
基于鸿蒙(HarmonyOS5)的打车小程序
1. 开发环境准备 安装DevEco Studio (鸿蒙官方IDE)配置HarmonyOS SDK申请开发者账号和必要的API密钥 2. 项目结构设计 ├── entry │ ├── src │ │ ├── main │ │ │ ├── ets │ │ │ │ ├── pages │ │ │ │ │ ├── H…...