【三维几何学习】网格简化-ModelNet10

news2024/11/19 13:35:51

网格简化-ModelNet10

  • 引言
  • 一、网格的简化
    • 1.1 水密网格的简化可视化
    • 1.2 非水密网格的简化可视化
    • 1.3 核心代码
  • 二、ModelNet10数据集简化
  • 三、展望

引言

计算机算力有限,特别是在深度学习领域,撇开网格的输入特征计算,现有条件很难直接训练测试高分辨的网格。故需要对网格进行简化:

常规网格简化算法简介

一、网格的简化

数据集可参考:三角网格(Triangular Mesh)分类数据集 - ModelNet及其水密版

分别使用open3DMeshlabblender对bathtub_0141.obj进行简化,未调参

1.1 水密网格的简化可视化

在这里插入图片描述
对水密网格进行简化,可以保持其大致形状,但是细节较模糊,也许加入平滑会更好
在这里插入图片描述

1.2 非水密网格的简化可视化

在这里插入图片描述在这里插入图片描述在这里插入图片描述在这里插入图片描述
对非水密的离散网格进行简化,可能会使其扭曲,如上图所示
结果文件如下:
请添加图片描述

1.3 核心代码

import os
import subprocess
import open3d
import time
import numpy as np
from blender_process import Process
# https://github.com/ranahanocka/MeshCNN/blob/master/scripts/dataprep/blender_process.py


def load_obj(file):
    f = open(file)
    vs, faces = [], []
    for line in f:
        line = line.strip()
        splitted_line = line.split()
        if not splitted_line:
            continue
        elif splitted_line[0] == 'v':
            vs.append([float(v) for v in splitted_line[1:4]])
        elif splitted_line[0] == 'f':
            face_vertex_ids = [int(c.split('/')[0]) for c in splitted_line[1:]]
            assert len(face_vertex_ids) == 3
            face_vertex_ids = [(ind - 1) if (ind >= 0) else (len(vs) + ind)
                               for ind in face_vertex_ids]
            faces.append(face_vertex_ids)
    f.close()
    return np.array(vs), np.array(faces, dtype=int)


if __name__=='__main__':
    # 0.简化网格面个数设定
    face_num = 500

    # 1.网格路径 读取网格
    load_dir = './datasets/bathtub_0141.obj'
    save_dir = './datasets/bathtub_0141_' + str(face_num)

    # 2.1 open3D简化并保存
    start_time = time.time()
    vs, faces = load_obj(load_dir)
    m = open3d.geometry.TriangleMesh()
    m.vertices = open3d.utility.Vector3dVector(vs)
    m.triangles = open3d.utility.Vector3iVector(faces)
    m = m.simplify_quadric_decimation(face_num)
    open3d.io.write_triangle_mesh(save_dir + '_open3d.obj', m)
    t = (time.time() - start_time)
    print('open3D简化并保存:', t)

    # 2.2 Meshlab简化并保存
    start_time = time.time()
    temp = subprocess.run(["D:/software/MeshLab/meshlabserver.exe",
                           "-i", os.path.abspath(load_dir),
                           "-o", os.path.abspath(save_dir + '_meshlab.obj'),
                           "-s", "D:/vm/QECD_500.mlx"])
    t = (time.time() - start_time)
    print('Meshlab简化并保存:', t)

    # 2.3 blender简化并保存
    start_time = time.time()
    blender = Process(os.path.abspath(load_dir),
                      face_num,
                      os.path.abspath(save_dir + '_blender.obj'))
    t = (time.time() - start_time)
    print('blender简化并保存:', t)

# bathtub_0141.obj 单位秒
# open3D简化并保存: 0.769096851348877     0.9059770107269287
# Meshlab简化并保存: 0.7407355308532715   1.652160406112671
# blender简化并保存: 0.5777468681335449   0.7607262134552002

QECD_500.mlx

