从metashape导出深度图,从深度图恢复密集点云

从metashape导出深度图,从深度图恢复密集点云

1.从metashape导出深度图

参考:https://blog.csdn.net/WHU_StudentZhong/article/details/123107072?spm=1001.2014.3001.5502

2.从深度图建立密集点云

首先从metashape导出blockExchange格式的xml文件,里面记录了相机的内外参等信息
file->export->export camera
下面就开始上代码

import numpy as np
import xml.etree.ElementTree as ET
import os
import cv2def write_point_cloud(ply_filename, points):formatted_points = []for point in points:formatted_points.append("%f %f %f %d %d %d 0\n" % (point[0], point[1], point[2], point[3], point[4], point[5]))out_file = open(ply_filename, "w")out_file.write('''plyformat ascii 1.0element vertex %dproperty float xproperty float yproperty float zproperty uchar blueproperty uchar greenproperty uchar redproperty uchar alphaend_header%s''' % (len(points), "".join(formatted_points)))out_file.close()def depth_image_to_point_cloud(rgb, depth, scale, K, pose):u = range(0, rgb.shape[1])v = range(0, rgb.shape[0])u, v = np.meshgrid(u, v)u = u.astype(float)v = v.astype(float)Z = depth.astype(float) / scaleX = (u - K[0, 2]) * Z / K[0, 0]Y = (v - K[1, 2]) * Z / K[1, 1]X = np.ravel(X)Y = np.ravel(Y)Z = np.ravel(Z)valid = (Z > 0) & (Z < 300)# 计算 valid 中有效元素的数量valid_count = np.count_nonzero(valid)# 打印结果print("有效元素的数量:", valid_count)X = X[valid]Y = Y[valid]Z = Z[valid]position = np.vstack((X, Y, Z, np.ones(len(X))))position = np.dot(pose, position)R = np.ravel(rgb[:, :, 0])[valid]G = np.ravel(rgb[:, :, 1])[valid]B = np.ravel(rgb[:, :, 2])[valid]points = np.transpose(np.vstack((position[0:3, :], R, G, B))).tolist()return pointsdef getDepth(position,depth, scale, K, pose):inverse_pose = np.linalg.inv(pose)position_camera=np.dot(inverse_pose, position)Z = position_camera[2]*scaleu=round(position_camera[0]*K[0, 0]/Z+K[0, 2])v=round(position_camera[1]*K[1, 1]/Z+K[1, 2])z=depth[v][u]return Z# image_files: XXXXXX.jpg (RGB, 24-bit, jpg)
# depth_files: XXXXXX.tif (32-bit, tif)
# poses: camera-to-world, 4×4 matrix in homogeneous coordinates
def build_point_cloud(K,dist_coeffs, scale, view_ply_in_world_coordinate,images,dataPath):images_path = os.path.join(dataPath, 'undistort')depth_path = os.path.join(dataPath, 'depth')for id, image in images.items():# 获取文件所在的文件夹路径image_name=os.path.join(images_path,image['imgName'])depth_name=os.path.join(depth_path,image['imgName'])depth_name=os.path.splitext(depth_name)[0]depth_name = depth_name + '.tif'rgb = cv2.imread(image_name)depth = cv2.imread(depth_name, cv2.IMREAD_UNCHANGED)height, width = depth.shape[:2]# # 创建深度图畸变映射# mapx, mapy = cv2.initUndistortRectifyMap(K, dist_coeffs, None, None, (width,height), cv2.CV_32FC1)# # 应用映射# depth = cv2.remap(depth, mapx, mapy, interpolation=cv2.INTER_NEAREST)rgb_resized=cv2.resize(rgb,(width, height))# # 创建rgb畸变映射# mapx, mapy = cv2.initUndistortRectifyMap(K, dist_coeffs, None, None, (width,height), cv2.CV_32FC1)# rgb_resized = cv2.remap(rgb_resized, mapx, mapy, interpolation=cv2.INTER_NEAREST)depth_values = depth.astype(np.float32)#显示深度值范围print('最小深度值:', np.min(depth_values))print('最大深度值:', np.max(depth_values))if view_ply_in_world_coordinate:current_points_3D = depth_image_to_point_cloud(rgb_resized, depth, scale=scale, K=K, pose=image['trans_M'])else:current_points_3D = depth_image_to_point_cloud(rgb_resized, depth, scale=scale, K=K, pose=image['trans_M'])save_ply_name = os.path.basename(os.path.splitext(image_name)[0]) + ".ply"#save_ply_path = os.path.join(dataPath, "point_clouds_frompoint")save_ply_path = os.path.join(dataPath, "point_clouds_any")if not os.path.exists(save_ply_path):  # 判断是否存在文件夹如果不存在则创建为文件夹os.mkdir(save_ply_path)write_point_cloud(os.path.join(save_ply_path, save_ply_name), current_points_3D)def compute_K_matrix(focal_length, principal_point_x, principal_point_y):"""计算内参数矩阵 K参数:focal_length:焦距principal_point_x: 主点在 x 方向上的像素坐标principal_point_y: 主点在 y 方向上的像素坐标skew: 像素间的 skew factor,默认为 0返回值:K 矩阵"""K = np.array([[focal_length, 0, principal_point_x],[0, focal_length, principal_point_y],[0, 0, 1]])return Kdef loadAllfrom_xml(path):# 解析 XML 文件doc = ET.parse(path)root = doc.getroot()# 初始化相机和图像列表cameras = {}images = {}# 查找相机元素photogroups = root.find(".//Photogroups")if photogroups is None:print("error: invalid scene file")return False# 解析相机信息for photogroup in photogroups.findall("Photogroup"):camera_model_type = photogroup.find("CameraModelType")if camera_model_type is None or camera_model_type.text != "Perspective":continueimage_dimensions = photogroup.find("ImageDimensions")if image_dimensions is None:continuewidth = int(image_dimensions.find("Width").text)height = int(image_dimensions.find("Height").text)resolution_scale = max(width, height)focal_length_pixels = photogroup.find("FocalLengthPixels")if focal_length_pixels is not None:f = float(focal_length_pixels.text)else:focal_length = float(photogroup.find("FocalLength").text)sensor_size = float(photogroup.find("SensorSize").text)f = focal_length * resolution_scale / sensor_sizeprincipal_point = photogroup.find("PrincipalPoint")if principal_point is not None:cx = float(principal_point.find("x").text) cy = float(principal_point.find("y").text)pxl_size = 1# 解析畸变参数distortion = photogroup.find("Distortion")k1 = k2 = k3 = p1 = p2 = 0if distortion is not None:k1_elem = distortion.find("K1")if k1_elem is not None:k1 = float(k1_elem.text)k2_elem = distortion.find("K2")if k2_elem is not None:k2 = float(k2_elem.text)k3_elem = distortion.find("K3")if k3_elem is not None:k3 = float(k3_elem.text)p1_elem = distortion.find("P1")if p1_elem is not None:p1 = float(p1_elem.text)p2_elem = distortion.find("P2")if p2_elem is not None:p2 = float(p2_elem.text)  camera = {'width': width, 'height': height, 'f': f, 'cx': cx, 'cy': cy, 'pxlSize': pxl_size,'k1': k1, 'k2': k2, 'k3': k3, 'p1': p2, 'p2': p1}cameras[1] = camera# 解析图像信息for photo in photogroup.findall("Photo"):img_id = int(photo.find("Id").text)image_path = photo.find("ImagePath").textfound = image_path.rfind("/")img_name = image_path[found + 1:]photo_pose = photo.find("Pose")if photo_pose is None:continuerotation = photo_pose.find("Rotation")if rotation is None:continuerotation_matrix = np.array([[float(rotation.find("M_00").text), float(rotation.find("M_01").text),float(rotation.find("M_02").text)],[float(rotation.find("M_10").text),float(rotation.find("M_11").text), float(rotation.find("M_12").text)],[float(rotation.find("M_20").text), float(rotation.find("M_21").text),float(rotation.find("M_22").text)]])center = photo_pose.find("Center")if center is None:continueXs = float(center.find("x").text)Ys = float(center.find("y").text)Zs = float(center.find("z").text)position= np.array([Xs,Ys,Zs])trans=create_transformation_matrix(rotation_matrix,position)img = {'iid': img_id,'image_path':image_path, 'imgName': img_name,'R':rotation_matrix,'Xs': Xs, 'Ys': Ys, 'Zs': Zs,'trans_M':trans}images[img_id] = imgreturn images, camerasdef create_transformation_matrix(rotation_matrix, translation_vector):# 创建一个 4x4 的单位矩阵transformation_matrix = np.eye(4)transformation_matrix[:3, :3] = rotation_matrix.T#将rotation求逆transformation_matrix[:3, 3] = translation_vectorreturn transformation_matriximages, cameras = loadAllfrom_xml('pos_undistort.xml')
K=compute_K_matrix(cameras[1]['f'],cameras[1]['cx'],cameras[1]['cy'])
dist_coeffs = np.array([cameras[1]['k1'],cameras[1]['k2'], cameras[1]['p1'], cameras[1]['p2'], cameras[1]['k3']])view_ply_in_world_coordinate = True
K=K*0.5
K[2][2]=1build_point_cloud(K,dist_coeffs*0.5,1,view_ply_in_world_coordinate,images,'G:\\graduate2024\\experiment\\test')

