Python三维网格体素化实例

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

Python三维网格体素化

本文主要是实现将一个网格模型体素化,实现不同分辨率的体素化效果,并且可视化输出为obj文件!

首先利用trimesh对mesh进行采样,然后根据采样点得到各个体素点的占有值。

效果

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

代码

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

#!/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.")

运行: 

Dependencies

  • numpy

  • trimesh

1

2

3

## Usage

 

python voxelize_surface.py example/chair.obj --output_folder output --resolution 30 30 30 --sampling 10000

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

你也想0元试听小码王编程课程吗?
填写信息免费预约
免责申明:以上展示内容来源于合作媒体、企业机构、网友提供或网络收集整理,版权争议与本站无关,文章涉及见解与观点不代表小码王官方立场,请读者仅做参考。本文标题:Python三维网格体素化实例,本文链接:https://www.xiaomawang.cn/help/200993.html;欢迎转载,转载请说明出处。若您认为本文侵犯了您的版权信息,或您发现该内容有任何涉及有违公德、触犯法律等违法信息,请您立即通过邮件(邮箱号: hzlixy@xiaoma.cn)联系我们及时修正或删除。
校区接待前厅
校区太空走廊
校区教室环境
校区多功能教室
小码王少儿编程体验课程免费预约