Source code for aicsimageprocessing.isosurfaceGenerator

# author: Zach Crabtree zacharyc@alleninstitute.org

import os

from aicsimageio import AICSImage
from skimage import measure


[docs]class Mesh: """ A cell mesh class contains the necessary information to generate a display a 3D isosurface. Examples -------- >>> image = AICSImage("some/bio/image.ome.tif") ... mesh0 = generate_mesh(image.data, isovalue=0, channel=0) ... # will generate a different mesh due to the different isovalue ... mesh1 = generate_mesh(image.data, isovalue=1, channel=0) ... mesh0.save_as_obj("some/bio/image/mesh.obj") ... # mesh.obj can be imported into 3D viewers and represents a 3D rendering of ... # image.ome.tif """ def __init__(self, verts, faces, normals, values): self.verts = verts self.faces = faces self.normals = normals self.values = values
[docs] def save_as_obj(self, file_path): """ Save a mesh object as an .obj file :param file_path: The filepath to the saved file """ if not file_path.endswith(".obj"): if file_path.rfind(".") != -1: file_path = os.path.splitext(file_path)[0] + ".obj" else: file_path += ".obj" with open(file_path, "w") as writer: writer.write("# OBJ file\n") writer.write("g Object001\n") for v in self.verts: writer.write("v {:.6f} {:.6f} {:.6f}\n".format(v[0], v[1], v[2])) if self.normals: for n in self.normals: writer.write( "vn {:.6f} {:.6f} {:.6f}\n".format(n[0], n[1], n[2]) ) for f in self.faces: # obj file vertex arrays are not 0-indexed :( must add 1 in order to # reference the right vertices writer.write("f {} {} {}\n".format(f[0] + 1, f[1] + 1, f[2] + 1))
[docs]def generate_mesh(image, isovalue=0, channel=0): """ Creates and returns a Mesh object Parameters ---------- image an AICSImage object isovalue The value that is used to pick the isosurface returned by the marching cubes algorithm For more info: https://www.youtube.com/watch?v=5fNbCFjqWao @ 40:00 mins channel The channel in the image that is used to extract the isosurface Returns ------- A Mesh object """ if not isinstance(image, AICSImage): raise ValueError("Meshes can only be generated with AICSImage objects!") if channel >= image.dims.C: raise IndexError( "Channel provided for mesh generation is out of bounds for image data!" ) image_stack = image.get_image_data("ZYX", C=channel) # Use marching cubes to obtain the surface mesh of the membrane wall verts, faces, normals, values = measure.marching_cubes( image_stack, isovalue, allow_degenerate=False ) return Mesh(verts, faces, normals, values)