需要注意的是,如果深度图的width height和rgb影像存在一个比例关系scale,则K也需要进行相应的尺度变换,例如,我使用的深度图长宽是rgb影像的一半,那么我的K乘以了一个0.5
另外由于我的影像已经事先去除了畸变,其畸变系数为0,因此此代码没有提供去除影像畸变的部分,需自行添加

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

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

相关文章

OpenHarmony、HarmonyOS打开编辑 PDF 等操作的三方组件使用教程

项目场景: 随着数字化时代的发展,PDF 文档成为广泛应用于各行业的重要文件格式。为了提高OpenHarmony/HarmonyOS生态系统的功能性和用户体验,我们需要一款支持打开、编辑PDF文件的应用程序。 使用户能够轻松打开、浏览和编辑PDF文件。该应用将充分利用OpenHarmony/HarmonyO…

【NTN 卫星通信】卫星和无人机配合的应用场景

1 场景概述 卫星接入网是一种有潜力的技术&#xff0c;可以为地面覆盖差地区的用户提供无处不在的网络服务。然而&#xff0c;卫星覆盖范围对于位于考古或采矿地点内部/被茂密森林覆盖的村庄/山谷/靠近山丘或大型建筑物的用户可能很稀疏。因此&#xff0c;涉及卫星接入和无人驾…