<!DOCTYPE FilterScript>
<FilterScript>
 <filter name="Simplification: Quadric Edge Collapse Decimation">
  <Param name="TargetFaceNum" type="RichInt" tooltip="The desired final number of faces." description="Target number of faces" value="500"/>
  <Param name="TargetPerc" type="RichFloat" tooltip="If non zero, this parameter specifies the desired final size of the mesh as a percentage of the initial size." description="Percentage reduction (0..1)" value="0"/>
  <Param name="QualityThr" type="RichFloat" tooltip="Quality threshold for penalizing bad shaped faces.&lt;br>The value is in the range [0..1]&#xa; 0 accept any kind of face (no penalties),&#xa; 0.5  penalize faces with quality &lt; 0.5, proportionally to their shape&#xa;" description="Quality threshold" value="0.3"/>
  <Param name="PreserveBoundary" type="RichBool" tooltip="The simplification process tries to do not affect mesh boundaries during simplification" description="Preserve Boundary of the mesh" value="false"/>
  <Param name="BoundaryWeight" type="RichFloat" tooltip="The importance of the boundary during simplification. Default (1.0) means that the boundary has the same importance of the rest. Values greater than 1.0 raise boundary importance and has the effect of removing less vertices on the border. Admitted range of values (0,+inf). " description="Boundary Preserving Weight" value="1"/>
  <Param name="PreserveNormal" type="RichBool" tooltip="Try to avoid face flipping effects and try to preserve the original orientation of the surface" description="Preserve Normal" value="false"/>
  <Param name="PreserveTopology" type="RichBool" tooltip="Avoid all the collapses that should cause a topology change in the mesh (like closing holes, squeezing handles, etc). If checked the genus of the mesh should stay unchanged." description="Preserve Topology" value="false"/>
  <Param name="OptimalPlacement" type="RichBool" tooltip="Each collapsed vertex is placed in the position minimizing the quadric error.&#xa; It can fail (creating bad spikes) in case of very flat areas. &#xa;If disabled edges are collapsed onto one of the two original vertices and the final mesh is composed by a subset of the original vertices. " description="Optimal position of simplified vertices" value="false"/>
  <Param name="PlanarQuadric" type="RichBool" tooltip="Add additional simplification constraints that improves the quality of the simplification of the planar portion of the mesh." description="Planar Simplification" value="false"/>
  <Param name="QualityWeight" type="RichBool" tooltip="Use the Per-Vertex quality as a weighting factor for the simplification. The weight is used as a error amplification value, so a vertex with a high quality value will not be simplified and a portion of the mesh with low quality values will be aggressively simplified." description="Weighted Simplification" value="false"/>
  <Param name="AutoClean" type="RichBool" tooltip="After the simplification an additional set of steps is performed to clean the mesh (unreferenced vertices, bad faces, etc)" description="Post-simplification cleaning" value="true"/>
  <Param name="Selected" type="RichBool" tooltip="The simplification is applied only to the selected set of faces.&#xa; Take care of the target number of faces!" description="Simplify only selected faces" value="false"/>
 </filter>
</FilterScript>

参考:

Meshlab:用PyMeshLab执行从MeshLab中导出的过滤器脚本(.mlx)功能
Open3D:Open3D Mesh 网格
blender:blender_process.py

二、ModelNet10数据集简化

生成简化版本的数据集

import glob, os, shutil, sys, json
from pathlib import Path
import pylab as plt
import trimesh
import open3d
import time
import numpy as np
from tqdm import tqdm


def load_off(file):
    file = open(file, 'r')
    if 'OFF' != file.readline().strip():
        raise ('Not a valid OFF header')

    n_verts, n_faces, n_dontknow = tuple([int(s) for s in file.readline().strip().split(' ')])
    verts = [[float(s) for s in file.readline().strip().split(' ')] for i_vert in range(n_verts)]
    faces = [[int(s) for s in file.readline().strip().split(' ')][1:] for i_face in range(n_faces)]
    file.close()
    return np.array(verts), np.array(faces, dtype=int)


MESH_EXTENSIONS = [
    '.off',
]
def is_mesh_file(filename):
    return any(filename.endswith(extension) for extension in MESH_EXTENSIONS)
