Python 异源mesh裁剪融合实现与优化

news2024/11/18 8:24:27

Python 异源mesh裁剪融合实现与优化

  • 一、项目需求
  • 二、解决方案
    • 1. 代码
    • 2. 结果
    • 3. 耗时
  • 三、优化探索
    • 0. 分析
    • 1. 在体素边界处进行裁剪
    • 2. 用mesh分块进行裁剪
    • 3. 用缓冲区的思路裁剪

一、项目需求

对mesh进行裁剪,但发现若非mesh是致密的,那么裁剪边会出现锯齿状边缘,究其原因,是因为该裁剪方式没有对三角面片进行处理,而是直接处理的mesh的顶点,导致裁剪边不光滑,那么两个相邻的裁剪后mesh(尤其是异源mesh)放在一起的时候,会出现缝隙。
在这里插入图片描述
在这里插入图片描述

计划找到一种在三角面片层面对mesh进行裁剪的方案,用来解决缝隙问题。

二、解决方案

找到三个python第三方库,分别为pyvista、vedo、trimesh可以实现上述功能,下面对这个三个库进行测试比较。

1. 代码

import time
from datetime import timedelta

import numpy as np

import pyvista as pv

mvs_path = r"T:\ProjectData\SDF_Studio\GT_data\mvs_mesh_aligned.ply"

dataset = pv.read(mvs_path)
start_time = time.time()
bounds = [195.957, 211.373, 347.767, 362.355, 270.836, 286.781]
clipped = dataset.clip_box(bounds, invert=False)
end_time = time.time()
elapsed_time = end_time - start_time
formatted_time = str(timedelta(seconds=elapsed_time))
print(f"pyvista took  {formatted_time}")

p = pv.Plotter()
p.add_mesh(clipped, label='Clipped')
p.show()

import vedo

mesh = vedo.load(mvs_path)
start_time = time.time()
clipped_mesh = mesh.cut_with_box(bounds)
end_time = time.time()
elapsed_time = end_time - start_time
formatted_time = str(timedelta(seconds=elapsed_time))
print(f"vode took  {formatted_time}")
# 显示裁剪后的mesh
vedo.show(clipped_mesh)

import trimesh

mesh = trimesh.load_mesh(mvs_path)
start_time = time.time()
min_values = [195.957,347.767,270.836]
max_values = [211.373,362.355,286.781]
# 定义六个平面的法向量和原点
planes = np.array([
    [1, 0, 0, min_values[0], 0, 0],
    [-1, 0, 0, max_values[0], 0, 0],
    [0, 1, 0, 0, min_values[1], 0],
    [0, -1, 0, 0, max_values[1], 0],
    [0, 0, 1, 0, 0, min_values[2]],
    [0, 0, -1, 0, 0, max_values[2]]])

mesh = trimesh.intersections.slice_mesh_plane(
    mesh=mesh,
    plane_normal=planes[:, :3],
    plane_origin=planes[:, 3:],
    cap=False,
)

end_time = time.time()
elapsed_time = end_time - start_time
formatted_time = str(timedelta(seconds=elapsed_time))
print(f"trimesh took  {formatted_time}")
mesh.show()

2. 结果

pyvista:
在这里插入图片描述
vedo:
在这里插入图片描述
trimesh:
在这里插入图片描述
以上都可以实现在三角面片层面对mesh进行裁剪,接下来看看其效率和效果。

3. 耗时

pyvista took  0:00:19.446367
vode took  0:00:00.642607
trimesh took  0:00:01.582946

根据测试结果来看,vedo的效率最高,接下来用vedo来做大型的mesh裁剪融合实验。但在实验结果中发现其在边角上处理的并不好,仍有空隙存在。

在这里插入图片描述
在这里插入图片描述

改用trimesh进行测试,其边界就处理得比较好,但相同数据下,trimesh耗时是vedo的两倍。目前还仅是较大的尺寸进行融合,后续当体素设置为更小尺寸时,耗时会指数级别增长,所以还需优化。

在这里插入图片描述
在这里插入图片描述