HarmonyOS Full SDK的安装

OpenHarmony的应用开发工具HUAWEI DevEco Studio现在随着OpenHarmony版本发布而发布,只能在版本发布说明中下载,例如最新版本的OpenHarmony 4.0 Release。对应的需要下载DevEco Studio 4.0 Release,如下图。 图片 下载Full SDK主要有两种方式,一种是通过DevEco Studio下载…

教你用Fiddler捕获HTTPS请求

安装Fiddler 这里不特别说明了&#xff0c;网上搜索一大把&#xff0c;根据安装引导一步步安装即可。&#xff08;这里采用的是fiddler v4.6&#xff09; 配置Fiddler 1、打开fiddler配置Tools –>Telerik Fiddler Options。 2、打开HTTPS配置项&#xff0c;勾选“Captur…

【程序员养生延寿系列-万人关注的养生指南 4 】

1.早起一杯温水&#xff0c;疏通肠胃&#xff0c;补充水分。 2.早十点和下午三点左右活动活动身体&#xff08;运动or健身&#xff09;&#xff0c;放松紧张疲惫的身体&#xff0c;帮助消化&#xff0c;给身体透个气。 3.每天散步&#xff0c;好处多多&#xff08;减肥健身&a…

ctf_show笔记篇(web入门---爆破)

爆破 21&#xff1a;直接bp抓包跑字典&#xff0c;需base64加密 22&#xff1a;可用工具跑也可用浏览器找还可以用网上做好的域名查找去找 23&#xff1a;此题需跑脚本已经附上自写脚本 最后跑出来六个答案一个一个尝试得到答案为3j import hashlibm "0123456789qwert…

C++_AVL树

目录 1、AVL的概念 2、平衡因子的调整概念 3、AVL树的插入 3.1 调整平衡因子代码实现 3.2 右旋操作 3.2 左旋操作 3.3 双旋-先右旋再左旋 3.4 双旋-先左旋再右旋 3.5 旋转操作的小结 4、AVL的验证与实现 结语 前言&#xff1a; 在C中&#xff0c;AVL树是在二叉搜索…

2024中国眼博会,山东省眼科医学技术交流大会

以展带会&#xff0c;以会促展&#xff0c;展与会有机结合&#xff0c;立足山东打造具全国影响力的眼康产业发展盛会&#xff1b; ——随着时代的高速发展&#xff0c;科技的进步&#xff0c;现代生活节奏的加快&#xff0c;青少年近视问题日益严重&#xff0c;对儿童青少年的…

旧的Spring Security OAuth已停止维护,全面拥抱新解决方案Spring SAS

Spring Authorization Server 替换 Shiro 指引 背景 Spring 团队正式宣布 Spring Security OAuth 停止维护&#xff0c;该项目将不会再进行任何的迭代 目前 Spring 生态中的 OAuth2 授权服务器是 Spring Authorization Server 已经可以正式生产使用作为 SpringBoot 3.0 的最新…

