def mesh_from_dvid_tarfile(server, uuid, tsv_instance, bodies, simplify=1.0, drop_normals=False, rescale_factor=1.0, output_path='{body}.obj'): from neuclease.dvid import fetch_tarfile for body in bodies: logger.info(f"Body {body}: Fetching tarfile") tar_bytes = fetch_tarfile(server, uuid, tsv_instance, body) logger.info(f"Body {body}: Loading mesh") mesh = Mesh.from_tarfile(tar_bytes) if simplify != 1.0: logger.info(f"Body {body}: Simplifying") mesh.simplify(simplify, in_memory=True) if drop_normals: mesh.drop_normals() if rescale_factor != 1.0: logger.info(f"Body {body}: Scaling by {rescale_factor}x") mesh.vertices_zyx[:] *= rescale_factor p = output_path.format(body=body) logger.info(f"Body {body}: Serializing to {p}") mesh.serialize(p)
def decimate_existing_mesh(server, uuid, instance, body_id, fraction, max_vertices=1e9, rescale=1.0, output_format=None, output_path=None, output_dvid=None, tar_bytes=None): """ Fetch all supervoxel meshes for the given body, combine them into a single mesh, and then decimate that mesh at the specified fraction. The output will be written to a file, or to a dvid instance (or both). Args: tar_bytes: Optional. You can provide the tarfile contents (as bytes) directly, in which case the input server will not be used. """ if output_path is not None: fmt = os.path.splitext(output_path)[1][1:] if output_format is not None and output_format != fmt: raise RuntimeError(f"Mismatch between output format '{output_format}'" f" and output file extension in '{output_path}'") output_format = fmt if output_format is None: raise RuntimeError("You must specify an output format (or an output path with a file extension)") assert output_format in Mesh.MESH_FORMATS, \ f"Unknown output format: {output_format}" assert output_path is not None or output_dvid is not None, \ "No output location specified" if tar_bytes is None: with Timer(f"Body: {body_id} Fetching tarfile", logger): tar_bytes = fetch_tarfile(server, uuid, instance, body_id) with Timer(f"Body: {body_id}: Loading mesh for body {body_id}", logger): mesh = Mesh.from_tarfile(tar_bytes, keep_normals=False) mesh_mb = mesh.uncompressed_size() / 1e6 orig_vertices = len(mesh.vertices_zyx) logger.info(f"Body: {body_id}: Original mesh has {orig_vertices} vertices and {len(mesh.faces)} faces ({mesh_mb:.1f} MB)") fraction = min(fraction, max_vertices / len(mesh.vertices_zyx)) with Timer(f"Body: {body_id}: Decimating at {fraction:.2f}", logger): mesh.simplify(fraction, in_memory=True) mesh_mb = mesh.uncompressed_size() / 1e6 logger.info(f"Body: {body_id}: Final mesh has {len(mesh.vertices_zyx)} vertices and {len(mesh.faces)} faces ({mesh_mb:.1f} MB)") if not isinstance(rescale, Iterable): rescale = 3*[rescale] rescale = np.asarray(rescale) if not (rescale == 1.0).all(): mesh.vertices_zyx[:] *= rescale with Timer(f"Body: {body_id}: Serializing", logger): mesh_bytes = None if output_dvid is not None: assert len(output_dvid) == 3 mesh_bytes = mesh.serialize(fmt=output_format) post_key(*output_dvid, f"{body_id}.{output_format}", mesh_bytes) if output_path: if mesh_bytes is None: mesh.serialize(output_path) else: with open(output_path, 'wb') as f: f.write(mesh_bytes) return len(mesh.vertices_zyx), fraction, orig_vertices