def gen_mesh_from_voxels_mc(voxels, voxelsize): import scipy.spatial as scsp tri = marching_cubes(voxels, voxelsize) nel, nnd, dim = tri.shape coors = tri.reshape((nel * nnd, dim)) tree = scsp.ckdtree.cKDTree(coors) eps = nm.max(coors.max(axis=0) - coors.min(axis=0)) * 1e-6 dist, idx = tree.query(coors, k=24, distance_upper_bound=eps) uniq = set([]) for ii in idx: ukey = ii[ii < tree.n] ukey.sort() uniq.add(tuple(ukey)) ntri = nm.ones((nel * nnd, ), dtype=nm.int32) nnod = len(uniq) ncoors = nm.zeros((nnod, 3), dtype=nm.float64) for ii, idxs in enumerate(uniq): ntri[nm.array(idxs)] = ii ncoors[ii] = coors[idxs[0]] mesh = Mesh.from_data('voxel_mc_data', ncoors, nm.ones((nnod, ), dtype=nm.int32), {0: nm.ascontiguousarray(ntri.reshape((nel, nnd)))}, {0: nm.ones( (nel, ), dtype=nm.int32)}, {0: '%d_%d' % (2, 3)}) return mesh
def gen_mesh_from_voxels_mc(voxels, voxelsize): import scipy.spatial as scsp tri = marching_cubes(voxels, voxelsize) nel, nnd, dim = tri.shape coors = tri.reshape((nel * nnd, dim)) tree = scsp.ckdtree.cKDTree(coors) eps = nm.max(coors.max(axis=0) - coors.min(axis=0)) *1e-6 dist, idx = tree.query(coors, k=24, distance_upper_bound=eps) uniq = set([]) for ii in idx: ukey = ii[ii < tree.n] ukey.sort() uniq.add(tuple(ukey)) ntri = nm.ones((nel * nnd,), dtype=nm.int32) nnod = len(uniq) ncoors = nm.zeros((nnod, 3), dtype=nm.float64) for ii, idxs in enumerate(uniq): ntri[nm.array(idxs)] = ii ncoors[ii] = coors[idxs[0]] mesh = Mesh.from_data('voxel_mc_data', ncoors, nm.ones((nnod,), dtype=nm.int32), {0: nm.ascontiguousarray(ntri.reshape((nel, nnd)))}, {0: nm.ones((nel,), dtype=nm.int32)}, {0: '%d_%d' % (2, 3)}) return mesh
def test_export(): u = np.zeros((10, 10, 10)) u[2:-2, 2:-2, 2:-2] = 1.0 vertices, triangles = mcubes.marching_cubes(u, 0.5) mcubes.export_obj(vertices, triangles, "output/test.obj") mcubes.export_off(vertices, triangles, "output/test.off") mcubes.export_mesh(vertices, triangles, "output/test.dae")
def gen_mesh_from_voxels_mc(voxels, voxelsize, gmsh3d=False, scale_factor=0.25): import scipy.spatial as scsp tri = marching_cubes(voxels, voxelsize) nel, nnd, dim = tri.shape coors = tri.reshape((nel * nnd, dim)) tree = scsp.ckdtree.cKDTree(coors) eps = nm.max(coors.max(axis=0) - coors.min(axis=0)) *1e-6 dist, idx = tree.query(coors, k=24, distance_upper_bound=eps) uniq = set([]) for ii in idx: ukey = ii[ii < tree.n] ukey.sort() uniq.add(tuple(ukey)) ntri = nm.ones((nel * nnd,), dtype=nm.int32) nnod = len(uniq) ncoors = nm.zeros((nnod, 3), dtype=nm.float64) for ii, idxs in enumerate(uniq): ntri[nm.array(idxs)] = ii ncoors[ii] = coors[idxs[0]] mesh = Mesh.from_data('voxel_mc_data', ncoors, nm.ones((nnod,), dtype=nm.int32), {0: nm.ascontiguousarray(ntri.reshape((nel, nnd)))}, {0: nm.ones((nel,), dtype=nm.int32)}, {0: '%d_%d' % (2, 3)}) if gmsh3d: from vtk2stl import vtk2stl import tempfile import os auxfile = os.path.join(tempfile.gettempdir(), 'dicom2fem_aux') vtk_fn = auxfile + '_surfmc.vtk' stl_fn = auxfile + '_surfmc.stl' geo_fn = auxfile + '_surf2vol.geo' mesh_fn = auxfile + '_volmv.mesh' mesh.write(vtk_fn) vtk2stl(vtk_fn, stl_fn) geofile = open(geo_fn, 'wt') geofile.write(gmsh3d_geo.replace('__INFILE__', stl_fn).replace('__SCFACTOR__', str(scale_factor))) geofile.close() os.system('gmsh -3 -format mesh -o %s %s' % (mesh_fn, geo_fn)) mesh = Mesh.from_file(mesh_fn) return mesh
def test_sphere(): x, y, z = np.mgrid[:100, :100, :100] u = (x - 50)**2 + (y - 50)**2 + (z - 50)**2 - 25**2 def func(x, y, z): return (x - 50)**2 + (y - 50)**2 + (z - 50)**2 - 25**2 vertices1, triangles1 = mcubes.marching_cubes(u, 0.0) vertices2, triangles2 = mcubes.marching_cubes_func( (0, 0, 0), (99, 99, 99), 100, 100, 100, func, 0.0) assert_allclose(vertices1, vertices2) assert_array_equal(triangles1, triangles2)
def extract_mesh(query_fn, feature_array, network_fn, args, voxel_size=0.01, isolevel=0.0, scene_name='', mesh_savepath=''): # Query network on dense 3d grid of points voxel_size *= args.sc_factor # in "network space" tx, ty, tz = scene_bounds.get_scene_bounds(scene_name, voxel_size, True) query_pts = np.stack(np.meshgrid(tx, ty, tz, indexing='ij'), -1).astype(np.float32) print(query_pts.shape) sh = query_pts.shape flat = query_pts.reshape([-1, 3]) fn = get_batch_query_fn(query_fn, feature_array, network_fn) chunk = 1024 * 64 raw = np.concatenate([fn(flat, i, i + chunk)[0].numpy() for i in range(0, flat.shape[0], chunk)], 0) raw = np.reshape(raw, list(sh[:-1]) + [-1]) sigma = raw[..., -1] print('Running Marching Cubes') vertices, triangles = mcubes.marching_cubes(sigma, isolevel, truncation=3.0) print('done', vertices.shape, triangles.shape) # normalize vertex positions vertices[:, :3] /= np.array([[tx.shape[0] - 1, ty.shape[0] - 1, tz.shape[0] - 1]]) # Rescale and translate scale = np.array([tx[-1] - tx[0], ty[-1] - ty[0], tz[-1] - tz[0]]) offset = np.array([tx[0], ty[0], tz[0]]) vertices[:, :3] = scale[np.newaxis, :] * vertices[:, :3] + offset # Transform to metric units vertices[:, :3] = vertices[:, :3] / args.sc_factor - args.translation # Create mesh mesh = trimesh.Trimesh(vertices, triangles, process=False) # Transform the mesh to Scannet's coordinate system gl_to_scannet = np.array([[1, 0, 0, 0], [0, 0, -1, 0], [0, 1, 0, 0], [0, 0, 0, 1]]).astype(np.float32).reshape([4, 4]) mesh.apply_transform(gl_to_scannet) if mesh_savepath == '': mesh_savepath = os.path.join(args.basedir, args.expname, f"mesh_vs{voxel_size / args.sc_factor.ply}") mesh.export(mesh_savepath) print('Mesh saved')
def test_gaussian_smoothing(): # Create sphere with radius 25 centered at (50, 50, 50) x, y, z = np.mgrid[:100, :100, :100] levelset = np.sqrt((x - 50)**2 + (y - 50)**2 + (z - 50)**2) - 25 binary_levelset = levelset > 0 smoothed_levelset = mcubes.smooth(binary_levelset, method='gaussian', sigma=3) vertices, _ = mcubes.marching_cubes(smoothed_levelset, 0.0) # Check all vertices have same distance to (50, 50, 50) dist = np.sqrt(np.sum((vertices - [50, 50, 50])**2, axis=1)) assert dist.min() > 24 and dist.max() < 25
def test_sphere(): # Create sphere with radius 25 centered at (50, 50, 50) x, y, z = np.mgrid[:100, :100, :100] levelset = np.sqrt((x - 50)**2 + (y - 50)**2 + (z - 50)**2) - 25 # vertices, triangles = mcubes.marching_cubes(levelset, 0) # mcubes.export_obj(vertices, triangles, 'sphere1.obj') binary_levelset = levelset > 0 smoothed_levelset = mcubes.smooth(binary_levelset, method='constrained', max_iters=500, rel_tol=1e-4) vertices, _ = mcubes.marching_cubes(smoothed_levelset, 0.0) # Check all vertices have same distance to (50, 50, 50) dist = np.sqrt(np.sum((vertices - [50, 50, 50])**2, axis=1)) assert dist.min() > 24.5 and dist.max() < 25.5 assert np.all(np.abs(smoothed_levelset - levelset) < 1) assert np.all((smoothed_levelset > 0) == binary_levelset)
import sys sys.path.append( '../../' ) # https://stackoverflow.com/questions/15109548/set-pythonpath-before-import-statements from marching_cubes import marching_cubes test_data = [[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 1, 0], [0, 1, 1, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]] if __name__ == "__main__": marching_cubes(test_data, 'fourpoint.obj')
def test_empty(): levelset = np.zeros((50, 50, 50)) vertices, triangles = mcubes.marching_cubes(levelset, 0.5) assert len(vertices) == len(triangles) == 0
import sys sys.path.append( '../../' ) # https://stackoverflow.com/questions/15109548/set-pythonpath-before-import-statements from marching_cubes import marching_cubes test_data = [[[0, 0, 0], [0, 0, 0], [0, 0, 0]], [[0, 0, 0], [0, 1, 0], [0, 0, 0]], [[0, 0, 0], [0, 0, 0], [0, 0, 0]]] if __name__ == "__main__": marching_cubes(test_data, 'onepoint.obj')
if c > 128: r.append(0) else: r.append(1) t.append(r) for r in t: print r data = [] for j in range(n): plane = [] for i in range(2 * n): r = [] for k in range(2 * n): jj = j ii = int(math.sqrt((i - n)**2 + (k - n)**2)) if ii >= 0 and ii < n and jj < n: r.append(t[ii][jj]) else: r.append(0) plane.append(r) data.append(plane) return data if __name__ == "__main__": data = generate_data_rotate('cup.png', 30) marching_cubes(data, 'cup.obj')
def generate_data(xDim, yDim, zDim): n = yDim data = [] for j in range(yDim): rc = [] for i in range(xDim): r = [] for k in range(zDim): f = 0.0 d = glm.length( glm.vec3(i, j, k) - glm.vec3(n / 2, n / 2, n / 2)) f = n / 3 - d if f > 0.0: r.append(1) else: r.append(0) rc.append(r) data.append(rc) return data test_data = generate_data(96, 96, 96) if __name__ == "__main__": marching_cubes(test_data, 'sphere.obj')
import numpy as np import marching_cubes as mcubes print("Example 1: Isosurface in NumPy volume...") #print(mcubes.__dir__()) # Create a data volume (100 x 100 x 100) X, Y, Z = np.mgrid[:100, :100, :100] sdf = (X - 50)**2 + (Y - 50)**2 + (Z - 50)**2 - 25**2 # Extract the 0-isosurface vertices, triangles = mcubes.marching_cubes(sdf, 0) mcubes.export_obj(vertices, triangles, "sphere.obj") print("Example 2: Isosurface and color in NumPy volume...") # Extract isosurface and color #color = 0.01 * np.concatenate((X[:,:,:,None],X[:,:,:,None],X[:,:,:,None]), axis=3) # color array (grayscale gradient in this example) color = 0.01 * np.concatenate( (X[:, :, :, None], Y[:, :, :, None], Z[:, :, :, None]), axis=3) # color array (positions as color) vertices_color, triangles_color = mcubes.marching_cubes_color(sdf, color, 0) mcubes.export_obj(vertices_color, triangles_color, "sphere_color.obj") mcubes.export_off(vertices_color, triangles_color, "sphere_color.off") print("Example 3: TSDF isosurface with super resolution...") dim = 100 # Create a data volume (100 x 100 x 100)
def visualize_sdf(sdf, output_path, level=0.75): vertices, triangles = mc.marching_cubes(sdf.astype(float), level) mc.export_obj(vertices, triangles, output_path)
def generate_data(xDim, yDim, zDim): n = yDim data = [] for j in range(yDim): rc = [] for i in range(xDim): r = [] for k in range(zDim): f = 0.0 d = glm.length( glm.vec3(i, j, k) - glm.vec3(n / 2, n / 2, n / 2)) f = n / 3 - d if f > 0.0: r.append(1) else: r.append(0) rc.append(r) data.append(rc) return data test_data = generate_data(96, 96, 96) if __name__ == "__main__": marching_cubes(test_data, 'cascade.obj')
import sys sys.path.append( '../../' ) # https://stackoverflow.com/questions/15109548/set-pythonpath-before-import-statements from marching_cubes import marching_cubes test_data = [[[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 1, 1, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]], [[0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0], [0, 0, 0, 0]]] if __name__ == "__main__": marching_cubes(test_data, 'twopoint.obj')