def export_mesh(label_id, ds, bb_starts, bb_stops, resolution, out_path): if bb_starts is None: bb = np.s_[:] else: start, stop = bb_starts[label_id], bb_stops[label_id] bb = tuple( slice(int(sta), int(sto) + 1) for sta, sto in zip(start, stop)) seg = ds[bb] mask = seg == label_id n_foreground = mask.sum() # assert we have some meaningful number of foreground pixels assert n_foreground > 100 res_nm = [1000. * re for re in resolution] verts, faces, normals = marching_cubes(mask, resolution=res_nm) # go from zyx axis convention to xyz verts = verts[:, ::-1] normals = normals[:, ::-1] # offset the vertex coordinates if bb_starts is not None: offset = np.array([sta * re for sta, re in zip(start, res_nm)])[::-1] verts += offset # save to obj write_obj(out_path, verts, faces, normals)
def _compute_meshes_id_block(blocking, block_id, ds_in, output_path, sizes, bb_min, bb_max, resolution, size_threshold, smoothing_iterations, output_format): fu.log("start processing block %i" % block_id) block = blocking.getBlock(block_id) id_begin, id_end = block.begin[0], block.end[0] # we don't compute the skeleton for id 0, which is reserved for the ignore label id_begin = 1 if id_begin == 0 else id_begin # compute_meshes ids in range and serialize skeletons for seg_id in range(id_begin, id_end): if size_threshold is not None: if sizes[seg_id] < size_threshold: continue bb = tuple( slice(mi, ma) for mi, ma in zip(bb_min[seg_id], bb_max[seg_id])) obj = ds_in[bb] == seg_id # try to compute_meshes the object, skip if any exception is thrown verts, faces, normals = marching_cubes( obj, smoothing_iterations=smoothing_iterations, resolution=resolution) offsets = [b.start * res for b, res in zip(bb, resolution)] verts += np.array(offsets) if output_format == 'npy': out_path = os.path.join(output_path, '%i.npz' % seg_id) meshio.write_numpy(out_path, verts, faces, normals) else: out_path = os.path.join(output_path, '%.obj' % seg_id) meshio.write_obj(out_path, verts, faces, normals) fu.log_block_success(block_id)
def test_marching_cubes(self): from elf.mesh import marching_cubes shape = (64, ) * 3 seg = (np.random.rand(*shape) > 0.6).astype("uint32") verts, faces, normals = marching_cubes(seg) self.assertGreater(len(verts), 0) self.assertGreater(len(faces), 0) self.assertGreater(len(normals), 0)
def test_marching_cubes_smoothing(self): from elf.mesh import marching_cubes shape = (32, ) * 3 seg = (np.random.rand(*shape) > 0.6).astype("uint32") for smoothing_iterations in (1, 2, 3): verts, faces, normals = marching_cubes( seg, smoothing_iterations=smoothing_iterations) self.assertGreater(len(verts), 0) self.assertGreater(len(faces), 0) self.assertGreater(len(normals), 0)
def test_ply(self): from elf.mesh.io import read_ply, write_ply shape = (64, ) * 3 seg = (np.random.rand(*shape) > 0.6).astype("uint32") verts, faces, _ = marching_cubes(seg) write_ply(self.tmp_path, verts, faces) deverts, defaces = read_ply(self.tmp_path) self.assertTrue(np.allclose(verts, deverts)) self.assertTrue(np.allclose(faces, defaces))