def make_dataset_by_class(dir, class_to_idx, phase):
    meshes = [[] for _ in class_to_idx]
    dir = os.path.expanduser(dir)
    id = -1
    for target in sorted(os.listdir(dir)):
        d = os.path.join(dir, target)  # 获取每一类的 路径
        if not os.path.isdir(d):
            continue  # 不是文件夹就跳过了
        d = os.path.join(d, phase)
        id = id + 1
        #print(os.listdir(d))
        for root, _, fnames in sorted(os.walk(d)):
            for fname in sorted(fnames):
                if is_mesh_file(fname):  # 是mesh文件 并且 是相关类型 train or test
                    path = os.path.join(root, fname)
                    item = (path, class_to_idx[target],fname,root)  # 路径 , 类别
                    meshes[id].append(item)
    return meshes


if __name__=='__main__':
    # 0.简化网格面个数设定
    face_num = 500
    # 1.得到所有文件的路径
    dir_ = '../../../datasets/ModelNet10'
    classes = [d for d in os.listdir(dir_) if os.path.isdir(os.path.join(dir_, d))]  # 只返回文件夹
    class_to_idx = {classes[i]: i for i in range(len(classes))}                      # 类别
    train = make_dataset_by_class(os.path.join(dir_), class_to_idx,'train')
    test = make_dataset_by_class(os.path.join(dir_), class_to_idx,'test')

    # 2.遍历 test
    cnt = 0
    for test_ in test:  # 所有类
        start_time = time.time()
        cnt = cnt + 1
        print(cnt)
        for mesh in test_:  # 每一类的所有obj
            # 2.1 读取
            vs, faces = load_off(mesh[0])
            m = open3d.geometry.TriangleMesh()
            m.vertices = open3d.utility.Vector3dVector(vs)
            m.triangles = open3d.utility.Vector3iVector(faces)
            # 2.2 路径
            # save_dir = '../../../datasets/ModelNet10_' + str(face_num) + '/' + mesh[3]
            save_dir = mesh[3].replace('ModelNet10', 'ModelNet10_' + str(face_num))
            if not os.path.isdir(save_dir):
                os.makedirs(save_dir, exist_ok=True)
            # 2.3 简化并保存
            while len(m.triangles) < face_num:   # 面的个数
                m = m.subdivide_midpoint(number_of_iterations=1)
            m = m.simplify_quadric_decimation(face_num)
            file_name = os.path.splitext(mesh[2])
            open3d.io.write_triangle_mesh(save_dir + '/' + file_name[0] + '.obj', m)
        t = (time.time() - start_time)
        print('t:', t)

    # 2.遍历 train
    cnt = 0
    for train_ in train:   # 所有类
        start_time = time.time()
        cnt = cnt + 1
        print(cnt)
        for mesh in train_:   # 每一类的所有obj
            # 2.1 读取
            vs, faces = load_off(mesh[0])
            m = open3d.geometry.TriangleMesh()
            m.vertices = open3d.utility.Vector3dVector(vs)
            m.triangles = open3d.utility.Vector3iVector(faces)
            # 2.2 路径
            save_dir = mesh[3].replace('ModelNet10', 'ModelNet10_' + str(face_num))
            if not os.path.isdir(save_dir):
                os.makedirs(save_dir, exist_ok=True)
            # 2.3 简化并保存
            while len(m.triangles) < face_num:
                m = m.subdivide_midpoint(number_of_iterations=1)
            m = m.simplify_quadric_decimation(face_num)
            file_name = os.path.splitext(mesh[2])
            open3d.io.write_triangle_mesh(save_dir + '/' + file_name[0] + '.obj', m)
        t = (time.time() - start_time)
        print('t:', t)

三、展望

  1. 保护边缘的网格简化
  2. 先计算完网格元素特征,再进行降采样
  3. 先水密化后简化,最好加入平滑等预处理

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

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

相关文章

JS逆向 -- 某联盟登录密码分析

一、输入账号密码 账号&#xff1a;15836353612 密码&#xff1a;123456 二、F12打开开发者工具&#xff0c;抓包分析&#xff0c;password被加密提交了 三、全局搜索password&#xff0c;定位到关键JS文件&#xff0c;下断调试 四、断下来后&#xff0c;查看formDate的值&…