三、优化探索

在这里记录所想到和已经实验的优化思路。

0. 分析

首先简单说一下trimesh的裁剪逻辑,它没有直接利用体素bound或者box进行裁剪方式,只有一个用平面切分mesh的方法,而且只返回法线正侧的mesh,见此处。所以想要裁剪出一个体素内的mesh,只能用6个平面循环切分得到,如上述代码。
那么很容易想到,用多个体素裁剪时会有重复计算。

1. 在体素边界处进行裁剪

先在所有体素边界处进行裁剪,然后得到边界处分割后的mesh,与原始mesh合并,在正常进行裁剪融合,但实验发现融合结果始终有缝隙存在,可能跟边界的顶点不好判别在哪一个体素有关系。
这个边框的mesh还比较有意思。
在这里插入图片描述

2. 用mesh分块进行裁剪

先找到一个大于体素的mesh分块,然后用这个mesh分块进行裁剪,实验发现用mesh分块裁剪确实很快,但在加上mesh分块的过程,与之前用整个mesh进行裁剪的耗时相当了。

def small_mesh(vertices,faces,min_v ,max_v ):
	'''在大型mesh中找到小的mesh分块'''
    # 找出满足条件的顶点的索引
    inside_indices = np.where(
        (vertices[:, 0] > min_v[0]) & (vertices[:, 0] < max_v[0]) &
        (vertices[:, 1] > min_v[1]) & (vertices[:, 1] < max_v[1]) &
        (vertices[:, 2] > min_v[2]) & (vertices[:, 2] < max_v[2])
    )[0]

    # 根据这些索引找到相关的三角面片
    inside_faces = np.any(np.isin(faces, inside_indices), axis=1)

    # 创建新的 mesh
    new_vertices = vertices[inside_indices]
    new_faces=faces[inside_faces]
    index_map1 = {old: new for new, old in enumerate(inside_indices.flatten())}
    new_faces = [[index_map1[idx] for idx in face] for face in new_faces if all(idx in index_map1 for idx in face)]
    new_mesh = trimesh.Trimesh(vertices=new_vertices, faces=new_faces)
    return new_mesh

在这里插入图片描述

3. 用缓冲区的思路裁剪

之所以有缝隙存在,是因为使用顶点判别时没有顾及到三角面片,如果设定一个缓冲区,那么三角面片就可以覆盖边界从而消除缝隙。
那怎么实现这个缓冲区的思路呢,其实也简单,在遍历顶点的时候,对每个顶点在6个方向上平移一个设定值,判断其是否会落入到其他体素内就可以了。若没有落入其他体素,记得不要重复统计该顶点。

# 核心代码
voxel_dict1 = defaultdict(list)
    buffer = 0.2  # 设置缓冲区大小
    directions=[np.array([1, 0, 0]), np.array([-1, 0, 0]), np.array([0, 1, 0]), np.array([0, -1, 0]), np.array([0, 0, 1]), np.array([0, 0, -1])]
    for i, v in tqdm(enumerate(vertices1)):
        k = ((v - global_min) / voxel_size).astype(np.int32)
        voxel_dict1[tuple(k)].append(i)
        # 将顶点向六个方向移动一个缓冲值,然后检查移动后的顶点是否会落入其他体素中
        for direction in directions:
            new_v = v + direction * buffer
            new_k = tuple(((new_v - global_min) / voxel_size).astype(np.int32))
            if not np.array_equal(new_k, k):   # 检查顶点是否移动到了其他体素中
                voxel_dict1[tuple(new_k)].append(i)

以下分别是无缓冲区、缓冲值为0.1,、缓冲值为0.2的结果。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
耗时8分钟左右,且跟体素尺寸无关,不会随着体素减小耗时指数倍增长。
在这里插入图片描述
实验表明,这种方法简单高效,可以有效去除异源mesh融合时的缝隙。在这里,最朴素的思想反而是最实用的。


打完收工

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

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

相关文章

用通俗易懂的方式讲解:使用Llama-2、PgVector和LlamaIndex,构建大模型 RAG 全流程

