• Python 三维网格体素化


    本文主要是实现将一个网格模型体素化,实现不同分辨率的体素化效果,并且可视化输出为obj文件!首先利用trimesh对mesh进行采样,然后根据采样点得到各个体素点的占有值。

    效果

    通过调整分辨率以及采样率(当分辨率变高时建议适量提高采样率)得到以下的效果!
    请添加图片描述

    代码

    #!/usr/bin/env python3
    # -*- coding: utf-8 -*-
    """
    @author: Matthieu Zins
    """
    
    import trimesh
    import numpy as np
    import os
    import argparse
    
    """
        ======   Voxelize the surface of a mesh   ======
    """
    
    
    
    def create_if_needed(folder):
        if not os.path.isdir(folder):
            os.mkdir(folder)
    
    
    
    parser = argparse.ArgumentParser(description='Pass object name')
    parser.add_argument('input_mesh', type=str)
    parser.add_argument('--output_folder', type=str, default="")
    parser.add_argument('--resolution', type=int, nargs=3, default=[50, 50, 50], 
                        help="resolution_X resolution_Y resolution_Z")
    parser.add_argument('--sampling', type=int, default="100000",
                        help="number of points sampled on the mesh")
    args = parser.parse_args()
    
    
    input_mesh_filename = args.input_mesh
    object_name = os.path.splitext(os.path.basename(input_mesh_filename))[0]
    output_folder = args.output_folder
    if len(output_folder) == 0: output_folder = object_name
    RES_X, RES_Y, RES_Z = args.resolution
    sample_points_count = args.sampling
    
    create_if_needed(output_folder)
    
    
    mesh = trimesh.exchange.load.load(input_mesh_filename)
    
    
    # Uniform Points Sampling
    pts, _ = trimesh.sample.sample_surface_even(mesh, sample_points_count )
    
    # Save sample points
    sampled_points_mesh = trimesh.Trimesh(vertices=pts)
    sampled_points_mesh.export(os.path.join(output_folder, object_name + "_resampled_points.ply"))
    
    
    # Adjust the grid origin and voxels size
    origin = pts.min(axis=0)
    dimensions = pts.max(axis=0) - pts.min(axis=0)
    scales = np.divide(dimensions, np.array([RES_X-1, RES_Y-1, RES_Z-1]))
    scale = np.max(scales)
    
    
    # Voxelize
    
    pts -= origin
    pts /= scale
    pts_int = np.round(pts).astype(int)
    
    grid = np.zeros((RES_X, RES_Y, RES_Z), dtype=int)
    gooRES_X = np.where(np.logical_and(pts_int[:, 0] >= 0, pts_int[:, 0] < RES_X))[0]
    gooRES_Y = np.where(np.logical_and(pts_int[:, 1] >= 0, pts_int[:, 1] < RES_Y))[0]
    gooRES_Z = np.where(np.logical_and(pts_int[:, 2] >= 0, pts_int[:, 2] < RES_Z))[0]
    goods = np.intersect1d(np.intersect1d(gooRES_X, gooRES_Y), gooRES_Z)
    pts_int = pts_int[goods, :]
    grid[pts_int[:, 0], pts_int[:, 1], pts_int[:, 2]] = 1
    
    
    
    
    # Save voxels
    voxel_pts = np.array([[-0.5, 0.5, -0.5],
                          [0.5, 0.5, -0.5],
                          [0.5, 0.5, 0.5],
                          [-0.5, 0.5, 0.5],
                          [-0.5, -0.5, -0.5],
                          [0.5, -0.5, -0.5],
                          [0.5, -0.5, 0.5],
                          [-0.5, -0.5, 0.5]])
    voxel_faces = np.array([[0, 1, 2, 3],
                            [1, 5, 6, 2],
                            [5, 4, 7, 6],
                            [4, 0, 3, 7],
                            [0, 4, 5, 1],
                            [7, 3, 2, 6]])
    
    def get_voxel(i, j, k):
        global voxel_pts, voxel_faces
        v = np.array([i, j, k], dtype=float) * scale
        v += origin
        points = voxel_pts * scale + v
        return points, voxel_faces.copy()
    
    points = []
    faces = []
    fi = 0
    for i in range(RES_X):
        for j in range(RES_Y):
            for k in range(RES_Z):
                if grid[i, j, k]:
                    p, f = get_voxel(i, j, k)
                    points.append(p)
                    f += fi
                    faces.append(f)
                    fi += 8
    
    points = np.vstack(points)
    faces = np.vstack(faces)
    # Write obj mesh with quad faces
    with open(os.path.join(output_folder, object_name + "_voxels.obj"), "w") as fout:
        for p in points:fout.write("v " + " ".join(map(str, p)) + "\n")
        for f in faces+1:fout.write("f " + " ".join(map(str, f)) + "\n")
    
    
    print(object_name, "done.")
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123

    运行
    Dependencies

    • numpy
    • trimesh
    ## Usage
    
    python voxelize_surface.py example/chair.obj --output_folder output --resolution 30 30 30 --sampling 10000
    
    
    • 1
    • 2
    • 3
    • 4

    The optional parameters are:

    • output_folder (string): folder where the result is saved
    • resolution (list): the resolution of the grid [res_x, res_y, res_z]
    • sampling (int): number of points sampled on the mesh surface before voxelization
    • :输入的类型可以时obj也可以是off以及ply格式!

    注意:若出现如下情况,可将采样点数(sampling)提高!出现此种情况的原因是采样间隔太大,而体素尺寸太小(分辨太高),所以导致在有些体素的占有值进行判断的时候出现错误。所以也可以通过降低分辨率来改善此种情况!

    在这里插入图片描述

    Reference

    声明: 本文的代码并非原创,来自GitHub中zinsmatt的Surface_Voxels一作!若有侵权请联系撤文!

    https://github.com/zinsmatt/Surface_Voxels

  • 相关阅读:
    深入了解java锁升级可以应对各种疑难问题
    坚持每天做一件事情的意义
    等差数列和等比数列 常用公式
    【python】入门第一课:了解基本语法(数据类型)
    NFT与奢侈品文化的天然契合:NFT满足了人类寻求独特性和地位的天性
    通过包管理器方式安装 Node.js
    复杂SQL收集
    【Swift 60秒】40 - Parameter labels
    Java版分布式微服务云开发架构 Spring Cloud+Spring Boot+Mybatis 电子招标采购系统功能清单
    Java Maven POM配置参考
  • 原文地址:https://blog.csdn.net/weixin_42145554/article/details/127985983