如何使用naive 做一个模态框的方式

1.我的问题使用了一个table 表格&#xff0c;在表格中设置俩个按钮 最后做出来的效果 <template><div><h1>测试文件</h1><!-- 表格 --><n-data-table :columns"columns" :data"data" :pagination"pagination" …

Linux内核队列queue.h

文章目录 一、简介二、SLIST单向无尾链表2.1 介绍2.2 操作2.3 例子 三、STAILQ单向有尾链表四、LIST双向无尾链表五、TAILQ双向有尾链表六、CIRCLEQ循环链表七、queue源码参考 一、简介 queue.h是一个非常经典的文件&#xff0c;定义了一系列宏的操作&#xff0c;它定义了一系…

笔记72:关于IMU(惯性测量单元)传感器的作用【不涉及公式推导】

一、IMU传感器是什么&#xff1a; 惯性测量单元IMU&#xff08;Inertial Measurement Unit&#xff09;是一种使用【加速度计】和【陀螺仪】来测量【物体三轴姿态角&#xff08;空间姿态&#xff09;】的装置&#xff1b;IMU在坐标系的每个坐标轴上&#xff0c;均安装有1个陀螺…

90-子集2(回溯算法)

题目 给你一个整数数组 nums &#xff0c;其中可能包含重复元素&#xff0c;请你返回该数组所有可能的子集&#xff08;幂集&#xff09;。 解集 不能 包含重复的子集。返回的解集中&#xff0c;子集可以按 任意顺序 排列。 示例 1&#xff1a; 输入&#xff1a;nums [1,2,2] …

深入理解CSS常见选择器

标题&#xff1a;深入理解CSS常见选择器 在CSS中&#xff0c;选择器是一种强大的工具&#xff0c;用于定位和样式化HTML文档中的元素。通过选择器的灵活运用&#xff0c;我们能够精准地选择需要操作的元素&#xff0c;从而实现丰富多彩的页面布局和设计。本文将重点介绍常见的…

Vue2:用node+express部署Vue项目

一、编译项目 命令 npm run build执行命令后&#xff0c;我们会在项目文件夹中看到如下生成的文件 二、部署Vue项目 接上一篇&#xff0c;nodeexpress编写轻量级服务 1、在demo中创建static文件夹 2、将dist目录中的文件放入static中 3、修改server.js文件 关键配置&…

全量知识系统问题及SmartChat给出的答复 之13 解析器+DDD+文法型

Q32. DDD的领域概念和知识系统中设计的解析器之间的关系。 那下面&#xff0c;我们回到前面的问题上来。 前面说到了三种语法解析器&#xff0c;分别是 形式语言的&#xff08;机器或计算机语言&#xff09;、人工语言的和自然语言的。再前面&#xff0c;我们聊到了DDD设计思…

基于java的学生派遣信息管理系统设计开题报告

欢迎添加微信互相交流学习哦&#xff01; 项目源码&#xff1a;biye2: 毕业设计源码 一、项目名称 Java基于学生派遣信息管理系统设计 二、项目背景 随着科技的发展&#xff0c;互联网在我国的应用越来越广泛&#xff0c;尤其是在教育领域。为了能更好地管理学生派遣信息&am…

DayDreamInGIS 之 ArcGIS Pro二次开发 图层属性中换行符等特殊字符替换

具体参考ArcMap中类似的问题&#xff0c;本帖开发一个ArcGISPro版的工具 1.基础库部分 插件开发&#xff0c;经常需要处理图层与界面的交互。基础库把常用的交互部分做了封装&#xff0c;方便之后的重复使用。 &#xff08;1&#xff09;下述类定义了数据存储结构&#xff0…

DFA还原白盒AES密钥

本期内容是关于某app模拟登录的,涉及的知识点比较多,有unidbg补环境及辅助还原算法,ida中的md5以及白盒aes,fart脱壳,frida反调试 本章所有样本及资料均上传到了123云盘 llb资料官方版下载丨最新版下载丨绿色版下载丨APP下载-123云盘 目录 首先抓包 fart脱壳 加密位置定位…

0048__Unix传奇

Unix传奇 &#xff08;上篇&#xff09;_unix传奇(上篇)-CSDN博客 Unix传奇 &#xff08;下篇&#xff09;-CSDN博客 Unix现状与未来——CSDN对我的采访_nuix邮件系统行业地位-CSDN博客