近年来&#xff0c;大型语言模型&#xff08;LLM&#xff09;取得了显著的进步&#xff0c;然而大模型缺点之一是幻觉问题&#xff0c;即“一本正经的胡说八道”。其中RAG&#xff08;Retrieval Augmented Generation&#xff0c;检索增强生成&#xff09;是解决幻觉比较有效的…

Linux网络引导自动安装centos7

目录 一、部署PXE远程安装服务 1. 系统装机的三种引导方式 2. pxe概述 3. 实现过程 4. 搭建过程中服务介绍 4.1 TFTP服务 4.2 vsftp&#xff1a;安装系统镜像文件获取方式 4.3 syslinux 4.4 DHCP服务 5. 操作过程 二、实现Kickstart无人值守安装 1. 安装Kickstart图…

vue项目执行依赖安装(npm i或npm install )报ls-remote -h -t异常

从git拉取的vue项目执行依赖安装时一直报错&#xff0c; 报错如下图&#xff1a;首先&#xff0c;查看了node版本、npm配置的镜像地址均没找到解决办法。 在命令行中直接输入git发现提示于是从网上搜到了一个博文https://blog.csdn.net/weixin_49159364/article/details/118198…

ycsb压测mongodb

下载解压 https://github.com/brianfrankcooper/YCSB/releases/download/0.17.0/ycsb-mongodb-binding-0.17.0.tar.gz tar -zxvf ycsb-mongodb-binding-0.17.0.tar.gzycsb提前已经在workload文件夹下准备好了几个压测场景分别对应workload[a:f] workloads/workloada 样例 …

【Linux】Linux系统编程——pwd命令

文章目录 1.命令概述2.命令格式3.常用选项4.相关描述5.参考示例 1.命令概述 pwd&#xff08;Print Working Directory&#xff09;命令用于显示用户当前工作目录的完整路径。这是一个常用的命令&#xff0c;帮助用户确定他们目前所在的目录位置。 2.命令格式 基本的 pwd 命令…

CVer从0入门NLP(二)———LSTM、ELMO、Transformer模型

&#x1f34a;作者简介&#xff1a;秃头小苏&#xff0c;致力于用最通俗的语言描述问题 &#x1f34a;专栏推荐&#xff1a;深度学习网络原理与实战 &#x1f34a;近期目标&#xff1a;写好专栏的每一篇文章 &#x1f34a;支持小苏&#xff1a;点赞&#x1f44d;&#x1f3fc;、…

恒创科技:云存储和网盘怎么区分出来?

随着互联网的发展&#xff0c;数据存储已成为人们日常生活中不可或缺的一部分。云存储和网盘是经常被人们提及的两种存储方式&#xff0c;均通过网络进行数据存储和访问的服务。但&#xff0c;它们在技术实现、数据安全性、访问方式和数据容量等方面存在一定的差异。要区分&…

DAY04_Spring—Aop案例引入代理机制

目录 1 AOP1.1 AOP案例引入1.1.1 数据库事务说明 1.2 Spring实现事务控制1.2.1 代码结构如下1.2.2 编辑User1.2.3 编辑UserMapper/UserMapperImpl1.2.4 编辑UserService/UserServiceImpl1.2.5 编辑配置类1.2.6 编辑测试类 1.3 代码问题分析1.4 代理模式1.4.1 生活中代理案例1.4…

赋能客户不停歇,卓翼飞思职业院校无人智能装备师资培训圆满落幕

1月10日-15日&#xff0c;卓翼飞思在北京研发中心成功举办职业院校无人智能装备高级师资培训。来自湖南汽车工程职业学院&#xff08;以下简称&#xff1a;湖南汽车职院&#xff09;的10名师生&技术人员参与此次培训&#xff0c;针对无人智能集群应用开发进行系统性的培训及…

图卷积GCN实战基于网络结构图的网络表示学习实战