AspNetCore中的中间件详解【超详细】

1 什么叫做中间件&#xff1f; ASP.NET Core处理请求的方式看做是一个管道&#xff0c;中间件是组装到应用程序管道中用来处理请求和响应的组件。通常是一个可重用的类方法 每个中间件可以&#xff1a; &#xff08;1&#xff09;选择是否将请求传递给管道中的下一个组件。 &a…

第一行代码 第七章 内容提供器

第七章 内容提供器 在上一章中我们学了Android数据持久化的技术&#xff0c;包括文件存储、SharedPreferences存储以及数据库存储。使用这些持久化技术所保存的数据都只能在当前应用程序中访问。 虽然文件和SharedPreferences存储中提供了MODE_WORLD_READABLE和MODE_WORLD_WR…

UU跑腿“跑男失联”:同城即配服务赛道商业逆袭难?

五一假期&#xff0c;人们纷纷走出家门&#xff0c;要么扎堆奔向“远方”&#xff0c;要么、享受本地烟火气息。 据文化和旅游部数据中心测算&#xff0c;劳动节假期&#xff0c;全国国内旅游出游合计2.74亿人次&#xff0c;同比增长70.83%。 五一假日的郑州东站 面对人山人海…

树莓派(主)与STM32(从)使用SPI通信

1.实验目的 2.SPI 简介 SPI&#xff08;Serial Peripheral Interface&#xff0c;串行外设接口&#xff09;是Motorola公司提出的一种同步串行数据传输标准 2.1 接口 SPI接口经常被称为4线串行总线&#xff0c;以主/从方式工作&#xff0c;数据传输过程由主机初始化。如图1…

【干货集】PCBA板边器件布局重要性

电子元器件在PCB板上的合理布局&#xff0c;是减少焊接缺点的极重要一环&#xff01;元器件要尽可能避开挠度值非常大的区域和高内应力区&#xff0c;布局应尽量匀称。 为了最大程度的利用电路板空间&#xff0c;相信很多做设计的小伙伴&#xff0c;会尽可能把元器件靠板的边缘…

机器学习基础知识之数据归一化

文章目录 归一化的原因1、最大最小归一化2、Z-score标准化3、不同方法的应用 归一化的原因 在进行机器学习训练时&#xff0c;通常一个数据集中包含多个不同的特征&#xff0c;例如在土壤重金属数据集中&#xff0c;每一个样本代表一个采样点&#xff0c;其包含的特征有经度、…

《程序员面试金典(第6版)》面试题 16.16. 部分排序(double双指针(多指针),C++)

题目描述 给定一个整数数组&#xff0c;编写一个函数&#xff0c;找出索引m和n&#xff0c;只要将索引区间[m,n]的元素排好序&#xff0c;整个数组就是有序的。注意&#xff1a;n-m尽量最小&#xff0c;也就是说&#xff0c;找出符合条件的最短序列。函数返回值为[m,n]&#xf…

什么是平台工程?如何开始?

平台工程是为开发人员构建和维护自助服务平台的学科。该平台提供了一套云原生工具和服务&#xff0c;帮助开发者快速高效地交付应用。平台工程的目标是通过标准化和自动化软件交付生命周期 (SDLC) 中的大部分任务来改善开发人员体验 (DX)。开发人员可以专注于使用自动化平台编码…

Type-C PD充电器诱骗PD+QC+AFC+FCP全协议快充取电5V9V12V15V20V

Type-C充电器采用的是PD快充协议&#xff0c;支持的电压高&#xff0c;电流大&#xff0c;一般有5V3A、9V3A、12V3A、15V3A、20V5A等等。 因为充电器内部有协议芯片&#xff0c;当外部设备连接时&#xff0c;设备会和充电器进行协议匹配&#xff0c;匹配成功之后&#xff0c;充…

ASEMI代理ADI亚德诺LT8609AJDDM#WTRPBF车规级芯片