下面的是数据&#xff1a; from,to,cost 73,5,352.6 5,154,347.2 154,263,392.9 263,56,440.8 56,96,374.6 96,42,378.1 42,58,364.6 58,95,476.8 95,72,480.1 72,271,419.5 271,68,251.1 134,107,344.0 107,130,862.1 130,129,482.5 227,167,1425.7 167,298,415.7 298,209,42…

(vue)键值对结构数据展示

(vue)键值对结构数据展示 效果&#xff1a; 数据结构&#xff1a; this.formInline.algorithmText [{algorithmParameters: {参数名1: "111",参数名2: "121,122",},algorithmName: "算法1",algorithmId: 9,},{algorithmParameters: {参数名1:…

Android安卓读写低频EM4469卡源码

本示例使用的发卡器&#xff1a; <?xml version"1.0" encoding"utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android"http://schemas.android.com/apk/res/android"xmlns:app"http://schemas.android.…

Qt通用属性工具:随心定义,随时可见(三)

传送门: 《Qt通用属性工具:随心定义,随时可见(一)》 《Qt通用属性工具:随心定义,随时可见(二)》 《Qt通用属性工具:随心定义,随时可见(三)》 一、效果展示 本文将展示的是一个源于Qt但是却有些年头的Qt属性浏览工具。支持交互式编辑和查阅对象属性。 这可不就是妥…

机器学习--人工智能概述

人工智能概述 入门人工智能&#xff0c;了解人工智能是什么。为啥发展起来&#xff0c;用途是什么&#xff0c;是最重要也是最关键的事情。大致有以下思路。 人工智能发展历程机器学习定义以及应用场景监督学习&#xff0c;无监督学习监督学习中的分类、回归特点知道机器学习…

产品经理学习-产品运营《用户运营策略》

⽤户画像与⽤户运营策略 什么是用户画像 对产品运营而言&#xff0c;用户画像就是对用户的各种特征贴上标签通过这些标签将用户分成不同的用户群体 为用户提供有针对性的服务。 制作用户画像是为了专注和精准 使产品的服务对象更加聚焦&#xff0c;更加专注&#xff1b;根据产…

NIFI 2.0.0版本HTTPS访问部署

1. 相关环境 服务器&#xff1a;centos JDK&#xff1a;jdk21 NIFI: nifi-2.0.0-M1 2. 下载NIFI 下载NIFI https://nifi.apache.org/download/ 将文件上传至服务器指定目录&#xff0c;解压缩 修改 bin 目录下的脚本文件 ​ 注意: nifi 2.0.0 版本需要jdk21&#xff0c;所…

C++ 二叉树OJ题

目录 1、606. 根据二叉树创建字符串 2、102. 二叉树的层序遍历 3、107. 二叉树的层序遍历 II 4、236. 二叉树的最近公共祖先 5、JZ36 二叉搜索树与双向链表 6、105. 从前序与中序遍历序列构造二叉树 7、106. 从中序与后序遍历序列构造二叉树 8、144. 二叉树的前序遍历…

pdf怎么查看?6个不能错过的软件!

PDF&#xff0c;作为一种常用的文件格式&#xff0c;已经成为了我们工作、学习中的必备工具。然而&#xff0c;对于许多新手来说&#xff0c;如何查看和编辑PDF文件却是一个不小的挑战。今天&#xff0c;我们就来为大家详细介绍一下如何查看和编辑PDF文件&#xff0c;以及一些必…

从法律的角度看待项目前期可行性研究的必要性

前言 在司法实践中&#xff0c;很多纠纷展现出来的问题是项目提供方没有按照合同约定履行发生违约的情况&#xff0c;例如逾期交付、项目不符合约定标准等等&#xff0c;但是这些情况发生的原因是各不相同的&#xff0c;其中有一类纠纷的发生却是从一开始就埋下了风险的种子&a…

2.0-学成在线内容管理

内容管理模块 1.需求 1.1 业务流程 内容管理的业务由教学机构人员和平台的运营人员共同完成。 教学机构人员的业务流程如下&#xff1a; 1、登录教学机构。 2、维护课程信息&#xff0c;添加一门课程需要编辑课程的基本信息、上传课程图片、课程营销信息、课程计划、上传课程…