编辑-Z LT8609AJDDM#WTRPBF特点&#xff1a; 宽输入电压范围&#xff1a;3.0V 至 42V 超低静态电流突发模式操作&#xff1a; 将 12VIN 调节到 3.3VOUT 时 IQ 为 2.5A 输出纹波 < 10mVP-P 高效 2MHz 同步操作&#xff1a; 1A 时效率为 93%, 12VIN 可获得 5VOUT 最大…

3.1 一个稍微完善的Vue.js响应式系统

前文提要&#xff1a;3.0 响应式系统的设计与实现 1、设置一个合理的effect副作用函数 如上文所说&#xff0c;如果我们直接将简单的effect函数作为副作用函数&#xff0c;如果一个副作用函数不叫effect岂不是找不到了。解决方案也很简单&#xff0c;我们设定一个全局变量用于…

在CRA中配置别名路径并添加别名路径提示

写在前面&#xff1a; 使用React官方脚手架create-react-app[简称CRA]创建react项目&#xff1a;npx create-react-app 项目名称 一、配置别名路径 1.1 写在前面 目的&#xff1a;简化项目中的路径处理&#xff0c;和Vue项目中的类似。 参考文档&#xff1a;自定义CRA的默认…

MySQL基础(十二)数据类型精讲

1. MySQL中的数据类型 类型类型举例整数类型TINYINT、SMALLINT、MEDIUMINT、INT(或INTEGER)、BIGINT浮点类型FLOAT、DOUBLE定点数类型DECIMAL位类型BIT日期时间类型YEAR、TIME、DATE、DATETIME、TIMESTAMP文本字符串类型CHAR、VARCHAR、TINYTEXT、TEXT、MEDIUMTEXT、LONGTEXT枚…

一个日期类深度认识operator符号重载

一&#xff1a;概念 在以前的C语言的学习中,如果我们需要比较两个整数并返回它的结果可以直接用与之相关的符号。例如我们可以直接写成A>B或者A<B一类的&#xff0c;但是它的局限性很大&#xff0c;只能比较内置类型&#xff0c;因为计算可以直接转换成对应的汇编代码进…

如何通过国外主机租用服务提高网站SEO排名?

当今的互联网已经成为了商业和社交活动的主要场所之一。在这个快速变化的数字时代&#xff0c;网站的搜索引擎优化(SEO)排名对于任何企业的成功都至关重要。一个好的SEO排名能够帮助企业吸引更多的访客和潜在客户&#xff0c;增加业务的转化率。而国外主机租用服务可以帮助您优…

【C++学习】函数模板

模板的概念 模板就是建立通用的模具&#xff0c;大大提高复用性。 模板的特点&#xff1a; 模板不可以直接使用&#xff0c;它只是一个模型 模板的通用不是万能的 基本语法 C中提供两种模板机制&#xff1a;函数模板和类模板 函数模板作用&#xff1a; 建立一个通用函数&…

C++学习day--05 C++数据类型

1、项目需求&#xff1a;实现黑客攻击系统菜单打印 实现&#xff1a; #include <iostream> #include <Windows.h> int main( void ) { std::cout << "1. 网站 404 攻击 " << std::endl; std::cout << "2. 网站篡改攻击 …

实验四 基于PPTP的远程VPN实现【网络安全】

实验四 基于PPTP的远程VPN实现【网络安全】 前言推荐实验四 基于PPTP的远程VPN实现使用&#xff1a;配置CentOS PPTP服务端配置CentOS PPTP客户端常见问题浏览器无法打开网页 最后 前言 2023-5-7 23:10:12 以下内容源自《【网络安全】》 仅供学习交流使用 推荐 第27节 远程…

TCP三次握手/四次挥手

TCP三次握手/四次挥手 TCP的三次握手和四次挥手实质就是TCP通信的连接和断开。 三次握手 任何基于TCP的应用&#xff0c;在发送数据之前&#xff0c;都需要由TCP进行三次握手进行连接 握手流程&#xff1a; 三次握手原理 第1次握手&#xff1a;客户端发送一个带有SYN&#…