def nuclei_detection(reference_img, threshold=1000, radius_range=(0.8,1.4), step=0.2, segmentation_centering=False, subsampling=4, microscope_orientation=1): size = np.array(reference_img.shape) voxelsize = microscope_orientation*np.array(reference_img.voxelsize) positions = detect_nuclei(reference_img,threshold=threshold,radius_range=radius_range, step=step) positions = array_dict(positions) positions = array_dict(positions.values(),positions.keys()+2).to_dict() if segmentation_centering: nuclei_img = deepcopy(reference_img) image_coords = tuple(np.transpose((positions.values()/voxelsize).astype(int))) if subsampling>1: #nuclei_img = nd.gaussian_filter(nuclei_img,sigma=subsampling/4.)[::subsampling,::subsampling,::subsampling] nuclei_img = nd.gaussian_filter1d(nd.gaussian_filter1d(nuclei_img,sigma=subsampling/8.,axis=0),sigma=subsampling/8.,axis=1)[::subsampling,::subsampling,:] nuclei_img = SpatialImage(nuclei_img,voxelsize=(subsampling*reference_img.voxelsize[0],subsampling*reference_img.voxelsize[1],reference_img.voxelsize[2])) image_coords = tuple(np.transpose((positions.values()/(microscope_orientation*np.array(nuclei_img.voxelsize))).astype(int))) intensity_min = np.percentile(nuclei_img[image_coords],0)-1 segmented_img = nuclei_active_region_segmentation(nuclei_img, positions, display=False, omega_energies=dict(intensity=subsampling,gradient=1.5,smoothness=10000.0*np.power(subsampling,1.5)), intensity_min=intensity_min) positions = nuclei_positions_from_segmented_image(segmented_img) positions = array_dict(positions) positions = array_dict(positions.values()*microscope_orientation,positions.keys()).to_dict() return positions
def cut_surface_topomesh(input_topomesh, z_cut=0, below=True): topomesh = deepcopy(input_topomesh) compute_topomesh_property(topomesh,'vertices',2) if below: triangle_below = array_dict(np.all(topomesh.wisp_property('barycenter',0).values(topomesh.wisp_property('vertices',2).values())[...,2] < z_cut,axis=1),list(topomesh.wisps(2))) else: triangle_below = array_dict(np.all(topomesh.wisp_property('barycenter',0).values(topomesh.wisp_property('vertices',2).values())[...,2] > z_cut,axis=1),list(topomesh.wisps(2))) topomesh.update_wisp_property('below',2,triangle_below) triangles_to_remove = [t for t in topomesh.wisps(2) if triangle_below[t]] for t in triangles_to_remove: topomesh.remove_wisp(2,t) topomesh = clean_topomesh(topomesh) compute_topomesh_property(topomesh,'triangles',1) compute_topomesh_property(topomesh,'vertices',1) compute_topomesh_property(topomesh,'length',1) topomesh.update_wisp_property('boundary',1,array_dict((np.array(map(len,topomesh.wisp_property('triangles',1).values()))==1).astype(int),list(topomesh.wisps(1)))) boundary_edges = np.array(list(topomesh.wisps(1)))[topomesh.wisp_property('boundary',1).values()==1] boundary_vertices = np.unique(topomesh.wisp_property('vertices',1).values(boundary_edges)) # z_offset = topomesh.wisp_property('barycenter',0).values()[:,2].std()/8. z_offset = np.percentile(topomesh.wisp_property('length',1).values(),10) iso_z_positions = np.array([np.concatenate([topomesh.wisp_property('barycenter',0)[v][:2],[z_cut+(1-2*below)*z_offset]]) if v in boundary_vertices else topomesh.wisp_property('barycenter',0)[v] for v in topomesh.wisps(0)]) topomesh.update_wisp_property('barycenter',0,array_dict(iso_z_positions,list(topomesh.wisps(0)))) return topomesh
def characteristic_dimension(self): if self.char_dimension is None: if len(self.points)>1: if len(self.triangles)>0: triangle_edge_list = [[1,2],[0,2],[0,1]] triangle_edges = np.concatenate(np.array(self.triangles.values())[:,triangle_edge_list]) triangle_edge_points = array_dict(self.points).values(triangle_edges) triangle_edge_vectors = triangle_edge_points[:,1] - triangle_edge_points[:,0] triangle_edge_lengths = np.linalg.norm(triangle_edge_vectors,axis=1) self.char_dimension = triangle_edge_lengths.mean() elif len(self.edges)>0: edges = np.array(self.edges.values()) edge_points = array_dict(self.points).values(edges) edge_vectors = edge_points[:,1] - edge_points[:,0] edge_lengths = np.linalg.norm(edge_vectors,axis=1) self.char_dimension = edge_lengths.mean() else: #from scipy.cluster.vq import vq #point_distances = np.sort([vq(np.array(self.points.values()),np.array([self.points[p]]))[1] for p in self.points.keys()]) # self.char_dimension = point_distances[:,1].mean() bbox = np.array(self.bounding_box()) bbox_volume = np.prod(bbox[:,1] - bbox[:,0]) point_volume = bbox_volume/float(2.*len(self.points)) self.char_dimension = np.power(3.*point_volume/(4.*np.pi),1/3.) return self.char_dimension else: return 1. else: return self.char_dimension
def draw_triangular_mesh(mesh, mesh_id=None, colormap=None): import openalea.plantgl.all as pgl import openalea.plantgl.ext.color as color triangle_points = array_dict(mesh.points).values(np.array(mesh.triangles.values())) triangle_normals = np.cross(triangle_points[:,1]-triangle_points[:,0],triangle_points[:,2]-triangle_points[:,0]) mesh_center = np.mean(mesh.points.values(),axis=0) reversed_normals = np.array(mesh.triangles.keys())[np.where(np.einsum('ij,ij->i',triangle_normals,triangle_points[:,0]-mesh_center) < 0)[0]] for t in reversed_normals: mesh.triangles[t] = list(reversed(mesh.triangles[t])) if colormap is None: colormap = color.GlasbeyMap(0,255) points_index = array_dict(np.arange(len(mesh.points)),mesh.points.keys()) if isinstance(colormap,color.GlasbeyMap): if isiterable(mesh.triangle_data.values()[0]): colors = [pgl.Color4(colormap(mesh.triangle_data[t][0]%256).i3tuple()) if mesh.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in mesh.triangles.keys()] else: colors = [pgl.Color4(colormap(mesh.triangle_data[t]%256).i3tuple()) if mesh.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in mesh.triangles.keys()] else: if isiterable(mesh.triangle_data.values()[0]): colors = [pgl.Color4(colormap(mesh.triangle_data[t][0]).i3tuple()) if mesh.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in mesh.triangles.keys()] else: colors = [pgl.Color4(colormap(mesh.triangle_data[t]).i3tuple()) if mesh.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in mesh.triangles.keys()] scene = pgl.Scene() if mesh_id is not None: scene += pgl.Shape(pgl.FaceSet(mesh.points.values(),list(points_index.values(np.array(mesh.triangles.values()))),colorList=colors,colorPerVertex=False),id=int(mesh_id)) else: scene += pgl.Shape(pgl.FaceSet(mesh.points.values(),list(points_index.values(np.array(mesh.triangles.values()))),colorList=colors,colorPerVertex=False)) return scene
def _repr_geom_(self): import openalea.plantgl.all as pgl import vplants.plantgl.ext.color as color from openalea.container import array_dict scene = pgl.Scene() colormap = color.GlasbeyMap(0,256) if len(self.triangles) > 0: triangle_points = array_dict(self.points).values(self.triangles.values()) triangle_normals = np.cross(triangle_points[:,1]-triangle_points[:,0],triangle_points[:,2]-triangle_points[:,0]) mesh_center = np.mean(self.points.values(),axis=0) reversed_normals = np.array(self.triangles.keys())[np.where(np.einsum('ij,ij->i',triangle_normals,triangle_points[:,0]-mesh_center) < 0)[0]] for t in reversed_normals: self.triangles[t] = list(reversed(self.triangles[t])) points_index = array_dict(np.arange(len(self.points)),self.points.keys()) if isiterable(self.triangle_data.values()[0]): colors = [pgl.Color4(colormap(self.triangle_data[t][0]%256).i3tuple()) if self.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in self.triangles.keys()] else: colors = [pgl.Color4(colormap(self.triangle_data[t]%256).i3tuple()) if self.triangle_data.has_key(t) else pgl.Color4(colormap(0).i3tuple()) for t in self.triangles.keys()] # scene += pgl.Shape(pgl.FaceSet(self.points.values(),list(points_index.values(self.triangles.values()))),pgl.Material((255,255,255))) scene += pgl.Shape(pgl.FaceSet(self.points.values(),list(points_index.values(self.triangles.values())),colorList=colors,colorPerVertex=False)) #for t in self.triangles.keys(): # scene += pgl.Shape(pgl.FaceSet([self.points[p] for p in self.triangles[t]],[list(range(3))]),pgl.Material(colormap(self.triangle_data[t]%256).i3tuple()),id=t) else: for p in self.points.keys(): mat = pgl.Material(colormap(p%256).i3tuple(),transparency=0.0,name=p) scene += pgl.Shape(pgl.Translated(self.points[p],pgl.Sphere(self.point_radius,slices=16,stacks=16)),mat,id=p) return scene
def property_spatial_image_to_triangular_mesh(image, property_name=None, labels=None, coef=1): from openalea.cellcomplex.property_topomesh.utils.image_tools import composed_triangular_mesh cell_triangular_meshes = deepcopy(image.cell_meshes) img_labels = cell_triangular_meshes.keys() if labels is None: labels = image.labels if coef != 1: for l in labels: cell_center = np.mean(cell_triangular_meshes[l].points.values(), axis=0) points = cell_center + coef * ( cell_triangular_meshes[l].points.values() - cell_center) cell_triangular_meshes[l].points = array_dict( points, cell_triangular_meshes[l].points.keys()) mesh, matching = composed_triangular_mesh( dict([(c, cell_triangular_meshes[c]) for c in labels if c in cell_triangular_meshes.keys()])) if property_name in image.image_property_names(): property_dict = image.image_property(property_name) else: property_dict = array_dict(labels, keys=labels) mesh.triangle_data = dict( zip(matching.keys(), property_dict.values(matching.values()))) return mesh, matching
def sphere_tissue_image(size=100, n_points=12): center = np.array([size/2,size/2,size/2],float) radius = size/4. points = {} for p in range(n_points): theta = np.random.rand()*2.*np.pi phi = np.random.rand()*np.pi - np.pi/2. points[p+3] = center + radius*np.array([np.cos(theta)*np.cos(phi),np.sin(theta)*np.cos(phi),np.sin(phi)]) points = array_dict(points) point_target_area = 4.*np.pi*np.power(radius,2.)/float(n_points) point_target_distance = np.power(point_target_area/np.pi,0.5) sigma_deformation = (size/100.)*(20./n_points) omega_forces = dict(distance=0.1*size/100., repulsion=100.0*np.power(size/100.,2)) for iterations in xrange(100): point_vectors = np.array([points[p]- points.values() for p in points.keys()]) point_distances = np.array([vq(points.values(),np.array([points[p]]))[1] for p in points.keys()]) point_vectors = point_vectors/(point_distances[...,np.newaxis]+1e-7) point_distance_forces = omega_forces['distance']*((point_distances-point_target_distance)[...,np.newaxis]*point_vectors/point_target_distance).sum(axis=1) point_repulsion_forces = omega_forces['repulsion']*np.power(point_target_distance,2)*(point_vectors/(np.power(point_distances,2)+1e-7)[...,np.newaxis]).sum(axis=1) point_forces = np.zeros((len(points),3)) point_forces += point_distance_forces point_forces += point_repulsion_forces point_forces = np.minimum(1.0,sigma_deformation/np.linalg.norm(point_forces,axis=1))[:,np.newaxis] * point_forces new_points = points.values() + point_forces new_points = center+ radius*((new_points-center)/np.linalg.norm((new_points-center),axis=1)[:,np.newaxis]) points = array_dict(new_points,points.keys()) points[2] = center coords = np.transpose(np.mgrid[0:size,0:size,0:size],(1,2,3,0)).reshape((np.power(size,3),3)).astype(int) labels = points.keys()[vq(coords,points.values())[0]] ext_coords = coords[vq(coords,np.array([center]))[1]>size/3.] img = np.ones((size,size,size),np.uint8) img[tuple(np.transpose(coords))] = labels img[tuple(np.transpose(ext_coords))] = 1 img = SpatialImage(img,resolution=(60./size,60./size,60./size)) return img
def triangle_topomesh(triangles, positions, **kwargs): triangles = np.array(triangles) positions = array_dict(positions) edges = array_unique(np.sort(np.concatenate(triangles[:,triangle_edge_list],axis=0))) triangle_edges = np.sort(np.concatenate(triangles[:,triangle_edge_list])) start_time = time() print "--> Generating triangle topomesh" triangle_edge_matching = vq(triangle_edges,edges)[0] triangle_topomesh = PropertyTopomesh(3) for c in np.unique(triangles): triangle_topomesh.add_wisp(0,c) for e in edges: eid = triangle_topomesh.add_wisp(1) for pid in e: triangle_topomesh.link(1,eid,pid) for t in triangles: fid = triangle_topomesh.add_wisp(2) for eid in triangle_edge_matching[3*fid:3*fid+3]: triangle_topomesh.link(2,fid,eid) triangle_topomesh.add_wisp(3,0) for fid in triangle_topomesh.wisps(2): triangle_topomesh.link(3,0,fid) triangle_topomesh.update_wisp_property('barycenter',0,positions.values(np.unique(triangles)),keys=np.unique(triangles)) end_time = time() print "<-- Generating triangle topomesh [",end_time-start_time,"s]" return triangle_topomesh
def circle_voronoi_topomesh(size = 1,resolution = 1.,circle_size = 100.,z_coef = 0.): n_cells = 3*size*(size-1)+1 radius = size*resolution circle_thetas = np.linspace(-np.pi,np.pi-2*np.pi/float(circle_size),circle_size) circle_points = np.transpose([radius*np.cos(circle_thetas),radius*np.sin(circle_thetas)]) cell_thetas = np.array([np.pi*np.random.randint(-180,180)/180. for c in xrange(n_cells)]) cell_distances = 0.5*radius*np.sqrt([np.random.rand() for c in xrange(n_cells)]) cell_points = np.transpose([cell_distances*np.cos(cell_thetas),cell_distances*np.sin(cell_thetas)]) omega_forces = dict(repulsion=0.5) sigma_deformation = 2.*radius/float(n_cells) for iteration in xrange(n_cells/2): cell_to_cell_vectors = np.array([[p-q for q in cell_points] for p in cell_points]) cell_to_cell_distances = np.linalg.norm(cell_to_cell_vectors,axis=2)/radius cell_to_circle_vectors = np.array([[p-q for q in circle_points] for p in cell_points]) cell_to_circle_distances = np.linalg.norm(cell_to_circle_vectors,axis=2)/radius deformation_force = np.zeros_like(cell_points) cell_repulsion_force = np.nansum(cell_to_cell_vectors/np.power(cell_to_cell_distances,3)[:,:,np.newaxis],axis=1) circle_repulsion_force = np.nansum(cell_to_circle_vectors/np.power(cell_to_circle_distances,3)[:,:,np.newaxis],axis=1) deformation_force += omega_forces['repulsion']*cell_repulsion_force deformation_force += 1.5*(n_cells/float(circle_size))*omega_forces['repulsion']*circle_repulsion_force deformation_force_amplitude = np.linalg.norm(deformation_force,axis=1) deformation_force = np.minimum(1.0,sigma_deformation/deformation_force_amplitude)[:,np.newaxis] * deformation_force cell_points += deformation_force cell_points = np.minimum(1.0,radius/(np.linalg.norm(cell_points,axis=1)))[:,np.newaxis] * cell_points all_positions = array_dict(np.transpose([np.concatenate([cell_points[:,0],circle_points[:,0]]),np.concatenate([cell_points[:,1],circle_points[:,1]]),np.zeros(n_cells+circle_size)]),keys=np.arange(n_cells+circle_size).astype(int)) triangles = all_positions.keys()[delaunay_triangulation(all_positions.values())] radial_distances = np.linalg.norm(all_positions.values(),axis=1) radial_z = z_coef*np.power(radial_distances/radius,2) all_positions = array_dict(np.transpose([all_positions.values()[:,0],all_positions.values()[:,1],radial_z]),keys=all_positions.keys()) triangulation_topomesh = triangle_topomesh(triangles,all_positions) cell_topomesh = dual_topomesh(triangulation_topomesh,2,vertex_positions='voronoi') return cell_topomesh
def dual_topomesh(topomesh,degree=2,vertex_positions='barycenter'): dual_topomesh = PropertyTopomesh(topomesh.degree()) if degree == 2: for d in xrange(3): if d<2: dual_topomesh._regions[d] = deepcopy(topomesh._borders[2-d]) if d>0: dual_topomesh._borders[d] = deepcopy(topomesh._regions[2-d]) dual_topomesh._borders[3] = dict(zip(dual_topomesh._borders[2].keys(),[[w] for w in dual_topomesh._borders[2].keys()])) dual_topomesh._regions[2] = dict(zip(dual_topomesh._borders[2].keys(),[[w] for w in dual_topomesh._borders[2].keys()])) edges_to_remove = [e for e in dual_topomesh.wisps(1) if len(list(dual_topomesh.borders(1,e)))<2] faces_to_remove = [f for f in dual_topomesh.wisps(2) if np.any([e in edges_to_remove for e in dual_topomesh.borders(2,f)])] cells_to_remove = faces_to_remove for e in edges_to_remove: dual_topomesh.remove_wisp(1,e) for f in faces_to_remove: dual_topomesh.remove_wisp(2,f) for c in cells_to_remove: dual_topomesh.remove_wisp(3,c) if 'voronoi' in vertex_positions: assert is_triangular(topomesh) if degree==2: from openalea.cellcomplex.property_topomesh.utils.geometry_tools import triangle_geometric_features compute_topomesh_property(topomesh,'vertices',2) triangles = topomesh.wisp_property('vertices',2).values(list(dual_topomesh.wisps(0))) positions = topomesh.wisp_property('barycenter',0) if vertex_positions == 'projected_voronoi': centers = triangle_geometric_features(triangles,positions,features=['projected_circumscribed_circle_center'])[:,0] else: centers = triangle_geometric_features(triangles,positions,features=['circumscribed_circle_center'])[:,0] dual_positions = array_dict(centers,list(dual_topomesh.wisps(0))) else: compute_topomesh_property(topomesh,'barycenter',degree) dual_positions = array_dict(topomesh.wisp_property('barycenter',degree).values(list(dual_topomesh.wisps(0))),list(dual_topomesh.wisps(0))) dual_topomesh.update_wisp_property('barycenter',0,dual_positions) return dual_topomesh
def point_position_optimization(points, omega_forces=dict(distance=1, repulsion=1), target_distance=1, sigma_deformation=0.1, n_iterations=100, force_centering=True, center=np.zeros(3)): points = array_dict(points) for iterations in xrange(100): point_vectors = np.array( [points[p] - points.values() for p in points.keys()]) point_distances = np.array([ vq(points.values(), np.array([points[p]]))[1] for p in points.keys() ]) point_vectors = point_vectors / (point_distances[..., np.newaxis] + 1e-7) point_distance_forces = omega_forces['distance'] * ( (target_distance - point_distances)[..., np.newaxis] * point_vectors / target_distance).sum(axis=1) point_repulsion_forces = omega_forces['repulsion'] * np.power( target_distance, 2) * (point_vectors / (np.power(point_distances, 2) + 1e-7)[..., np.newaxis]).sum(axis=1) point_forces = np.zeros((len(points), 3)) point_forces += point_distance_forces point_forces += point_repulsion_forces point_forces = np.minimum( 1.0, sigma_deformation / np.linalg.norm(point_forces, axis=1))[:, np.newaxis] * point_forces new_points = points.values() + point_forces new_points += center - points.values().mean(axis=0) points = array_dict(new_points, points.keys()) return points
def spatial_image_analysis_property(sia, property_name, labels=None): if property_name == 'volume': property_data = sia.volume(labels) elif property_name == 'neighborhood_size': property_data = sia.neighbors_number(labels) elif property_name == 'shape_anisotropy': inertia_axes_vectors, inertia_axes_values = sia.inertia_axis(labels) property_data = [fractional_anisotropy(inertia_axes_values[l]) for l in labels] elif property_name == 'gaussian_curvature': property_data = sia.gaussian_curvature_CGAL(labels) else: property_data = dict(zip(labels,labels)) if isinstance(property_data,np.ndarray) or isinstance(property_data,list): property_data = array_dict(property_data, keys=labels) elif isinstance(property_data,dict): property_data = array_dict(property_data) return property_data
def sphere_topomesh(radius=1.0,center=np.zeros(3)): from openalea.container import array_dict from openalea.cellcomplex.property_topomesh.property_topomesh_optimization import topomesh_triangle_split ico = icosahedron_topomesh() topomesh = topomesh_triangle_split(topomesh_triangle_split(ico)) positions = topomesh.wisp_property('barycenter',0) new_positions = array_dict(center + radius*positions.values()/np.linalg.norm(positions.values(),axis=1)[:,np.newaxis],positions.keys()) topomesh.update_wisp_property('barycenter',0,new_positions) return topomesh
def nuclei_image_surface_topomesh(nuclei_img, nuclei_sigma=2., density_voxelsize=1., intensity_threshold=2000., microscope_orientation=1, maximal_length=10., remeshing_iterations=10, erosion_radius=0.0): voxelsize = np.array(nuclei_img.voxelsize) size = np.array(nuclei_img.shape) subsampling = np.ceil(density_voxelsize / voxelsize).astype(int) # nuclei_density = nd.gaussian_filter(nuclei_img,nuclei_sigma/voxelsize)/(2.*intensity_threshold) nuclei_density = (nd.gaussian_filter(nuclei_img, nuclei_sigma / voxelsize) > (2. * intensity_threshold)).astype(np.uint8) nuclei_density = nuclei_density[::subsampling[0], ::subsampling[1], :: subsampling[2]] pad_shape = np.transpose( np.tile(np.array(nuclei_density.shape) / 2, (2, 1))) nuclei_density = np.pad(nuclei_density, pad_shape, mode='constant') if erosion_radius > 0: structuring_element = spherical_structuring_element( erosion_radius, voxelsize * subsampling) nuclei_density = nd.binary_erosion( nuclei_density, structuring_element).astype(np.uint8) surface_topomesh = implicit_surface_topomesh( nuclei_density, np.array(nuclei_density).shape, microscope_orientation * voxelsize * subsampling, smoothing=50, decimation=100, iso=0.5, center=False) surface_topomesh.update_wisp_property( 'barycenter', 0, array_dict( surface_topomesh.wisp_property('barycenter', 0).values() - 0.25 * microscope_orientation * voxelsize * subsampling * np.array(nuclei_density.shape), surface_topomesh.wisp_property('barycenter', 0).keys())) if remeshing_iterations > 0: surface_topomesh = property_topomesh_isotropic_remeshing( surface_topomesh, maximal_length=maximal_length, iterations=remeshing_iterations) return surface_topomesh
def nuclei_positions_from_segmented_image(segmented_img, background_label=1): """ """ voxelsize = np.array(segmented_img.voxelsize) segmented_cells = np.array( [c for c in np.unique(segmented_img) if c != background_label]) segmented_positions = array_dict( np.array( nd.center_of_mass(np.ones_like(segmented_img), segmented_img, index=segmented_cells)) * voxelsize, segmented_cells) return segmented_positions
def vtk_polydata_to_cell_triangular_meshes(polydata): mesh = {} polydata_cell_data = polydata.GetCellData().GetArray(0) triangle_cell_start_time = time() print " --> Listing triangles" print " - ",polydata.GetNumberOfCells()," triangles" # polydata_triangles = np.sort([[polydata.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in xrange(polydata.GetNumberOfCells())]) polydata_triangles = np.array([[polydata.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in xrange(polydata.GetNumberOfCells())]) triangle_cell_end_time = time() print " <-- Listing triangles [",triangle_cell_end_time - triangle_cell_start_time,"s]" triangle_cell_start_time = time() print " --> Listing triangle cells" triangle_cell = np.array([polydata_cell_data.GetTuple(t)[0] for t in xrange(polydata.GetNumberOfCells())],np.uint16) triangle_cell_end_time = time() print " <-- Listing triangle cells [",triangle_cell_end_time - triangle_cell_start_time,"s]" start_time = time() print " --> Creating cell meshes" for c in np.unique(triangle_cell): mesh[c] = TriangularMesh() cell_triangles = np.arange(polydata.GetNumberOfCells())[np.where(triangle_cell==c)] # cell_triangle_points = np.sort([[polydata.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in cell_triangles]) cell_triangle_points = np.array([[polydata.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in cell_triangles]) cell_vertices = np.sort(np.unique(cell_triangle_points)) mesh[c].points = array_dict(np.array([polydata.GetPoints().GetPoint(v) for v in cell_vertices]),cell_vertices).to_dict() mesh[c].triangles = array_dict(cell_triangle_points,cell_triangles).to_dict() mesh[c].triangle_data = array_dict(np.ones_like(cell_triangles)*c,cell_triangles).to_dict() end_time = time() print " <-- Creating cell meshes [",end_time-start_time,"s]" return mesh
def update_image_property(self, property_name, property_data, erase_property=False): if isinstance(property_data, list) or isinstance( property_data, np.ndarray): assert len(property_data) == len(self._labels) property_keys = self._labels elif isinstance(property_data, dict) or isinstance( property_data, array_dict): property_keys = np.sort(property_data.keys()) property_data = [property_data[l] for l in property_keys] if property_name in self._properties.keys(): if erase_property: self._properties[property_name] = array_dict( property_data, keys=property_keys) else: for l, v in zip(property_keys, property_data): self._properties[property_name][l] = v else: print "Creating property ", property_name, " on image" self._properties[property_name] = array_dict(property_data, keys=property_keys)
def spatial_image_analysis_to_spatial_image(input_sia, property_name=None, labels=None): """ """ sia = deepcopy(input_sia) img_labels = sia.labels() if labels is not None: labels_to_remove = set(img_labels) - set(list(labels)) sia.remove_labels_from_image(labels_to_remove) img_labels = sia.labels() segmented_img = deepcopy(sia.image) background = sia.background() print background if property_name == 'volume': img_volumes = sia.volume(img_labels) if isinstance(img_volumes, np.ndarray) or isinstance( img_volumes, list): img_volumes = array_dict(img_volumes, keys=img_labels) elif isinstance(img_volumes, dict): img_volumes = array_dict(img_volumes) property_img = SpatialImage(img_volumes.values(segmented_img).astype( np.uint16), resolution=segmented_img.resolution) property_img[segmented_img == background] = background else: property_img = segmented_img return property_img
def test_draco(): n_points = 12 img = sphere_tissue_image(size=100, n_points=n_points) draco = DracoMesh(img) assert draco.point_topomesh.nb_wisps(0) == n_points + 1 draco.delaunay_adjacency_complex(surface_cleaning_criteria=[]) image_tetrahedra = np.sort(draco.image_cell_vertex.keys()) image_tetrahedra = image_tetrahedra[image_tetrahedra[:, 0] != 1] draco_tetrahedra = np.sort([ list(draco.triangulation_topomesh.borders(3, t, 3)) for t in draco.triangulation_topomesh.wisps(3) ]) delaunay_consistency = jaccard_index(image_tetrahedra, draco_tetrahedra) draco.adjacency_complex_optimization(n_iterations=2) assert draco.triangulation_topomesh.nb_region_neighbors(0, 2) == n_points image_tetrahedra = np.sort(draco.image_cell_vertex.keys()) image_tetrahedra = image_tetrahedra[image_tetrahedra[:, 0] != 1] draco_tetrahedra = np.sort([ list(draco.triangulation_topomesh.borders(3, t, 3)) for t in draco.triangulation_topomesh.wisps(3) ]) draco_consistency = jaccard_index(image_tetrahedra, draco_tetrahedra) # print delaunay_consistency,' -> ',draco_consistency assert draco_consistency == 1 or (draco_consistency >= 0.9 and draco_consistency > delaunay_consistency) triangular = ['star', 'remeshed', 'projected', 'regular', 'flat'] image_dual_topomesh = draco.dual_reconstruction( reconstruction_triangulation=triangular, adjacency_complex_degree=3) image_volumes = array_dict( nd.sum(np.ones_like(img), img, index=np.unique(img)[1:]) * np.prod(img.voxelsize), np.unique(img)[1:]) compute_topomesh_property(image_dual_topomesh, 'volume', 3) draco_volumes = image_dual_topomesh.wisp_property('volume', 3) for c in image_dual_topomesh.wisps(3): assert np.isclose(image_volumes[c], draco_volumes[c], 0.33)
def vertex_topomesh(positions, **kwargs): positions = array_dict(positions) start_time = time() print "--> Generating vertex topomesh" vertex_topomesh = PropertyTopomesh(3) for c in positions.keys(): vertex_topomesh.add_wisp(0,c) vertex_topomesh.update_wisp_property('barycenter',0,positions.values(positions.keys()),keys=positions.keys()) end_time = time() print "<-- Generating vertex topomesh [",end_time-start_time,"s]" return vertex_topomesh
def test_length_scaling(): side_length = 1. scale_factor = 2. topomesh = hexagon_topomesh(side_length) compute_topomesh_property(topomesh, 'length', 1) topomesh.update_wisp_property('barycenter', 0, array_dict( topomesh.wisp_property('barycenter', 0).values() * scale_factor, list(topomesh.wisps(0)))) side_length *= scale_factor compute_topomesh_property(topomesh, 'length', 1) for eid in topomesh.wisps(1): assert np.isclose(topomesh.wisp_property('length', 1)[eid], side_length, 1e-7)
def filter_topomesh_vertices(topomesh, vtx_list="L1"): """ Return a filtered topomesh containing only the values found in `vtx_list`. Parameters ---------- topomesh : vertex_topomesh a topomesh to edit vtx_list : str | list if a list, the ids it contains will be used to filter the `topomesh` can be a string like "L1", then propery "layer" should exists! Returns ------- vertex_topomesh """ if isinstance(vtx_list, str): try: assert "layer" in list(topomesh.wisp_property_names(0)) except AssertionError: raise ValueError("Property 'layer' is missing in the topomesh!") # - Duplicate the topomesh: filtered_topomesh = deepcopy(topomesh) # - Define selected vertices: if vtx_list == "L1": # -- Filter L1 seeds from 'detected_topomesh': filtered_cells = np.array(list(filtered_topomesh.wisps(0)))[filtered_topomesh.wisp_property('layer',0).values()==1] elif vtx_list == "L2": # -- Filter L2 seeds from 'detected_topomesh': filtered_cells = np.array(list(filtered_topomesh.wisps(0)))[filtered_topomesh.wisp_property('layer',0).values()==2] elif isinstance(vtx_list, list): filtered_cells = [v for v in vtx_list if v in filtered_topomesh.wisps(0)] else: raise ValueError("Unable to use given `vtx_list`, please check it!") # - Remove unwanted vertices: vtx2remove = list(set(filtered_topomesh.wisps(0)) - set(filtered_cells)) for c in vtx2remove: filtered_topomesh.remove_wisp(0,c) # - Update properies found in the original topomesh: for ppty in filtered_topomesh.wisp_property_names(0): vtx = list(filtered_topomesh.wisps(0)) ppty_dict = array_dict(filtered_topomesh.wisp_property(ppty, 0).values(vtx), keys=vtx) filtered_topomesh.update_wisp_property(ppty, 0, ppty_dict) return filtered_topomesh
def compute_image_property_from_function(self, property_name, property_function): """ property_function : a function taking as an input a binary image and computing a specific cell property. """ from time import time start_time = time() print "--> Computing " + property_name + " property" self._properties[property_name] = array_dict() for l in self.labels: label_start_time = time() binary_img = (self.image == l).astype(int) self._properties[property_name][l] = property_function(binary_img) print " --> Computing label " + str( l) + " " + property_name + " [", time( ) - label_start_time, " s]" print "<-- Computing " + property_name + " property [", time( ) - start_time, " s]"
def poly_topomesh(polys, positions, faces_as_cells=False, **kwargs): polys = np.array(polys) positions = array_dict(positions) poly_lengths = np.array(map(len,polys)) poly_edge_list = [np.transpose([np.arange(l),(np.arange(l)+1)%l]) for l in poly_lengths] edges = array_unique(np.sort(np.concatenate([np.array(p)[l] for p,l in zip(polys,poly_edge_list)],axis=0))) poly_edges = np.sort(np.concatenate([np.array(p)[l] for p,l in zip(polys,poly_edge_list)],axis=0)) start_time = time() print "--> Generating poly topomesh" poly_edge_matching = vq(poly_edges,edges)[0] poly_topomesh = PropertyTopomesh(3) for c in np.unique(polys): poly_topomesh.add_wisp(0,c) for e in edges: eid = poly_topomesh.add_wisp(1) for pid in e: poly_topomesh.link(1,eid,pid) total_poly_length = 0 for q,l in zip(polys,poly_lengths): fid = poly_topomesh.add_wisp(2) for eid in poly_edge_matching[total_poly_length:total_poly_length+l]: poly_topomesh.link(2,fid,eid) total_poly_length += l if not faces_as_cells: poly_topomesh.add_wisp(3,0) for fid in poly_topomesh.wisps(2): poly_topomesh.link(3,0,fid) else: for fid in poly_topomesh.wisps(2): poly_topomesh.add_wisp(3,fid) poly_topomesh.link(3,fid,fid) poly_topomesh.update_wisp_property('barycenter',0,positions.values(np.unique(polys)),keys=np.unique(polys)) end_time = time() print "<-- Generating poly topomesh [",end_time-start_time,"s]" return poly_topomesh
def tetrahedra_topomesh(tetrahedra, positions, **kwargs): tetrahedra = np.array(tetrahedra) positions = array_dict(positions) tetrahedra_triangles = array_unique(np.concatenate(np.sort(tetrahedra[:,tetra_triangle_list]))) tetrahedra_triangle_edges = tetrahedra_triangles[:,triangle_edge_list] tetrahedra_triangle_vectors = positions.values(tetrahedra_triangle_edges[...,1]) - positions.values(tetrahedra_triangle_edges[...,0]) tetrahedra_triangle_lengths = np.linalg.norm(tetrahedra_triangle_vectors,axis=2) tetrahedra_triangle_perimeters = tetrahedra_triangle_lengths.sum(axis=1) tetrahedra_edges = array_unique(np.concatenate(tetrahedra_triangles[:,triangle_edge_list],axis=0)) start_time = time() print "--> Generating tetrahedra topomesh" triangle_edges = np.concatenate(tetrahedra_triangles[:,triangle_edge_list],axis=0) triangle_edge_matching = vq(triangle_edges,tetrahedra_edges)[0] tetrahedra_faces = np.concatenate(np.sort(tetrahedra[:,tetra_triangle_list])) tetrahedra_triangle_matching = vq(tetrahedra_faces,tetrahedra_triangles)[0] tetrahedra_topomesh = PropertyTopomesh(3) for c in np.unique(tetrahedra_triangles): tetrahedra_topomesh.add_wisp(0,c) for e in tetrahedra_edges: eid = tetrahedra_topomesh.add_wisp(1) for pid in e: tetrahedra_topomesh.link(1,eid,pid) for t in tetrahedra_triangles: fid = tetrahedra_topomesh.add_wisp(2) for eid in triangle_edge_matching[3*fid:3*fid+3]: tetrahedra_topomesh.link(2,fid,eid) for t in tetrahedra: cid = tetrahedra_topomesh.add_wisp(3) for fid in tetrahedra_triangle_matching[4*cid:4*cid+4]: tetrahedra_topomesh.link(3,cid,fid) tetrahedra_topomesh.update_wisp_property('barycenter',0,positions.values(np.unique(tetrahedra_triangles)),keys=np.unique(tetrahedra_triangles)) end_time = time() print "<-- Generating tetrahedra topomesh [",end_time-start_time,"s]" return tetrahedra_topomesh
def edge_topomesh(edges, positions, **kwargs): positions = array_dict(positions) start_time = time() print "--> Generating edge topomesh" edge_topomesh = PropertyTopomesh(3) for c in np.unique(edges): edge_topomesh.add_wisp(0,c) for e in edges: eid = edge_topomesh.add_wisp(1) for pid in e: edge_topomesh.link(1,eid,pid) edge_topomesh.update_wisp_property('barycenter',0,positions.values(np.unique(edges)),keys=np.unique(edges)) end_time = time() print "<-- Generating edge topomesh [",end_time-start_time,"s]" return edge_topomesh
def compute_temporal_topomesh_property(topomesh, property_name, degree=0, positions=None, verbose=False): """ """ from openalea.cellcomplex.property_topomesh.property_topomesh_analysis import compute_topomesh_property if positions is None: positions = topomesh.wisp_property('barycenter',degree=0) if property_name == 'time': assert degree>0 if not 'time' in topomesh.wisp_property_names(degree): topomesh.add_wisp_property('time',degree=degree) compute_topomesh_property(topomesh,'vertices',degree) topomesh.update_wisp_property('time',degree=degree,values=array_dict([np.unique(topomesh.wisp_property('time',0).values(topomesh.wisp_property('vertices',degree)[w]))[0] for w in topomesh.wisps(degree)],keys=list(topomesh.wisps(degree)))) if property_name == 'mother_cell': assert degree==3 if not 'mother_cell' in topomesh.wisp_property_names(degree): topomesh.add_wisp_property('mother_cell',degree=degree) topomesh.update_wisp_property('mother_cell',degree=degree,values=np.array([int(list(topomesh.ancestors(degree,w))[0]) for w in topomesh.wisps(degree)]),keys=np.array(list(topomesh.wisps(degree))))
def implicit_surface(density_field,size,resolution,iso=0.5): import numpy as np from scipy.cluster.vq import kmeans, vq from openalea.container import array_dict from skimage.measure import marching_cubes surface_points, surface_triangles = marching_cubes(density_field,iso) surface_points = (np.array(surface_points))*(size*resolution/np.array(density_field.shape)) - size*resolution/2. points_ids = np.arange(len(surface_points)) points_to_delete = [] for p,point in enumerate(surface_points): matching_points = np.sort(np.where(vq(surface_points,np.array([point]))[1] == 0)[0]) if len(matching_points) > 1: points_to_fuse = matching_points[1:] for m_p in points_to_fuse: surface_triangles[np.where(surface_triangles==m_p)] = matching_points[0] points_to_delete.append(m_p) points_to_delete = np.unique(points_to_delete) print len(points_to_delete),"points deleted" surface_points = np.delete(surface_points,points_to_delete,0) points_ids = np.delete(points_ids,points_to_delete,0) surface_triangles = array_dict(np.arange(len(surface_points)),points_ids).values(surface_triangles) for p,point in enumerate(surface_points): matching_points = np.where(vq(surface_points,np.array([point]))[1] == 0)[0] if len(matching_points) > 1: print p,point raw_input() triangles_to_delete = [] for t,triangle in enumerate(surface_triangles): if len(np.unique(triangle)) < 3: triangles_to_delete.append(t) # elif triangle.max() >= len(surface_points): # triangles_to_delete.append(t) surface_triangles = np.delete(surface_triangles,triangles_to_delete,0) return surface_points, surface_triangles
def quad_topomesh(quads, positions, faces_as_cells=False, **kwargs): quads = np.array(quads) positions = array_dict(positions) edges = array_unique(np.sort(np.concatenate(quads[:,quad_edge_list],axis=0))) quad_edges = np.sort(np.concatenate(quads[:,quad_edge_list])) start_time = time() print "--> Generating quad topomesh" quad_edge_matching = vq(quad_edges,edges)[0] quad_topomesh = PropertyTopomesh(3) for c in np.unique(quads): quad_topomesh.add_wisp(0,c) for e in edges: eid = quad_topomesh.add_wisp(1) for pid in e: quad_topomesh.link(1,eid,pid) for q in quads: fid = quad_topomesh.add_wisp(2) for eid in quad_edge_matching[4*fid:4*fid+4]: quad_topomesh.link(2,fid,eid) if not faces_as_cells: quad_topomesh.add_wisp(3,0) for fid in quad_topomesh.wisps(2): quad_topomesh.link(3,0,fid) else: for fid in quad_topomesh.wisps(2): quad_topomesh.add_wisp(3,fid) quad_topomesh.link(3,fid,fid) quad_topomesh.update_wisp_property('barycenter',0,positions.values(np.unique(quads)),keys=np.unique(quads)) end_time = time() print "<-- Generating quad topomesh [",end_time-start_time,"s]" return quad_topomesh
def cube_image(size=50): img = np.ones((size,size,size),np.uint8) points = {} points[11] = np.array([1,0,0],float)*size points[12] = np.array([0,1,0],float)*size points[31] = np.array([0,0,1],float)*size points[59] = np.array([1,1,1],float)*size points = array_dict(points) center = np.array([[size/2,size/2,size/2]],float) coords = np.transpose(np.mgrid[0:size,0:size,0:size],(1,2,3,0)).reshape((np.power(size,3),3)) labels = points.keys()[vq(coords,points.values())[0]] ext_coords = coords[vq(coords,center)[1]>size/2.] img[tuple(np.transpose(coords))] = labels #img[tuple(np.transpose(ext_coords))] = 1 img = SpatialImage(img,resolution=(1,1,1)) return img
def cube_image(size=50): img = np.ones((size, size, size), np.uint8) points = {} points[11] = np.array([1, 0, 0], float) * size points[12] = np.array([0, 1, 0], float) * size points[31] = np.array([0, 0, 1], float) * size points[59] = np.array([1, 1, 1], float) * size points = array_dict(points) center = np.array([[size / 2, size / 2, size / 2]], float) coords = np.transpose(np.mgrid[0:size, 0:size, 0:size], (1, 2, 3, 0)).reshape((np.power(size, 3), 3)) labels = points.keys()[vq(coords, points.values())[0]] ext_coords = coords[vq(coords, center)[1] > size / 2.] img[tuple(np.transpose(coords))] = labels #img[tuple(np.transpose(ext_coords))] = 1 img = SpatialImage(img, voxelsize=(1, 1, 1)) return img
def test_draco(): n_points = 12 img = sphere_tissue_image(size=100,n_points=n_points) draco = DracoMesh(img) assert draco.point_topomesh.nb_wisps(0) == n_points+1 draco.delaunay_adjacency_complex(surface_cleaning_criteria = []) image_tetrahedra = np.sort(draco.image_cell_vertex.keys()) image_tetrahedra = image_tetrahedra[image_tetrahedra[:,0] != 1] draco_tetrahedra = np.sort([list(draco.triangulation_topomesh.borders(3,t,3)) for t in draco.triangulation_topomesh.wisps(3)]) delaunay_consistency = jaccard_index(image_tetrahedra, draco_tetrahedra) draco.adjacency_complex_optimization(n_iterations=2) assert draco.triangulation_topomesh.nb_region_neighbors(0,2) == n_points image_tetrahedra = np.sort(draco.image_cell_vertex.keys()) image_tetrahedra = image_tetrahedra[image_tetrahedra[:,0] != 1] draco_tetrahedra = np.sort([list(draco.triangulation_topomesh.borders(3,t,3)) for t in draco.triangulation_topomesh.wisps(3)]) draco_consistency = jaccard_index(image_tetrahedra, draco_tetrahedra) # print delaunay_consistency,' -> ',draco_consistency assert draco_consistency == 1 or (draco_consistency >= 0.9 and draco_consistency > delaunay_consistency) triangular = ['star','remeshed','projected','regular','flat'] image_dual_topomesh = draco.dual_reconstruction(reconstruction_triangulation = triangular, adjacency_complex_degree=3) image_volumes = array_dict(nd.sum(np.ones_like(img),img,index=np.unique(img)[1:])*np.prod(img.resolution),np.unique(img)[1:]) compute_topomesh_property(image_dual_topomesh,'volume',3) draco_volumes = image_dual_topomesh.wisp_property('volume',3) for c in image_dual_topomesh.wisps(3): assert np.isclose(image_volumes[c],draco_volumes[c],0.33)
def nuclei_layer(nuclei_positions, nuclei_image, microscope_orientation=1, surface_mode="image", density_voxelsize=1., return_topomesh=False): size = np.array(nuclei_image.shape) voxelsize = microscope_orientation * np.array(nuclei_image.voxelsize) positions = array_dict(nuclei_positions) # if display: # from openalea.core.world import World # world = World() # #grid_voxelsize = voxelsize*[12,12,4] # grid_voxelsize = np.sign(voxelsize)*[4.,4.,4.] # #x,y,z = np.ogrid[0:size[0]*voxelsize[0]:grid_voxelsize[0],0:size[1]*voxelsize[1]:grid_voxelsize[1],0:size[2]*voxelsize[2]:grid_voxelsize[2]] # #grid_size = size # x,y,z = np.ogrid[-0.5*size[0]*voxelsize[0]:1.5*size[0]*voxelsize[0]:grid_voxelsize[0],-0.5*size[1]*voxelsize[1]:1.5*size[1]*voxelsize[1]:grid_voxelsize[1],-0.5*size[2]*voxelsize[2]:1.5*size[2]*voxelsize[2]:grid_voxelsize[2]] # grid_size = 2*size # #nuclei_potential = np.array([nuclei_density_function(dict([(p,positions[p])]),cell_radius=8,k=1.0)(x,y,z) for p in positions.keys()]) # #nuclei_potential = np.transpose(nuclei_potential,(1,2,3,0)) # #nuclei_density = np.sum(nuclei_potential,axis=3) # nuclei_density = nuclei_density_function(positions,cell_radius=5,k=1.0)(x,y,z) # surface_topomesh = implicit_surface_topomesh(nuclei_density,grid_size,voxelsize,iso=0.5,center=False) # surface_topomesh.update_wisp_property('barycenter',0,array_dict(surface_topomesh.wisp_property('barycenter',0).values() - 0.5*voxelsize*size,surface_topomesh.wisp_property('barycenter',0).keys())) # # if display: # # world.add(surface_topomesh,'surface') # # raw_input() # # world.remove('surface') # # return None,None,surface_topomesh # triangulation_topomesh = delaunay_tetrahedrization_topomesh(positions,clean_surface=False) # delaunay_topomesh = deepcopy(triangulation_topomesh) # # triangulation_topomesh = tetrahedrization_clean_surface(delaunay_topomesh,surface_cleaning_criteria=['surface','sliver'],surface_topomesh=surface_topomesh) # triangulation_topomesh = tetrahedrization_clean_surface(delaunay_topomesh,surface_cleaning_criteria=['surface','distance','sliver'],surface_topomesh=surface_topomesh,maximal_distance=maximal_distance,maximal_eccentricity=maximal_eccentricity) # #triangulation_topomesh = tetrahedrization_clean_surface(delaunay_topomesh,surface_cleaning_criteria=['surface','distance','sliver'],surface_topomesh=surface_topomesh,maximal_distance=maximal_distance,maximal_eccentricity=maximal_eccentricity) # # if display: # # world.add(triangulation_topomesh,'triangulation') # # raw_input() # # world.remove('triangulation') # # return None,triangulation_topomesh,surface_topomesh # L1_triangulation_topomesh = epidermis_topomesh(triangulation_topomesh) # compute_topomesh_property(L1_triangulation_topomesh,'normal',2,normal_method="density",object_positions=positions) # compute_topomesh_vertex_property_from_faces(L1_triangulation_topomesh,'normal',weighting='area',adjacency_sigma=1.2,neighborhood=3) # down_facing = L1_triangulation_topomesh.wisp_property('normal',0).values()[:,2] < -0.0 # L1_triangulation_topomesh.update_wisp_property('downward',0,array_dict(down_facing,keys=list(L1_triangulation_topomesh.wisps(0)))) # triangle_down_facing = np.any(L1_triangulation_topomesh.wisp_property('downward',0).values(L1_triangulation_topomesh.wisp_property('vertices',2).values(list(L1_triangulation_topomesh.wisps(2)))),axis=1) # triangle_down_facing = triangle_down_facing.astype(float) # L1_triangulation_topomesh.update_wisp_property('downward',2,array_dict(triangle_down_facing,keys=list(L1_triangulation_topomesh.wisps(2)))) # for i,t in enumerate(L1_triangulation_topomesh.wisps(2)): # if L1_triangulation_topomesh.wisp_property('downward',2)[t] == 1: # triangle_neighbors = list(L1_triangulation_topomesh.border_neighbors(2,t)) # if np.any(L1_triangulation_topomesh.wisp_property('downward',2).values(triangle_neighbors)==0): # triangle_down_facing[i] = 0.5 # L1_triangulation_topomesh.update_wisp_property('downward',2,array_dict(triangle_down_facing,keys=list(L1_triangulation_topomesh.wisps(2)))) # triangles_to_remove = np.array(list(L1_triangulation_topomesh.wisps(2)))[L1_triangulation_topomesh.wisp_property('downward',2).values() == 1] # for t in triangles_to_remove: # L1_triangulation_topomesh.remove_wisp(2,t) # edges_to_remove = np.array(list(L1_triangulation_topomesh.wisps(1)))[np.array([L1_triangulation_topomesh.nb_regions(1,e)==0 for e in L1_triangulation_topomesh.wisps(1)])] # for e in edges_to_remove: # L1_triangulation_topomesh.remove_wisp(1,e) # vertices_to_remove = np.array(list(L1_triangulation_topomesh.wisps(0)))[np.array([L1_triangulation_topomesh.nb_regions(0,v)==0 for v in L1_triangulation_topomesh.wisps(0)])] # for v in vertices_to_remove: # L1_triangulation_topomesh.remove_wisp(0,v) # L1_triangulation_topomesh = topomesh_connected_components(L1_triangulation_topomesh)[0] # cell_layer = array_dict(np.zeros_like(positions.keys()),positions.keys()) # for c in L1_triangulation_topomesh.wisps(0): # cell_layer[c] = 1 # for c in triangulation_topomesh.wisps(0): # if cell_layer[c] != 1: # if np.any(cell_layer.values(list(triangulation_topomesh.region_neighbors(0,c))) == 1): # cell_layer[c] = 2 if surface_mode == 'density': grid_voxelsize = microscope_orientation * np.ones( 3, float) * density_voxelsize x, y, z = np.ogrid[-0.5 * size[0] * voxelsize[0]:1.5 * size[0] * voxelsize[0]:grid_voxelsize[0], -0.5 * size[1] * voxelsize[1]:1.5 * size[1] * voxelsize[1]:grid_voxelsize[1], -0.5 * size[2] * voxelsize[2]:1.5 * size[2] * voxelsize[2]:grid_voxelsize[2]] grid_size = 2 * size nuclei_density = nuclei_density_function(positions, cell_radius=5, k=1.0)(x, y, z) surface_topomesh = implicit_surface_topomesh(nuclei_density, grid_size, voxelsize, iso=0.5, center=False) surface_topomesh.update_wisp_property( 'barycenter', 0, array_dict( surface_topomesh.wisp_property('barycenter', 0).values() - 0.5 * voxelsize * size, surface_topomesh.wisp_property('barycenter', 0).keys())) elif surface_mode == 'image': surface_topomesh = nuclei_image_surface_topomesh( nuclei_image, microscope_orientation=microscope_orientation, density_voxelsize=density_voxelsize, nuclei_sigma=1, maximal_length=6., remeshing_iterations=20) top_surface_topomesh = up_facing_surface_topomesh(surface_topomesh, nuclei_positions, connected=True) top_surface_topomesh = topomesh_triangle_split(top_surface_topomesh) #world.add(top_surface_topomesh,'top_surface') surface_points = top_surface_topomesh.wisp_property( 'barycenter', 0).values(list(top_surface_topomesh.wisps(0))) surface_potential = np.array([ nuclei_density_function(dict([(p, positions[p])]), cell_radius=5, k=1.0)(surface_points[:, 0], surface_points[:, 1], surface_points[:, 2]) for p in positions.keys() ]) surface_cells = np.array(positions.keys())[np.argmax(surface_potential, axis=0)] L1_cells = np.unique(surface_cells) cell_layer = array_dict(np.zeros_like(positions.keys()), positions.keys()) for c in L1_cells: cell_layer[c] = 1 if return_topomesh: # triangulation_topomesh.update_wisp_property('layer',0,cell_layer) # return cell_layer, triangulation_topomesh, surface_topomesh return cell_layer, top_surface_topomesh else: return cell_layer
def cell_topomesh(input_topomesh, cells=None, copy_properties=False): from time import time start_time = time() #topomesh = PropertyTopomesh(topomesh=input_topomesh) topomesh = PropertyTopomesh(3) if cells is None: cells = set(topomesh.wisps(3)) else: cells = set(cells) faces = set() for c in cells: topomesh._borders[3][c] = deepcopy(input_topomesh._borders[3][c]) faces = faces.union(set(topomesh._borders[3][c])) edges = set() for f in faces: topomesh._borders[2][f] = deepcopy(input_topomesh._borders[2][f]) topomesh._regions[2][f] = deepcopy(list(set(input_topomesh._regions[2][f]).intersection(cells))) edges = edges.union(set(topomesh._borders[2][f])) vertices = set() for e in edges: topomesh._borders[1][e] = deepcopy(input_topomesh._borders[1][e]) topomesh._regions[1][e] = deepcopy(list(set(input_topomesh._regions[1][e]).intersection(faces))) vertices = vertices.union(set(topomesh._borders[1][e])) for v in vertices: topomesh._regions[0][v] = deepcopy(list(set(input_topomesh._regions[0][v]).intersection(edges))) if copy_properties: for degree in xrange(4): for property_name in input_topomesh.wisp_property_names(degree): input_property = input_topomesh.wisp_property(property_name,degree) property_keys = np.intersect1d(input_property.keys(),list(topomesh.wisps(degree))) if len(property_keys)>0: topomesh.update_wisp_property(property_name,degree,array_dict(input_topomesh.wisp_property(property_name,degree).values(property_keys),property_keys)) topomesh.update_wisp_property('barycenter',0,array_dict(input_topomesh.wisp_property('barycenter',0).values(list(vertices)),list(vertices))) # cells_to_remove = [c for c in topomesh.wisps(3) if not c in cells] # cells_to_remove = list(set(topomesh.wisps(3)).difference(set(cells))) # for c in cells_to_remove: # topomesh.remove_wisp(3,c) # faces_to_remove = [w for w in topomesh.wisps(2) if topomesh.nb_regions(2,w)==0] # for w in faces_to_remove: # topomesh.remove_wisp(2,w) # edges_to_remove = [w for w in topomesh.wisps(1) if topomesh.nb_regions(1,w)==0] # for w in edges_to_remove: # topomesh.remove_wisp(1,w) # vertices_to_remove = [w for w in topomesh.wisps(0) if topomesh.nb_regions(0,w)==0] # for w in vertices_to_remove: # topomesh.remove_wisp(0,w) end_time = time() #end_time = time() print "<-- Extracting cell topomesh [",end_time-start_time,"s]" return topomesh
def surface_dual_topomesh(topomesh, vertex_placement='center', exterior_vertex=1, exterior_distance=0, face_positions=None, vertices_as_cells=None): if vertices_as_cells is None: vertices_as_cells = topomesh.nb_wisps(3) != 1 dual_topomesh = PropertyTopomesh(3) for f in topomesh.wisps(2): dual_topomesh.add_wisp(0,f) for e in topomesh.wisps(1): dual_topomesh.add_wisp(1,e) for f in topomesh.regions(1,e): dual_topomesh.link(1,e,f) for v in topomesh.wisps(0): if v != exterior_vertex: dual_topomesh.add_wisp(2,v) for e in topomesh.regions(0,v): dual_topomesh.link(2,v,e) if vertices_as_cells: dual_topomesh.add_wisp(3,v) dual_topomesh.link(3,v,v) else: for c in topomesh.regions(0,v,3): if not dual_topomesh.has_wisp(3,c): dual_topomesh.add_wisp(3,c) dual_topomesh.link(3,c,v) for degree in [0,1,2]: for property_name in topomesh.wisp_property_names(degree): dual_topomesh.update_wisp_property(property_name,2-degree,topomesh.wisp_property(property_name,degree)) if vertices_as_cells: for property_name in topomesh.wisp_property_names(0): dual_topomesh.update_wisp_property(property_name,3,topomesh.wisp_property(property_name,0)) else: for property_name in topomesh.wisp_property_names(3): dual_topomesh.update_wisp_property(property_name,3,topomesh.wisp_property(property_name,3)) compute_topomesh_property(topomesh,'barycenter',2) face_centers = topomesh.wisp_property('barycenter',2) positions = topomesh.wisp_property('barycenter',0) if is_triangular(topomesh): compute_topomesh_property(topomesh,'vertices',2) triangle_ids = np.array(list(topomesh.wisps(2))) triangles = topomesh.wisp_property('vertices',2).values(triangle_ids) if exterior_vertex is not None: exterior_triangle_ids = triangle_ids[np.where(np.any(triangles==exterior_vertex,axis=1))] exterior_triangles = triangles[np.where(np.any(triangles==exterior_vertex,axis=1))] exterior_edges = [t[t!=exterior_vertex] for t in exterior_triangles] exterior_edge_ids = np.concatenate([[e for e in topomesh.borders(2,t) if not exterior_vertex in topomesh.borders(1,e)] for t in exterior_triangle_ids]) exterior_edge_triangle_ids = np.concatenate([[t for t in topomesh.regions(1,e) if not exterior_vertex in topomesh.borders(2,t,2)] for e in exterior_edge_ids]) triangle_ids = triangle_ids[np.where(np.all(triangles!=exterior_vertex,axis=1))] triangles = triangles[np.where(np.all(triangles!=exterior_vertex,axis=1))] else: exterior_triangles = [] exterior_triangle_ids = [] exterior_edges = [] exterior_edge_triangle_ids = [] exterior_centers = [] if vertex_placement == 'voronoi': centers = triangle_geometric_features(triangles,positions,['circumscribed_circle_center'])[:,0] elif vertex_placement == 'projected_voronoi': centers = triangle_geometric_features(triangles,positions,['projected_circumscribed_circle_center'])[:,0] elif vertex_placement == 'center': centers = triangle_geometric_features(triangles,positions,['barycenter'])[:,0] if exterior_vertex is not None: exterior_edge_centers = positions.values(exterior_edges).mean(axis=1) exterior_face_centers = face_centers.values(exterior_edge_triangle_ids) exterior_face_dual_centers = array_dict(centers,triangle_ids).values(exterior_edge_triangle_ids) exterior_edge_vectors = np.sign(np.einsum("...ij,...ij->...i",exterior_face_centers-exterior_edge_centers,exterior_face_dual_centers-exterior_edge_centers))[:,np.newaxis]*(exterior_edge_centers-exterior_face_dual_centers) print exterior_edge_vectors exterior_edge_vectors = exterior_edge_vectors/np.linalg.norm(exterior_edge_vectors,axis=1)[:,np.newaxis] exterior_dual_distance = np.linalg.norm(exterior_face_dual_centers-exterior_edge_centers,axis=1) #exterior_centers = face_centers.values(exterior_edge_triangle_ids) + exterior_coef*(positions.values(exterior_edges).mean(axis=1)-face_centers.values(exterior_edge_triangle_ids)) exterior_centers = exterior_face_dual_centers + np.maximum(exterior_distance-exterior_dual_distance,0)[:,np.newaxis]*exterior_edge_vectors print list(triangle_ids),list(exterior_triangle_ids) print list(topomesh.wisps(2)) dual_topomesh.update_wisp_property('barycenter',0,array_dict(list(centers)+list(exterior_centers),list(triangle_ids)+list(exterior_triangle_ids))) else: dual_topomesh.update_wisp_property('barycenter',0,face_centers) edges_to_remove = [e for e in dual_topomesh.wisps(1) if dual_topomesh.nb_borders(1,e) != 2] for e in edges_to_remove: dual_topomesh.remove_wisp(1,e) return clean_topomesh(dual_topomesh)
np.ones_like(edited_L1_points[:, 0]), np.zeros_like(non_L1_points[:, 0]) ]))) signal_values = {} for signal_name, compute_ratio in zip(signal_names, compute_ratios): signal_img = image_dict[signal_name] signal_img = SpatialImage(signal_img, voxelsize=vxs) ratio_img = reference_img if compute_ratio else np.ones_like( reference_img) ratio_img = SpatialImage(ratio_img, voxelsize=vxs) signal_values[signal_name] = compute_fluorescence_ratios( ratio_img, signal_img, edited_positions) edited_positions = array_dict( np.array(edited_positions.values()) * microscope_orientation, edited_positions.keys()).to_dict() edited_topomesh = vertex_topomesh(edited_positions) for signal_name in signal_names: edited_topomesh.update_wisp_property(signal_name, 0, signal_values[signal_name]) edited_topomesh.update_wisp_property('layer', 0, edited_layer) topomesh_file = image_dirname + "/" + nomenclature_names[ filename] + "/" + nomenclature_names[ filename] + "_nuclei_detection_topomesh_corrected{}.ply".format( suffix) save_ply_property_topomesh(edited_topomesh, topomesh_file,
def create_CGAL_topomesh(img, mesh_fineness=1.0): """ """ dirname = str(shared_data(openalea.cgal_meshing).parent.parent+'/') start_time = time() print "--> Input Image" img_graph = graph_from_image(img,spatio_temporal_properties=['volume','barycenter'],ignore_cells_at_stack_margins = False,property_as_real=False) img_labels = np.array(list(img_graph.vertices())) img_volumes = np.array([img_graph.vertex_property('volume')[v] for v in img_graph.vertices()]) print " --> ",img_labels.shape[0]," Objects, ", img_volumes[2:].mean()," microm3 per object" facet_distance = np.power(img_volumes[2:].mean(),1/3.)/(4.5*np.pi*mesh_fineness) print " --> Facet Distance : ",facet_distance print " --> Converting to 8bit" img_neighbors = np.array([list(img_graph.neighbors(v)) for v in img_graph.vertices()]) count_labels = np.zeros(256) img_graph.add_vertex_property('8bit_labels') if img_labels.shape[0] < 255: for i,v in enumerate(img_graph.vertices()): img_graph.vertex_property('8bit_labels')[v] = i+2 else: for v in img_graph.vertices(): possible_labels = np.array([]) select = 0 while possible_labels.size == 0: possible_labels = set(np.arange(2,256)) possible_labels = possible_labels.difference(set(np.where(count_labels>count_labels[2:].min()+select)[0])) #possible_labels = possible_labels.difference(set(np.where(count_labels>count_labels[2:].min()+1)[0])) neighbor_labels = set() for n in img_graph.neighbors(v): try: neighbor_label = {img_graph.vertex_property('8bit_labels')[n]} for n2 in img_graph.neighbors(n): if n2 != v: try: neighbor_label = {img_graph.vertex_property('8bit_labels')[n2]} except KeyError: neighbor_label = set() pass neighbor_labels = neighbor_labels.union(neighbor_label) except KeyError: neighbor_label = set() pass neighbor_labels = neighbor_labels.union(neighbor_label) possible_labels = np.array(list(possible_labels.difference(neighbor_labels)),np.uint8) if possible_labels.size == 0: select += 1 #print neighbor_labels new_label = possible_labels[np.random.randint(possible_labels.size)] img_graph.vertex_property('8bit_labels')[v] = new_label count_labels[new_label] += 1 #print v, ' -> ', new_label new_labels = np.ones(img.max()+1,np.uint8) new_labels[img_labels] = np.array([img_graph.vertex_property('8bit_labels')[v] for v in img_graph.vertices()],np.uint8) if np.unique(new_labels).shape[0]<255: label_index = np.ones(256) label_index[np.unique(new_labels)] = np.arange(new_labels.shape[0])+1 for v in img_graph.vertices(): img_graph.vertex_property('8bit_labels')[v] = label_index[img_graph.vertex_property('8bit_labels')[v]] new_labels = np.ones(img.max()+1,np.uint8) #new_labels[img_labels] = np.array([img_graph.vertex_property('8bit_labels')[v] for v in img_graph.vertices()],np.uint8) for v in img_graph.vertices(): new_labels[v] = img_graph.vertex_property('8bit_labels')[v] mod_img = np.array(new_labels[img],np.uint8) inrfile = dirname+"tmp/8bit_image.inr.gz" imsave(inrfile,SpatialImage(mod_img)) end_time = time() print "<-- Input Image [",end_time-start_time,"s]" facet_angle = 30.0 facet_size = 40.0 edge_ratio = 4.0 cell_size = 60.0 start_time = time() print "--> Building CGAL Mesh" outputfile = dirname+"tmp/CGAL_output_mesh.mesh" buildCGALMesh(inrfile,outputfile,facet_angle,facet_size,facet_distance,edge_ratio,cell_size) end_time = time() print "<-- Building CGAL Mesh [",end_time-start_time,"s]" mesh = CGALMesh() mesh.createMesh(outputfile) start_time = time() print "--> Re-Indexing Components" mesh.components = np.unique(mesh.tri_subdomains) new_mesh = CGALMesh() new_mesh.createMesh(outputfile) new_mesh.tri_subdomains = np.ones_like(mesh.tri_subdomains) new_mesh.tetra_subdomains = np.ones_like(mesh.tetra_subdomains) new_mesh.tri_subdomains[np.where(mesh.tri_subdomains == mesh.components[0])] = 1 new_mesh.tetra_subdomains[np.where(mesh.tetra_subdomains == mesh.components[0])] = 1 for c in mesh.components[1:]: cell_labels = np.where(new_labels == c)[0] n_cells = cell_labels.size if n_cells > 0: # print " --> Component ",c," -> ",n_cells," Cells" cell_tetrahedra = mesh.tetrahedra[np.where(mesh.tetra_subdomains==c)] #if n_cells == 1: if False: print " --> Component ",c," -> 1 Object (",n_cells," Cell) : ",cell_labels,"(",img_graph.vertex_property('8bit_labels')[cell_labels[0]],")" new_mesh.tetra_subdomains[np.where(mesh.tetra_subdomains == c)] = cell_labels[0] new_mesh.tri_subdomains[np.where(mesh.tri_subdomains == c)] = cell_labels[0] else: cell_tetrahedra_components = np.zeros(cell_tetrahedra.shape[0],int) tetrahedra_component_correspondance = {} tetra_centers = np.mean(mesh.vertices[cell_tetrahedra],axis=1) for t, tetra in enumerate(cell_tetrahedra): if cell_tetrahedra_components[t] == 0: neighbour_tetrahedra = np.unique(np.append(np.where(cell_tetrahedra==tetra[0])[0],np.append(np.where(cell_tetrahedra==tetra[1])[0],np.append(np.where(cell_tetrahedra==tetra[2])[0],np.where(cell_tetrahedra==tetra[3])[0])))) if (cell_tetrahedra_components[neighbour_tetrahedra].max()>0): neighbour_components = cell_tetrahedra_components[neighbour_tetrahedra][np.where(cell_tetrahedra_components[neighbour_tetrahedra]>0)] min_component = np.array([tetrahedra_component_correspondance[component] for component in neighbour_components]).min() for component in neighbour_components: tetrahedra_component_correspondance[tetrahedra_component_correspondance[component]] = min_component tetrahedra_component_correspondance[component] = min_component cell_tetrahedra_components[neighbour_tetrahedra] = min_component else: tetrahedra_component_correspondance[cell_tetrahedra_components.max()+1] = int(cell_tetrahedra_components.max()+1) cell_tetrahedra_components[neighbour_tetrahedra] = int(cell_tetrahedra_components.max()+1) for component in tetrahedra_component_correspondance: label = component while label != tetrahedra_component_correspondance[label]: label = tetrahedra_component_correspondance[label] tetrahedra_component_correspondance[component] = tetrahedra_component_correspondance[label] component_labels = np.unique([tetrahedra_component_correspondance[component] for component in cell_tetrahedra_components]) n_objects = component_labels.size # if n_objects != n_cells: # print tetrahedra_component_correspondance for component in tetrahedra_component_correspondance: tetrahedra_component_correspondance[component] = np.where(component_labels == tetrahedra_component_correspondance[component])[0][0] for component in tetrahedra_component_correspondance: cell_tetrahedra_components[np.where(cell_tetrahedra_components == component)] = tetrahedra_component_correspondance[component] tetrahedra_object_centers = np.zeros((n_objects,3)) tetrahedra_object_centers[:,0] = nd.sum(tetra_centers[:,0],cell_tetrahedra_components,index=xrange(n_objects))/nd.sum(np.ones_like(cell_tetrahedra_components),cell_tetrahedra_components,index=xrange(n_objects)) tetrahedra_object_centers[:,1] = nd.sum(tetra_centers[:,1],cell_tetrahedra_components,index=xrange(n_objects))/nd.sum(np.ones_like(cell_tetrahedra_components),cell_tetrahedra_components,index=xrange(n_objects)) tetrahedra_object_centers[:,2] = nd.sum(tetra_centers[:,2],cell_tetrahedra_components,index=xrange(n_objects))/nd.sum(np.ones_like(cell_tetrahedra_components),cell_tetrahedra_components,index=xrange(n_objects)) img_points = np.array([img_graph.vertex_property('barycenter')[v] for v in cell_labels]) tetrahedra_labels = cell_labels[vq(tetrahedra_object_centers,img_points)[0]] # img_points = np.array([img_graph.vertex_property('barycenter')[v] for v in img_labels]) # tetrahedra_labels = img_labels[vq(tetrahedra_object_centers,img_points)[0]] cell_triangles = mesh.triangles[np.where(mesh.tri_subdomains==c)] cell_triangles_components = np.array([np.unique(cell_tetrahedra_components[np.where(cell_tetrahedra==tri[0])[0]])[0] for tri in cell_triangles]) print " --> Component ",c," -> ",n_objects," Objects (",n_cells," Cells) : ",tetrahedra_labels new_mesh.tetra_subdomains[np.where(mesh.tetra_subdomains == c)] = tetrahedra_labels[cell_tetrahedra_components] new_mesh.tri_subdomains[np.where(mesh.tri_subdomains == c)] = tetrahedra_labels[cell_triangles_components] mesh.tri_subdomains = new_mesh.tri_subdomains mesh.tetra_subdomains = new_mesh.tetra_subdomains mesh.components = np.unique(mesh.tri_subdomains) print mesh.vertices.shape[0],"Vertices, ",mesh.triangles.shape[0],"Triangles, ",mesh.tetrahedra.shape[0],"Tetrahedra, ",mesh.components.shape[0]," Components" end_time = time() print "<-- Re-Indexing Components [",end_time-start_time,"s]" mesh.saveCGALfile(outputfile) start_time = time() print "--> Creating Topomesh" mesh = CGALMesh() mesh.createMesh(outputfile) mesh.generatePropertyTopomesh() positions = array_dict(mesh.vertex_positions.values()*np.array(img.resolution),keys=list(mesh.topo_mesh.wisps(0))) compute_topomesh_property(mesh.topo_mesh,'barycenter',degree=0,positions=positions) end_time = time() print "<-- Creating Topomesh [",end_time-start_time,"s]" return mesh.topo_mesh
def topomesh_to_vtk_polydata(topomesh,degree=2,positions=None,topomesh_center=None,coef=1): import numpy as np import vtk from time import time from openalea.container import array_dict if positions is None: positions = topomesh.wisp_property('barycenter',0) if topomesh_center is None: topomesh_center = np.mean(positions.values(),axis=0) # topomesh_center = np.array([0,0,0]) print topomesh_center vtk_mesh = vtk.vtkPolyData() vtk_points = vtk.vtkPoints() vtk_edges = vtk.vtkCellArray() vtk_triangles = vtk.vtkCellArray() vtk_cells = vtk.vtkLongArray() start_time = time() print "--> Creating VTK PolyData" if degree == 3: for c in topomesh.wisps(3): cell_points = [] cell_center = np.mean([positions[v] for v in topomesh.borders(3,c,3)],axis=0) for v in topomesh.borders(3,c,3): position = cell_center + coef*(positions[v]-cell_center) - topomesh_center position[np.where(np.abs(position)<.001)] =0. p = vtk_points.InsertNextPoint(position) cell_points.append(p) cell_points = array_dict(cell_points,list(topomesh.borders(3,c,3))) for t in topomesh.borders(3,c): poly = vtk_triangles.InsertNextCell(3) for v in topomesh.borders(2,t,2): vtk_triangles.InsertCellPoint(cell_points[v]) vtk_cells.InsertValue(poly,c) elif degree == 2: for t in topomesh.wisps(2): triangle_points = [] triangle_center = np.mean([positions[v] for v in topomesh.borders(2,t,2)],axis=0) for v in topomesh.borders(2,t,2): position = triangle_center + coef*(positions[v]-triangle_center) - topomesh_center position[np.where(np.abs(position)<.001)] =0. p = vtk_points.InsertNextPoint(position) triangle_points.append(p) triangle_points = array_dict(triangle_points,list(topomesh.borders(2,t,2))) poly = vtk_triangles.InsertNextCell(3) for v in topomesh.borders(2,t,2): vtk_triangles.InsertCellPoint(triangle_points[v]) vtk_cells.InsertValue(poly,list(topomesh.regions(2,t))[0]) elif degree == 1: points = [] for v in topomesh.wisps(0): position = positions[v] position[np.where(np.abs(position)<.001)] =0. p = vtk_points.InsertNextPoint(position) points.append(p) points = array_dict(points,list(topomesh.wisps(0))) for e in topomesh.wisps(1): # if topomesh.wisp_property('epidermis',1)[e]: # if True: if len(list(topomesh.regions(1,e))) > 2: c = vtk_edges.InsertNextCell(2) for v in topomesh.borders(1,e): vtk_edges.InsertCellPoint(points[v]) print" --> Linking Mesh" vtk_mesh.SetPoints(vtk_points) vtk_mesh.SetPolys(vtk_triangles) vtk_mesh.SetLines(vtk_edges) vtk_mesh.GetCellData().SetScalars(vtk_cells) end_time = time() print "<-- Creating VTK PolyData [",end_time-start_time,"s]" return vtk_mesh
def compute_topomesh_image(topomesh, img): image_start_time = time() print "<-- Computing topomesh image" polydata_img = np.ones_like(img) for c in list(topomesh.wisps(3)): if len(list(topomesh.borders(3,c))) > 0: polydata_start_time = time() sub_topomesh = cell_topomesh(topomesh,cells=[c]) start_time = time() bounding_box = np.array([[0,polydata_img.shape[0]],[0,polydata_img.shape[1]],[0,polydata_img.shape[2]]]) bounding_box[:,0] = np.floor(sub_topomesh.wisp_property('barycenter',0).values().min(axis=0)/np.array(img.resolution)).astype(int)-1 bounding_box[:,0] = np.maximum(bounding_box[:,0],0) bounding_box[:,1] = np.ceil(sub_topomesh.wisp_property('barycenter',0).values().max(axis=0)/np.array(img.resolution)).astype(int)+1 bounding_box[:,1] = np.minimum(bounding_box[:,1],np.array(img.shape)-1) sub_polydata_img = polydata_img[bounding_box[0,0]:bounding_box[0,1],bounding_box[1,0]:bounding_box[1,1],bounding_box[2,0]:bounding_box[2,1]] #world.add(sub_polydata_img,"topomesh_image",colormap='glasbey',alphamap='constant',bg_id=1,intensity_range=(0,1)) reader = matrix_to_image_reader('sub_polydata_image',sub_polydata_img,sub_polydata_img.dtype) #reader = matrix_to_image_reader('polydata_image',polydata_img,polydata_img.dtype) end_time = time() print " --> Extracting cell sub-image [",end_time-start_time,"s]" start_time = time() topomesh_center = bounding_box[:,0]*np.array(img.resolution) positions = sub_topomesh.wisp_property('barycenter',0) polydata = vtk.vtkPolyData() vtk_points = vtk.vtkPoints() vtk_triangles = vtk.vtkCellArray() for t in sub_topomesh.wisps(2): triangle_points = [] for v in sub_topomesh.borders(2,t,2): p = vtk_points.InsertNextPoint(positions[v]-topomesh_center) triangle_points.append(p) triangle_points = array_dict(triangle_points,list(sub_topomesh.borders(2,t,2))) poly = vtk_triangles.InsertNextCell(3) for v in sub_topomesh.borders(2,t,2): vtk_triangles.InsertCellPoint(triangle_points[v]) polydata.SetPoints(vtk_points) polydata.SetPolys(vtk_triangles) end_time = time() print " --> Creating VTK PolyData [",end_time-start_time,"s]" start_time = time() pol2stenc = vtk.vtkPolyDataToImageStencil() pol2stenc.SetTolerance(0) pol2stenc.SetOutputOrigin((0,0,0)) #pol2stenc.SetOutputOrigin(tuple(-bounding_box[:,0])) pol2stenc.SetOutputSpacing(img.resolution) SetInput(pol2stenc,polydata) pol2stenc.Update() end_time = time() print " --> Cell ",c," polydata stencil [",end_time-start_time,"s]" start_time = time() imgstenc = vtk.vtkImageStencil() if vtk.VTK_MAJOR_VERSION <= 5: imgstenc.SetInput(reader.GetOutput()) imgstenc.SetStencil(pol2stenc.GetOutput()) else: imgstenc.SetInputData(reader.GetOutput()) imgstenc.SetStencilConnection(pol2stenc.GetOutputPort()) imgstenc.ReverseStencilOn() imgstenc.SetBackgroundValue(c) imgstenc.Update() end_time = time() print " --> Cell ",c," image stencil [",end_time-start_time,"s]" start_time = time() dim = tuple((bounding_box[:,1]-bounding_box[:,0])[::-1]) array = np.ones(dim, img.dtype) export = vtk.vtkImageExport() export.SetInputConnection(imgstenc.GetOutputPort()) export.Export(array) end_time = time() print " --> Exporting image [",end_time-start_time,"s]" start_time = time() array = np.transpose(array,(2,1,0)) polydata_img[bounding_box[0,0]:bounding_box[0,1],bounding_box[1,0]:bounding_box[1,1],bounding_box[2,0]:bounding_box[2,1]] = array end_time = time() print " --> Inserting cell sub-image [",end_time-start_time,"s]" polydata_end_time = time() print "--> Inserting topomesh cell ",c," [",polydata_end_time-polydata_start_time,"s]" image_end_time = time() print "<-- Computing topomesh image [",image_end_time-image_start_time,"s]" return polydata_img
def optimize_topomesh(input_topomesh,omega_forces={'regularization':0.00,'laplacian':1.0,'planarization':0.27,'epidermis_planarization':0.07},omega_regularization_max=None,iterations=20,edge_flip=False,**kwargs): """ """ topomesh = deepcopy(input_topomesh) preparation_start_time = time() # topomesh.update_wisp_property('barycenter',degree=0,values=initial_vertex_positions,keys=np.array(list(topomesh.wisps(0)))) compute_topomesh_property(topomesh,'valence',degree=0) compute_topomesh_property(topomesh,'borders',degree=1) compute_topomesh_property(topomesh,'vertices',degree=1) compute_topomesh_property(topomesh,'vertices',degree=2) compute_topomesh_property(topomesh,'vertices',degree=3) compute_topomesh_property(topomesh,'cells',degree=2) compute_topomesh_property(topomesh,'cells',degree=1) compute_topomesh_property(topomesh,'cells',degree=0) compute_topomesh_property(topomesh,'length',degree=1) compute_topomesh_property(topomesh,'barycenter',degree=3) compute_topomesh_property(topomesh,'barycenter',degree=2) compute_topomesh_property(topomesh,'barycenter',degree=1) triangular_mesh = kwargs.get('triangular_mesh',True) if triangular_mesh: compute_topomesh_triangle_properties(topomesh) compute_topomesh_property(topomesh,'normal',degree=2) compute_topomesh_property(topomesh,'angles',degree=2) compute_topomesh_property(topomesh,'epidermis',degree=0) compute_topomesh_property(topomesh,'epidermis',degree=1) # compute_topomesh_property(topomesh,'epidermis',degree=3) if omega_forces.has_key('planarization'): start_time = time() print "--> Computing interfaces" for cid in topomesh.wisps(3): for n_cid in topomesh.border_neighbors(3,cid): if (n_cid<cid) and (not (n_cid,cid) in topomesh._interface[3].values()): iid = topomesh._interface[3].add((n_cid,cid),None) end_time = time() print "<-- Computing interfaces[",end_time-start_time,"s]" preparation_end_time = time() print "--> Preparing topomesh [",preparation_end_time-preparation_start_time,"s]" display = kwargs.get('display',False) if display: pass optimization_start_time = time() if omega_forces.has_key('regularization'): if omega_regularization_max is None: omega_regularization_max = omega_forces['regularization'] gradient_derivatives = kwargs.get("gradient_derivatives",[]) cell_vertex_motion = kwargs.get("cell_vertex_motion",False) if cell_vertex_motion: image_cell_vertex = deepcopy(kwargs.get("image_cell_vertex",{})) for v in image_cell_vertex.keys(): image_cell_vertex[v] = image_cell_vertex[v]*np.array(kwargs.get("image_voxelsize",(1.0,1.0,1.0))) #image_cell_vertex[v] = image_cell_vertex[v] compute_topomesh_property(topomesh,'cells',degree=0) vertex_cell_neighbours = topomesh.wisp_property('cells',degree=0) epidermis_vertices = np.array(list(topomesh.wisps(0)))[np.where(topomesh.wisp_property('epidermis',degree=0).values())] start_time = time() print "--> Computing mesh cell vertices" mesh_cell_vertex = {} for v in topomesh.wisps(0): if len(vertex_cell_neighbours[v]) == 5: for k in xrange(5): vertex_cell_labels = tuple([c for c in vertex_cell_neighbours[v]][:k])+tuple([c for c in vertex_cell_neighbours[v]][k+1:]) if not mesh_cell_vertex.has_key(vertex_cell_labels): mesh_cell_vertex[vertex_cell_labels] = v if len(vertex_cell_neighbours[v]) == 4: vertex_cell_labels = tuple([c for c in vertex_cell_neighbours[v]]) mesh_cell_vertex[vertex_cell_labels] = v if v in epidermis_vertices: # and count_l1_cells(vertex_cell_neighbours[v]) == 4: for k in xrange(4): vertex_cell_labels = (1,) + tuple([c for c in vertex_cell_neighbours[v]][:k])+tuple([c for c in vertex_cell_neighbours[v]][k+1:]) if not mesh_cell_vertex.has_key(vertex_cell_labels): mesh_cell_vertex[vertex_cell_labels] = v if (len(vertex_cell_neighbours[v]) == 3) and (v in epidermis_vertices): # and (count_l1_cells(vertex_cell_neighbours[v]) == 3): vertex_cell_labels = (1,) + tuple([c for c in vertex_cell_neighbours[v]]) mesh_cell_vertex[vertex_cell_labels] = v end_time = time() print "<-- Computing mesh cell vertices [",end_time-start_time,"s]" cell_vertex_matching = vq(np.sort(array_dict(image_cell_vertex).keys()),np.sort(array_dict(mesh_cell_vertex).keys())) matched_image_index = np.where(cell_vertex_matching[1] == 0)[0] matched_mesh_index = cell_vertex_matching[0][np.where(cell_vertex_matching[1] == 0)[0]] matched_image_cell_vertex = np.array(image_cell_vertex.values())[matched_image_index] matched_keys = np.sort(np.array(image_cell_vertex.keys()))[matched_image_index] matched_mesh_vertices = np.array(mesh_cell_vertex.values())[cell_vertex_matching[0][np.where(cell_vertex_matching[1] == 0)[0]]] matched_keys = np.sort(np.array(mesh_cell_vertex.keys()))[matched_mesh_index] initial_vertex_positions = array_dict(topomesh.wisp_property('barycenter',0).values(list(topomesh.wisps(0))),list(topomesh.wisps(0))) final_vertex_positions = array_dict() fixed_vertex = array_dict(np.array([False for v in topomesh.wisps(0)]),np.array(list(topomesh.wisps(0)))) for i,v in enumerate(matched_mesh_vertices): if not np.isnan(matched_image_cell_vertex[i]).any(): final_vertex_positions[v] = matched_image_cell_vertex[i] # print topomesh.wisp_property('barycenter',0)[v]," -> ",final_vertex_positions[v] fixed_vertex[v] = True matched_mesh_vertices = final_vertex_positions.keys() sigma_deformation_initial = kwargs.get("sigma_deformation",np.sqrt(3)/4.) sigma_deformation = sigma_deformation_initial*np.ones_like(np.array(list(topomesh.wisps(0))),float) if cell_vertex_motion: sigma_deformation[np.where(fixed_vertex.values())[0]] = 0. iterations_per_step = kwargs.get('iterations_per_step',1) for iteration in xrange(iterations/iterations_per_step+1): print "_____________________________" print "" print " Iteration ",iteration print "_____________________________" start_time = time() gaussian_sigma = kwargs.get('gaussian_sigma',10.0) target_areas = kwargs.get('target_areas',None) property_topomesh_vertices_deformation(topomesh,iterations=iterations_per_step,omega_forces=omega_forces,sigma_deformation=sigma_deformation,gradient_derivatives=gradient_derivatives,voxelsize=kwargs.get("image_voxelsize",(1.0,1.0,1.0)),gaussian_sigma=gaussian_sigma,target_areas=target_areas) if cell_vertex_motion: vertex_start_time = time() print "--> Moving cell vertices" if iteration <= (iterations/iterations_per_step+1)/1.: #topomesh.update_wisp_property('barycenter',degree=0,values=((iterations/iterations_per_step+1-(iteration+1))*initial_vertex_positions.values(matched_mesh_vertices) + (iteration+1)*final_vertex_positions.values(matched_mesh_vertices))/(iterations/iterations_per_step+1),keys=matched_mesh_vertices,erase_property=False) for v in matched_mesh_vertices: topomesh.wisp_property('barycenter',degree=0)[v] = ((iterations/iterations_per_step+1-(iteration+1))*initial_vertex_positions[v] + (iteration+1)*final_vertex_positions[v])/(iterations/iterations_per_step+1) vertex_end_time = time() print "<-- Moving cell vertices [",vertex_end_time-vertex_start_time,"s]" compute_topomesh_property(topomesh,'length',degree=1) compute_topomesh_property(topomesh,'barycenter',degree=3) compute_topomesh_property(topomesh,'barycenter',degree=2) if triangular_mesh: compute_topomesh_triangle_properties(topomesh) compute_topomesh_property(topomesh,'normal',degree=2) if edge_flip: # property_topomesh_edge_flip_optimization(topomesh,omega_energies=omega_forces,simulated_annealing=True,iterations=15,display=display) property_topomesh_edge_flip_optimization(topomesh,omega_energies=omega_forces,simulated_annealing=False,iterations=3,display=display) compute_topomesh_property(topomesh,'length',degree=1) compute_topomesh_property(topomesh,'barycenter',degree=3) compute_topomesh_property(topomesh,'barycenter',degree=2) if triangular_mesh: compute_topomesh_triangle_properties(topomesh) compute_topomesh_property(topomesh,'normal',degree=2) sigma_deformation = sigma_deformation_initial*np.power(0.95,(iteration+1)*iterations_per_step)*np.ones_like(np.array(list(topomesh.wisps(0))),float) if cell_vertex_motion: sigma_deformation[np.where(fixed_vertex.values())[0]] = 0. if omega_forces.has_key('regularization'): omega_forces['regularization'] = np.minimum(omega_forces['regularization']+(omega_regularization_max*iterations_per_step)/iterations,omega_regularization_max) if display: pass end_time = time() print "_____________________________" print "" print " [",end_time-start_time,"s]" #raw_input() print "_____________________________" optimization_end_time = time() print "--> Optimizing Topomesh [",optimization_end_time - optimization_start_time,"s]" return topomesh
def nuclei_topomesh_curvature(topomesh, surface_subdivision=1, return_topomesh=False, projection_center=None): L1_cells = topomesh.wisp_property( 'layer', 0).keys()[topomesh.wisp_property('layer', 0).values() == 1] cell_barycenters = array_dict( topomesh.wisp_property('barycenter', 0).values(L1_cells), L1_cells) if projection_center is None: center = cell_barycenters.values().mean(axis=0) center[2] -= 2. * (cell_barycenters.values() - cell_barycenters.values().mean(axis=0))[:, 2].max() else: center = np.array(projection_center) cell_vectors = cell_barycenters.values() - center cell_r = np.linalg.norm(cell_vectors, axis=1) cell_rx = np.linalg.norm(cell_vectors[:, np.array([0, 2])], axis=1) cell_ry = np.linalg.norm(cell_vectors[:, np.array([1, 2])], axis=1) cell_phi = np.sign(cell_vectors[:, 0]) * np.arccos( cell_vectors[:, 2] / cell_rx) cell_psi = np.sign(cell_vectors[:, 1]) * np.arccos( cell_vectors[:, 2] / cell_ry) cell_flat_barycenters = deepcopy(cell_barycenters) for i, c in enumerate(cell_barycenters.keys()): cell_flat_barycenters[c][0] = cell_phi[i] cell_flat_barycenters[c][1] = cell_psi[i] cell_flat_barycenters[c][2] = 0. triangles = np.array(cell_barycenters.keys())[delaunay_triangulation( np.array([cell_flat_barycenters[c] for c in cell_barycenters.keys()]))] cell_topomesh = triangle_topomesh(triangles, cell_barycenters) maximal_length = 15. compute_topomesh_property(cell_topomesh, 'length', 1) compute_topomesh_property(cell_topomesh, 'triangles', 1) boundary_edges = np.array( map(len, cell_topomesh.wisp_property('triangles', 1).values())) == 1 distant_edges = cell_topomesh.wisp_property('length', 1).values() > maximal_length edges_to_remove = np.array(list(cell_topomesh.wisps(1)))[boundary_edges & distant_edges] while len(edges_to_remove) > 0: triangles_to_remove = np.concatenate( cell_topomesh.wisp_property('triangles', 1).values(edges_to_remove)) for t in triangles_to_remove: cell_topomesh.remove_wisp(2, t) clean_topomesh(cell_topomesh) compute_topomesh_property(cell_topomesh, 'triangles', 1) boundary_edges = np.array( map(len, cell_topomesh.wisp_property('triangles', 1).values())) == 1 distant_edges = cell_topomesh.wisp_property( 'length', 1).values() > maximal_length edges_to_remove = np.array(list( cell_topomesh.wisps(1)))[boundary_edges & distant_edges] cell_topomesh = topomesh_connected_components(cell_topomesh)[0] property_topomesh_vertices_deformation(cell_topomesh, iterations=5) for i in xrange(surface_subdivision): cell_topomesh = topomesh_triangle_split(cell_topomesh) compute_topomesh_property(cell_topomesh, 'vertices', 2) property_topomesh_vertices_deformation(cell_topomesh, iterations=15) compute_topomesh_property(cell_topomesh, 'barycenter', 2) compute_topomesh_property(cell_topomesh, 'normal', 2, normal_method='orientation') compute_topomesh_vertex_property_from_faces(cell_topomesh, 'normal', adjacency_sigma=2, neighborhood=5) compute_topomesh_property(cell_topomesh, 'mean_curvature', 2) compute_topomesh_vertex_property_from_faces(cell_topomesh, 'mean_curvature', adjacency_sigma=2, neighborhood=5) compute_topomesh_vertex_property_from_faces(cell_topomesh, 'gaussian_curvature', adjacency_sigma=2, neighborhood=5) cell_points = cell_barycenters.values() for curvature_property in ['mean_curvature', 'gaussian_curvature']: surface_curvature = cell_topomesh.wisp_property( curvature_property, 0).values(list(cell_topomesh.wisps(0))) cell_potential = np.array([ nuclei_density_function(dict([ (p, cell_topomesh.wisp_property('barycenter', 0)[p]) ]), cell_radius=5, k=1.0)(cell_points[:, 0], cell_points[:, 1], cell_points[:, 2]) for p in cell_topomesh.wisps(0) ]) cell_curvature = (cell_potential * surface_curvature[:, np.newaxis] ).sum(axis=0) / cell_potential.sum(axis=0) cell_curvature = dict(zip(cell_barycenters.keys(), cell_curvature)) topomesh.update_wisp_property( curvature_property, 0, array_dict([ cell_curvature[c] if c in cell_barycenters.keys() else 0 for c in topomesh.wisps(0) ], list(topomesh.wisps(0)))) if return_topomesh: return cell_topomesh else: return
def link_polydata_triangle_cells(polydata,img,img_graph=None): if img_graph is None: from openalea.image.algo.graph_from_image import graph_from_image img_graph = graph_from_image(img,spatio_temporal_properties=['barycenter','volume'],ignore_cells_at_stack_margins = False,property_as_real=True) polydata_cell_data = polydata.GetCellData().GetArray(0) start_time = time() print " --> Listing points" polydata_points = np.array([polydata.GetPoints().GetPoint(i) for i in xrange(polydata.GetPoints().GetNumberOfPoints())]) end_time = time() print " <-- Listing points [",end_time - start_time,"s]" start_time = time() print " --> Merging points" point_ids = {} for p in xrange(polydata.GetPoints().GetNumberOfPoints()): point_ids[tuple(polydata_points[p])] = [] for p in xrange(polydata.GetPoints().GetNumberOfPoints()): point_ids[tuple(polydata_points[p])] += [p] unique_points = array_unique(polydata_points) n_points = unique_points.shape[0] point_unique_id = {} for p in xrange(n_points): for i in point_ids[tuple(unique_points[p])]: point_unique_id[i] = p end_time = time() print " <-- Merging points [",end_time - start_time,"s]" triangle_cell_start_time = time() print " --> Listing triangles" print " - ",polydata.GetNumberOfCells()," triangles" polydata_triangles = np.sort([[polydata.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in xrange(polydata.GetNumberOfCells())]) print " - ",array_unique(polydata_triangles).shape[0]," unique triangles" # polydata_triangle_points = [polydata.GetCell(t).GetPointIds() for t in xrange(polydata.GetNumberOfCells())] # polydata_triangles = np.sort([[triangle_points.GetId(i) for i in xrange(3)] for triangle_points in polydata_triangle_points]) polydata_triangles = np.sort(array_dict(point_unique_id).values(polydata_triangles)) print " - ",array_unique(polydata_triangles).shape[0]," unique triangles (merged vertices)" triangle_cell_end_time = time() print " <-- Listing triangles [",triangle_cell_end_time - triangle_cell_start_time,"s]" raw_input() triangle_cell_start_time = time() print " --> Initializing triangle cells" triangle_cells = {} for t in xrange(polydata.GetNumberOfCells()): triangle_cells[tuple(polydata_triangles[t])] = [] for i in xrange(10): if t == (i*polydata.GetNumberOfCells())/10: print " --> Initializing triangle cells (",10*i,"%)" triangle_cell_end_time = time() print " <-- Initializing triangle cells [",triangle_cell_end_time - triangle_cell_start_time,"s]" triangle_cell_start_time = time() for t in xrange(polydata.GetNumberOfCells()): triangle_cells[tuple(polydata_triangles[t])] += list(polydata_cell_data.GetTuple(t)) for i in xrange(100): if t == (i*polydata.GetNumberOfCells())/100: triangle_cell_end_time = time() print " --> Listing triangle cells (",i,"%) [",(triangle_cell_end_time-triangle_cell_start_time)/(polydata.GetNumberOfCells()/100.),"s]" triangle_cell_start_time = time() triangle_cell_start_time = time() print " --> Cleaning triangle cells" for t in xrange(polydata.GetNumberOfCells()): triangle_cells[tuple(polydata_triangles[t])] = np.unique(triangle_cells[tuple(polydata_triangles[t])]) for i in xrange(10): if t == (i*polydata.GetNumberOfCells())/10: print " --> Cleaning triangle cells (",10*i,"%)" triangle_cell_end_time = time() print " <-- Cleaning triangle cells [",triangle_cell_end_time - triangle_cell_start_time,"s]" # triangle_cell_start_time = time() # print " --> Listing triangle cells" # triangle_cell = np.array([polydata_cell_data.GetTuple(t)[0] for t in xrange(polydata.GetNumberOfCells())],np.uint16) # triangle_cell_end_time = time() # print " <-- Listing triangle cells [",triangle_cell_end_time - triangle_cell_start_time,"s]" # triangle_cells = {} # for t in xrange(polydata.GetNumberOfCells()): # triangle_cells[t] = [] # for c in considered_cells: # cell_triangles = np.where(triangle_cell == c)[0] # for t in cell_triangles: # triangle_cells[t] += [c] # print " Cell ",c," : ",cell_triangles.shape[0]," triangles" # neighbor_triangles = where_list(triangle_cell,list(img_graph.neighbors(c)))[0] # neighbor_triangle_matching = vq(polydata_triangles[cell_triangles],polydata_triangles[neighbor_triangles]) # cell_double_triangles = neighbor_triangles[neighbor_triangle_matching[0][np.where(neighbor_triangle_matching[1]==0)[0]]] # for t in cell_double_triangles: # triangle_cells[t] += [c] # print triangle_cells.values() # raw_input() # unique_triangles,unique_triangle_rows = array_unique(polydata_triangles,return_index=True) # n_triangles = unique_triangles.shape[0] # triangle_unique = array_dict(np.arange(n_triangles),unique_triangle_rows) # triangle_id = (polydata_triangles * np.array([contour.GetOutput().GetPoints().GetNumberOfPoints(),1,1./contour.GetOutput().GetPoints().GetNumberOfPoints()])).sum(axis=1) # unique_triangle_id = (unique_triangles * np.array([contour.GetOutput().GetPoints().GetNumberOfPoints(),1,1./contour.GetOutput().GetPoints().GetNumberOfPoints()])).sum(axis=1) # triangle_number = nd.sum(np.ones_like(triangle_id),triangle_id,index=triangle_id) # double_triangle_rows = np.where(triangle_number==2)[0] # print " ",double_triangle_rows.shape[0]," double triangles / ",contour.GetOutput().GetNumberOfCells() # double_triangles = polydata_triangles[double_triangle_rows] # unique_triangle_number = nd.sum(np.ones_like(triangle_id),triangle_id,index=unique_triangle_id) # double_unique_triangle_rows = np.where(unique_triangle_number==2)[0] # double_unique_triangles = unique_triangles[double_unique_triangle_rows] # triangle_triangle_matching = (vq(double_triangles,double_unique_triangles)[0]) # triangle_triangle_matching = array_dict(double_unique_triangle_rows[triangle_triangle_matching],double_triangle_rows) # unique_triangle_cells = {} # for t in xrange(n_triangles): # unique_triangle_cells[t] = [] # for t in xrange(polydata.GetNumberOfCells()): # if triangle_number[t] == 1: # unique_triangle_cells[triangle_unique[t]] += list(polydata_cell_data.GetTuple(t)) # elif triangle_number[t] == 2: # unique_triangle_cells[triangle_triangle_matching[t]] += list(polydata_cell_data.GetTuple(t)) # triangle_cells = {} # for t in xrange(polydata.GetNumberOfCells()): # if triangle_number[t] == 1: # triangle_cells[t] = np.array(unique_triangle_cells[triangle_unique[t]],np.uint16) # elif triangle_number[t] == 2: # triangle_cells[t] = np.array(unique_triangle_cells[triangle_triangle_matching[t]],np.uint16) cell_data = vtk.vtkFloatArray() cell_data.SetNumberOfComponents(2) cell_data.SetNumberOfTuples(polydata.GetNumberOfCells()) for t in xrange(polydata.GetNumberOfCells()): triangle_key = tuple(polydata_triangles[t]) if len(triangle_cells[triangle_key]) == 2: cell_data.SetTuple(t,np.sort(triangle_cells[triangle_key])) else: cell_data.SetTuple(t,np.concatenate([triangle_cells[triangle_key],[1]])) polydata.GetCellData().SetScalars(cell_data) return triangle_cells
def up_facing_surface_topomesh(input_surface_topomesh, normal_method='density', nuclei_positions=None, down_facing_threshold=-0., connected=True): assert (normal_method != 'density') or (nuclei_positions is not None) if nuclei_positions is not None: positions = array_dict(nuclei_positions) else: positions = None surface_topomesh = deepcopy(input_surface_topomesh) compute_topomesh_property(surface_topomesh, 'normal', 2, normal_method=normal_method, object_positions=positions) compute_topomesh_vertex_property_from_faces(surface_topomesh, 'normal', weighting='area', adjacency_sigma=1.2, neighborhood=3) down_facing = surface_topomesh.wisp_property( 'normal', 0).values()[:, 2] < down_facing_threshold surface_topomesh.update_wisp_property( 'downward', 0, array_dict(down_facing, keys=list(surface_topomesh.wisps(0)))) triangle_down_facing = np.any(surface_topomesh.wisp_property( 'downward', 0).values( surface_topomesh.wisp_property('vertices', 2).values( list(surface_topomesh.wisps(2)))), axis=1) triangle_down_facing = triangle_down_facing.astype(float) surface_topomesh.update_wisp_property( 'downward', 2, array_dict(triangle_down_facing, keys=list(surface_topomesh.wisps(2)))) for i, t in enumerate(surface_topomesh.wisps(2)): if surface_topomesh.wisp_property('downward', 2)[t] == 1: triangle_neighbors = np.array( list(surface_topomesh.border_neighbors(2, t)), np.uint16) if np.any( surface_topomesh.wisp_property('downward', 2).values( triangle_neighbors) == 0): triangle_down_facing[i] = 0.5 surface_topomesh.update_wisp_property( 'downward', 2, array_dict(triangle_down_facing, keys=list(surface_topomesh.wisps(2)))) triangles_to_remove = np.array(list(surface_topomesh.wisps(2)))[ surface_topomesh.wisp_property('downward', 2).values() == 1] for t in triangles_to_remove: surface_topomesh.remove_wisp(2, t) edges_to_remove = np.array(list(surface_topomesh.wisps(1)))[np.array([ surface_topomesh.nb_regions(1, e) == 0 for e in surface_topomesh.wisps(1) ])] for e in edges_to_remove: surface_topomesh.remove_wisp(1, e) vertices_to_remove = np.array(list(surface_topomesh.wisps(0)))[np.array([ surface_topomesh.nb_regions(0, v) == 0 for v in surface_topomesh.wisps(0) ])] for v in vertices_to_remove: surface_topomesh.remove_wisp(0, v) #top_surface_topomesh = cut_surface_topomesh(surface_topomesh,z_cut=0.8*size[2]*voxelsize[2]) if connected: top_surface_topomesh = topomesh_connected_components( surface_topomesh)[0] else: top_surface_topomesh = surface_topomesh return top_surface_topomesh
def evaluate_positions_detection(vertex_topomesh, ground_truth_topomesh, max_matching_distance=3.0, outlying_distance=5.0, max_distance=100.): """ Parameters ---------- vertex_topomesh : topomesh a topomesh with nuclei/seed coordinates (require wisp_property 'barycenter') to compare to a ground truth ground_truth_topomesh : topomesh a topomesh with expertised nuclei/seed coordinates (require wisp_property 'barycenter') to be used as reference for evaluation max_matching_distance : float outlying_distance : float, optional max_distance : float, optional Returns ------- dictionary of indicators (after matching) such as: 'True Positive': 'False Negative': 'False Positive': 'Precision': 'Recall': 'Jaccard': 'Dice': Notes ----- Requires the Hungarian library : https://github.com/hrldcpr/hungarian """ nuc_ids = vertex_topomesh.wisp_property('barycenter', 0).keys() nuc_coords = vertex_topomesh.wisp_property('barycenter', 0).values() grt_coords = ground_truth_topomesh.wisp_property('barycenter', 0).values() segmentation_ground_truth_matching = vq(nuc_coords, grt_coords) ground_truth_segmentation_complete_matching = np.array([vq(nuc_coords, np.array([p]))[1] for p in grt_coords]) segmentation_outliers = array_dict(segmentation_ground_truth_matching[1] > outlying_distance + 1, nuc_ids) cost_matrix = deepcopy(ground_truth_segmentation_complete_matching) if cost_matrix.shape[0] < cost_matrix.shape[1]: cost_matrix = np.concatenate([cost_matrix, np.ones((cost_matrix.shape[1] - cost_matrix.shape[0], cost_matrix.shape[1])) * max_distance]) elif cost_matrix.shape[1] < cost_matrix.shape[0]: cost_matrix = np.concatenate([cost_matrix, np.ones((cost_matrix.shape[0], cost_matrix.shape[0] - cost_matrix.shape[1])) * max_distance], axis=1) cost_matrix[cost_matrix > outlying_distance] = max_distance initial_cost_matrix = deepcopy(cost_matrix) start_time = time() print "--> Hungarian assignment..." assignment = lap(cost_matrix) end_time = time() print "<-- Hungarian assignment [", end_time - start_time, "s]" ground_truth_assignment = np.arange(ground_truth_topomesh.nb_wisps(0)) segmentation_assignment = assignment[0][:ground_truth_topomesh.nb_wisps(0)] assignment_distances = initial_cost_matrix[ (ground_truth_assignment, segmentation_assignment)] # print "Assignment : ",assignment_distances.mean() evaluation = {} evaluation['True Positive'] = (assignment_distances < max_matching_distance).sum() evaluation['False Negative'] = (assignment_distances >= max_matching_distance).sum() evaluation['False Positive'] = vertex_topomesh.nb_wisps(0) - segmentation_outliers.values().sum() - evaluation['True Positive'] evaluation['Precision'] = evaluation['True Positive'] / float(evaluation['True Positive'] + evaluation['False Positive']) if evaluation['True Positive'] + evaluation['False Positive'] > 0 else 100. evaluation['Recall'] = evaluation['True Positive'] / float(evaluation['True Positive'] + evaluation['False Negative']) evaluation['Jaccard'] = evaluation['True Positive'] / float(evaluation['True Positive'] + evaluation['False Positive'] + evaluation['False Negative']) evaluation['Dice'] = 2. * evaluation['True Positive'] / float(2. * evaluation['True Positive'] + evaluation['False Positive'] + evaluation['False Negative']) print "Precision ", np.round(100. * evaluation['Precision'], 2), "%, Recall ", np.round(100. * evaluation['Recall'], 2), "%" return evaluation
def image_to_vtk_polydata(img,considered_cells=None,mesh_center=None,coef=1.0,mesh_fineness=1.0): start_time = time() print "--> Generating vtk mesh from image" vtk_mesh = vtk.vtkPolyData() vtk_points = vtk.vtkPoints() vtk_triangles = vtk.vtkCellArray() vtk_cells = vtk.vtkLongArray() nx, ny, nz = img.shape data_string = img.tostring('F') reader = vtk.vtkImageImport() reader.CopyImportVoidPointer(data_string, len(data_string)) if img.dtype == np.uint8: reader.SetDataScalarTypeToUnsignedChar() else: reader.SetDataScalarTypeToUnsignedShort() reader.SetNumberOfScalarComponents(1) reader.SetDataExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) reader.SetWholeExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) reader.SetDataSpacing(*img.resolution) if considered_cells is None: considered_cells = np.unique(img)[1:] if mesh_center is None: mesh_center = np.array(img.resolution)*np.array(img.shape)/2. marching_cube_start_time = time() print " --> Marching Cubes" contour = vtk.vtkDiscreteMarchingCubes() SetInput(contour,reader.GetOutput()) contour.ComputeNormalsOn() contour.ComputeGradientsOn() contour.ComputeScalarsOn() for i,label in enumerate(considered_cells): contour.SetValue(i,label) contour.Update() marching_cube_end_time = time() print " <-- Marching Cubes : ",contour.GetOutput().GetPoints().GetNumberOfPoints()," Points,",contour.GetOutput().GetNumberOfCells()," Triangles, ",len(np.unique(img)[1:])," Cells [",marching_cube_end_time - marching_cube_start_time,"s]" marching_cubes = contour.GetOutput() marching_cubes_cell_data = marching_cubes.GetCellData().GetArray(0) triangle_cell_start_time = time() print " --> Listing triangles" print " - ",marching_cubes.GetNumberOfCells()," triangles" marching_cubes_triangles = np.sort([[marching_cubes.GetCell(t).GetPointIds().GetId(i) for i in xrange(3)] for t in xrange(marching_cubes.GetNumberOfCells())]) triangle_cell_end_time = time() print " <-- Listing triangles [",triangle_cell_end_time - triangle_cell_start_time,"s]" triangle_cell_start_time = time() print " --> Listing triangle cells" triangle_cell = np.array([marching_cubes_cell_data.GetTuple(t)[0] for t in xrange(marching_cubes.GetNumberOfCells())],np.uint16) triangle_cell_end_time = time() print " <-- Listing triangle cells [",triangle_cell_end_time - triangle_cell_start_time,"s]" triangle_cell_start_time = time() print " --> Updating marching cubes mesh" vtk_mesh = vtk.vtkPolyData() vtk_points = vtk.vtkPoints() vtk_triangles = vtk.vtkCellArray() vtk_cells = vtk.vtkLongArray() for label in considered_cells: # cell_start_time = time() cell_marching_cubes_triangles = marching_cubes_triangles[np.where(triangle_cell == label)] marching_cubes_point_ids = np.unique(cell_marching_cubes_triangles) marching_cubes_points = np.array([marching_cubes.GetPoints().GetPoint(p) for p in marching_cubes_point_ids]) marching_cubes_center = marching_cubes_points.mean(axis=0) marching_cubes_points = marching_cubes_center + coef*(marching_cubes_points-marching_cubes_center) - mesh_center cell_points = [] for p in xrange(marching_cubes_points.shape[0]): pid = vtk_points.InsertNextPoint(marching_cubes_points[p]) cell_points.append(pid) cell_points = array_dict(cell_points,marching_cubes_point_ids) for t in xrange(cell_marching_cubes_triangles.shape[0]): poly = vtk_triangles.InsertNextCell(3) for i in xrange(3): pid = cell_marching_cubes_triangles[t][i] vtk_triangles.InsertCellPoint(cell_points[pid]) vtk_cells.InsertValue(poly,label) # cell_end_time = time() # print " --> Cell",label,":",cell_marching_cubes_triangles.shape[0],"triangles [",cell_end_time-cell_start_time,"s]" vtk_mesh.SetPoints(vtk_points) vtk_mesh.SetPolys(vtk_triangles) vtk_mesh.GetCellData().SetScalars(vtk_cells) triangle_cell_end_time = time() print " <-- Updating marching cubes mesh [",triangle_cell_end_time - triangle_cell_start_time,"s]" decimation_start_time = time() print " --> Decimation" smoother = vtk.vtkWindowedSincPolyDataFilter() SetInput(smoother,vtk_mesh) smoother.SetFeatureAngle(30.0) smoother.SetPassBand(0.05) smoother.SetNumberOfIterations(25) smoother.NonManifoldSmoothingOn() smoother.NormalizeCoordinatesOn() smoother.Update() decimate = vtk.vtkQuadricClustering() SetInput(decimate,smoother.GetOutput()) decimate.SetNumberOfDivisions(*tuple(mesh_fineness*np.array(np.array(img.shape)*np.array(img.resolution)/2.,np.uint16))) decimate.SetFeaturePointsAngle(30.0) decimate.CopyCellDataOn() decimate.Update() decimation_end_time = time() print " <-- Decimation : ",decimate.GetOutput().GetPoints().GetNumberOfPoints()," Points,",decimate.GetOutput().GetNumberOfCells()," Triangles, ",len(considered_cells)," Cells [",decimation_end_time - decimation_start_time,"s]" end_time = time() print "<-- Generating vtk mesh from image [",end_time-start_time,"s]" return decimate.GetOutput()
def update_graph_display(self, world_object, attribute): if world_object: graph = world_object.data if isinstance(graph, TemporalPropertyGraph): temporal = True else: temporal = False # labels = list(graph.vertices()) if world_object['filter_property_name'] == "": labels = list(graph.vertices()) else: filter_property = graph.vertex_property( world_object['filter_property_name']) labels = [ v for v in filter_property.keys() if filter_property[v] ] labels = [ v for v in labels if graph.vertex_property('barycenter').has_key(v) ] extent = np.transpose([ np.array( graph.vertex_property('barycenter').values()).min(axis=0), np.array( graph.vertex_property('barycenter').values()).max(axis=0) ]) for dim, axis in enumerate(['x', 'y', 'z']): dim_slice = [ extent[dim, 0] + s * (extent[dim, 1] - extent[dim, 0]) / 100. for s in world_object[axis + "_slice"] ] labels = [ v for v in labels if graph.vertex_property('barycenter')[v][dim] >= dim_slice[0] ] labels = [ v for v in labels if graph.vertex_property('barycenter')[v][dim] <= dim_slice[1] ] if temporal: if not world_object['all_time_points']: time_point = world_object['time_point'] labels = [ v for v in labels if graph.vertex_temporal_index(v) == time_point ] # if world_object['cell_layer'] == 'L1': # labels = sia.cell_first_layer() # elif world_object['cell_layer'] == 'L2': # labels = sia.cell_second_layer() # else: # labels = sia.labels() for element, element_plural in zip(['vertex', 'edge'], ['vertices', 'edges']): if 'display_' + element_plural in attribute[ 'name'] or attribute['name'] in [ 'filter_property_name', 'time_point', 'edge_type', 'all_time_points', 'time_offset' ] or '_slice' in attribute['name']: if world_object['display_' + element_plural]: property_name = world_object[element + '_property_name'] if temporal: edge_type = world_object['edge_type'] time_offset = world_object['time_offset'] if not world_object['all_time_points']: mesh = property_graph_to_triangular_mesh( graph, element, property_name, labels, edge_type=edge_type) else: mesh = property_graph_to_triangular_mesh( graph, element, property_name, labels, edge_type=edge_type, time_offset=time_offset * (extent[0, 1] - extent[0, 0])) else: mesh = property_graph_to_triangular_mesh( graph, element, property_name, labels) if self.world.has_key(world_object.name + "_" + element_plural): kwargs = world_kwargs( self.world[world_object.name + "_" + element_plural]) else: kwargs = {} kwargs['colormap'] = ( 'glasbey' if element == 'vertex' else 'grey') if (property_name == '') else 'jet' self._mesh[world_object.name][element] = mesh self.world.add( self._mesh[world_object.name][element], world_object.name + "_" + element_plural, **kwargs) else: self.world.remove(world_object.name + "_" + element_plural) elif element + '_property_name' in attribute['name']: if world_object['display_' + element_plural]: property_name = world_object[element + '_property_name'] if element == 'vertex': if property_name in graph.vertex_property_names(): graph_property = graph.vertex_property( property_name) property_data = array_dict( dict( zip(labels, [ graph_property[l] if graph_property.has_key(l) else np.nan for l in labels ]))) else: property_data = array_dict( dict(zip(labels, labels))) self._mesh[world_object.name][ element].point_data = property_data elif element == 'edge': graph_edges = self._mesh[ world_object.name][element].edges.keys() if property_name in graph.edge_property_names(): graph_property = graph.edge_property( property_name) property_data = array_dict( dict( zip(graph_edges, [ graph_property[e] if graph_property.has_key(e) else np.nan for e in graph_edges ]))) else: property_data = array_dict({}) self._mesh[world_object. name][element].edge_data = property_data self.world[world_object.name + "_" + element_plural].data = self._mesh[ world_object.name][element] if len(property_data) > 1: self.world[world_object.name + "_" + element_plural].set_attribute( 'intensity_range', (property_data.values().min(), property_data.values().max())) elif element + '_dataframe' in attribute['name']: if world_object[element + '_dataframe']: property_name = world_object[element + '_property_name'] df = property_graph_to_dataframe( graph, element, labels) self.world.add( df, world_object.name + "_" + element + "_dataframe") self.world[world_object.name + "_" + element + "_dataframe"].set_attribute( 'X_variable', property_name) self.world[world_object.name + "_" + element + "_dataframe"].set_attribute( 'plot', 'cumulative') else: self.world.remove(world_object.name + "_" + element + "_dataframe")
def image_to_vtk_cell_polydata(img,considered_cells=None,mesh_center=None,coef=1.0,mesh_fineness=1.0,smooth_factor=1.0): start_time = time() print "--> Generating vtk mesh from image" vtk_mesh = vtk.vtkPolyData() vtk_points = vtk.vtkPoints() vtk_triangles = vtk.vtkCellArray() vtk_cells = vtk.vtkLongArray() nx, ny, nz = img.shape data_string = img.tostring('F') reader = vtk.vtkImageImport() reader.CopyImportVoidPointer(data_string, len(data_string)) if img.dtype == np.uint8: reader.SetDataScalarTypeToUnsignedChar() else: reader.SetDataScalarTypeToUnsignedShort() reader.SetNumberOfScalarComponents(1) reader.SetDataExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) reader.SetWholeExtent(0, nx - 1, 0, ny - 1, 0, nz - 1) reader.SetDataSpacing(*img.resolution) reader.Update() if considered_cells is None: considered_cells = np.unique(img)[1:] if mesh_center is None: #mesh_center = np.array(img.resolution)*np.array(img.shape)/2. mesh_center = np.array([0,0,0]) for label in considered_cells: cell_start_time = time() cell_volume = (img==label).sum()*np.array(img.resolution).prod() # mask_data = vtk.vtkImageThreshold() # mask_data.SetInputConnection(reader.GetOutputPort()) # mask_data.ThresholdBetween(label, label) # mask_data.ReplaceInOn() # mask_data.SetInValue(label) # mask_data.SetOutValue(0) contour = vtk.vtkDiscreteMarchingCubes() # contour.SetInput(mask_data.GetOutput()) SetInput(contour,reader.GetOutput()) contour.ComputeNormalsOn() contour.ComputeGradientsOn() contour.SetValue(0,label) contour.Update() # print " --> Marching Cubes : ",contour.GetOutput().GetPoints().GetNumberOfPoints()," Points,",contour.GetOutput().GetNumberOfCells()," Triangles, 1 Cell" # decimate = vtk.vtkDecimatePro() # decimate.SetInputConnection(contour.GetOutputPort()) # # decimate.SetTargetReduction(0.75) # decimate.SetTargetReduction(0.66) # # decimate.SetTargetReduction(0.5) # # decimate.SetMaximumError(2*np.sqrt(3)) # decimate.Update() smooth_iterations = int(np.ceil(smooth_factor*8.)) smoother = vtk.vtkWindowedSincPolyDataFilter() SetInput(smoother,contour.GetOutput()) smoother.BoundarySmoothingOn() # smoother.BoundarySmoothingOff() smoother.FeatureEdgeSmoothingOn() # smoother.FeatureEdgeSmoothingOff() smoother.SetFeatureAngle(120.0) # smoother.SetPassBand(1) smoother.SetPassBand(0.01) smoother.SetNumberOfIterations(smooth_iterations) smoother.NonManifoldSmoothingOn() smoother.NormalizeCoordinatesOn() smoother.Update() divisions = int(np.ceil(np.power(cell_volume,1/3.)*mesh_fineness)) decimate = vtk.vtkQuadricClustering() # decimate = vtk.vtkQuadricDecimation() # decimate = vtk.vtkDecimatePro() # decimate.SetInput(contour.GetOutput()) SetInput(decimate,smoother.GetOutput()) # decimate.SetTargetReduction(0.95) # decimate.AutoAdjustNumberOfDivisionsOff() decimate.SetNumberOfDivisions(divisions,divisions,divisions) decimate.SetFeaturePointsAngle(120.0) # decimate.AttributeErrorMetricOn() # decimate.ScalarsAttributeOn() # decimate.PreserveTopologyOn() # decimate.CopyCellDataOn() # decimate.SetMaximumCost(1.0) # decimate.SetMaximumCollapsedEdges(10000.0) decimate.Update() # print " --> Decimation : ",decimate.GetOutput().GetPoints().GetNumberOfPoints()," Points,",decimate.GetOutput().GetNumberOfCells()," Triangles, 1 Cell" cell_polydata = decimate.GetOutput() # cell_polydata = smoother.GetOutput() polydata_points = np.array([cell_polydata.GetPoints().GetPoint(p) for p in xrange(cell_polydata.GetPoints().GetNumberOfPoints())]) polydata_center = polydata_points.mean(axis=0) polydata_points = polydata_center + coef*(polydata_points-polydata_center) - mesh_center cell_points = [] for p in xrange(cell_polydata.GetPoints().GetNumberOfPoints()): pid = vtk_points.InsertNextPoint(polydata_points[p]) cell_points.append(pid) cell_points = array_dict(cell_points,np.arange(cell_polydata.GetPoints().GetNumberOfPoints())) for t in xrange(cell_polydata.GetNumberOfCells()): poly = vtk_triangles.InsertNextCell(3) for i in xrange(3): pid = cell_polydata.GetCell(t).GetPointIds().GetId(i) vtk_triangles.InsertCellPoint(cell_points[pid]) vtk_cells.InsertValue(poly,label) cell_end_time = time() print " --> Cell",label,":",decimate.GetOutput().GetNumberOfCells(),"triangles (",cell_volume," microm3 ) [",cell_end_time-cell_start_time,"s]" vtk_mesh.SetPoints(vtk_points) vtk_mesh.SetPolys(vtk_triangles) vtk_mesh.GetCellData().SetScalars(vtk_cells) print " <-- Cell Mesh : ",vtk_mesh.GetPoints().GetNumberOfPoints()," Points,",vtk_mesh.GetNumberOfCells()," Triangles, ",len(considered_cells)," Cells" end_time = time() print "<-- Generating vtk mesh from image [",end_time-start_time,"s]" return vtk_mesh
def compute_image_property(self, property_name, min_contact_area=None, sub_factor=8.): """ """ computable_properties = [ 'barycenter', 'volume', 'neighborhood_size', 'layer', 'mean_curvature', 'gaussian_curvature' ] try: assert property_name in computable_properties except: print "Property \"" + property_name + "\" can not be computed on image" print "Try with one of the following :" for p in computable_properties: print " * " + p else: if self._image is not None: if property_name in ['barycenter', 'volume']: graph = graph_from_image( self._image, background=self.background, spatio_temporal_properties=[property_name], ignore_cells_at_stack_margins=self. ignore_cells_at_stack_margins) property_dict = graph.vertex_property(property_name) elif property_name == 'neighborhood_size': neighbors = [ self.image_graph.neighbors(l) for l in self.labels ] property_dict = dict(zip(self.labels, map(len, neighbors))) elif property_name == 'layer': if min_contact_area is None: min_contact_area = self.min_contact_area graph = graph_from_image( self._image, background=self.background, spatio_temporal_properties=['L1'], ignore_cells_at_stack_margins=self. ignore_cells_at_stack_margins, min_contact_area=min_contact_area) first_layer = graph.vertex_property('L1') second_layer_cells = [ v for v in graph.vertices() if np.any([first_layer[n] for n in graph.neighbors(v)]) and not first_layer[v] ] second_layer = dict( zip(list(graph.vertices()), [ v in second_layer_cells for v in graph.vertices() ])) property_dict = dict( zip(self.labels, [ 1 if first_layer[l] else 2 if second_layer[l] else 3 for l in self.labels ])) elif property_name in ['mean_curvature', 'gaussian_curvature']: if not self.has_image_property('barycenter'): self.compute_image_property('barycenter') if not self.has_image_property('layer'): print "--> Computing layer property" self.compute_image_property('layer') cell_centers = self.image_property('barycenter') L1_cells = self.labels[self.image_property( 'layer').values() == 1] from openalea.cellcomplex.property_topomesh.utils.implicit_surfaces import implicit_surface_topomesh from openalea.cellcomplex.property_topomesh.property_topomesh_analysis import compute_topomesh_property, compute_topomesh_vertex_property_from_faces from openalea.cellcomplex.property_topomesh.property_topomesh_optimization import property_topomesh_vertices_deformation, topomesh_triangle_split sub_binary_image = (self._image != self.background).astype( float)[::sub_factor, ::sub_factor, ::sub_factor] surface_topomesh = implicit_surface_topomesh( sub_binary_image, np.array(sub_binary_image.shape), sub_factor * np.array(self._image.voxelsize), center=False) property_topomesh_vertices_deformation(surface_topomesh, iterations=10) compute_topomesh_property(surface_topomesh, 'barycenter', 2) compute_topomesh_property(surface_topomesh, 'normal', 2, normal_method='orientation') compute_topomesh_vertex_property_from_faces( surface_topomesh, 'normal', adjacency_sigma=2, neighborhood=5) compute_topomesh_property(surface_topomesh, 'mean_curvature', 2) compute_topomesh_vertex_property_from_faces( surface_topomesh, property_name, adjacency_sigma=2, neighborhood=5) surface_cells = L1_cells[vq( surface_topomesh.wisp_property('barycenter', 0).values(), cell_centers.values(L1_cells))[0]] surface_topomesh.update_wisp_property( 'label', 0, array_dict(surface_cells, list(surface_topomesh.wisps(0)))) L1_cell_property = nd.sum(surface_topomesh.wisp_property( property_name, 0).values(), surface_cells, index=L1_cells) / nd.sum( np.ones_like(surface_cells), surface_cells, index=L1_cells) L1_cell_property = array_dict(L1_cell_property, L1_cells) property_dict = array_dict([ L1_cell_property[l] if (l in L1_cells) and (not np.isnan(L1_cell_property[l])) else 0 for l in self.labels ], self.labels) property_data = [property_dict[l] for l in self.labels] self.update_image_property(property_name, property_data)
def nuclei_surface_topomesh(nuclei_topomesh, size, voxelsize, cell_radius=5.0, subsampling=6., density_k=0.25): nuclei_positions = nuclei_topomesh.wisp_property('barycenter', 0) from time import time start_time = time() size_offset = 0.25 grid_voxelsize = np.sign(voxelsize) * subsampling #x,y,z = np.ogrid[0:size[0]*voxelsize[0]:grid_voxelsize[0],0:size[1]*voxelsize[1]:grid_voxelsize[1],0:size[2]*voxelsize[2]:grid_voxelsize[2]] #grid_size = size x, y, z = np.ogrid[-size_offset * size[0] * voxelsize[0]:(1 + size_offset) * size[0] * voxelsize[0]:grid_voxelsize[0], -size_offset * size[1] * voxelsize[1]:(1 + size_offset) * size[1] * voxelsize[1]:grid_voxelsize[1], -size_offset * size[2] * voxelsize[2]:(1 + size_offset) * size[2] * voxelsize[2]:grid_voxelsize[2]] grid_size = (1 + 2. * size_offset) * size end_time = time() print "--> Generating grid [", end_time - start_time, "s]" start_time = time() nuclei_density = nuclei_density_function(nuclei_positions, cell_radius=cell_radius, k=density_k)(x, y, z) end_time = time() print "--> Computing density [", end_time - start_time, "s]" start_time = time() surface_topomesh = implicit_surface_topomesh(nuclei_density, grid_size, voxelsize, iso=0.5, center=False) surface_topomesh.update_wisp_property( 'barycenter', 0, array_dict( surface_topomesh.wisp_property('barycenter', 0).values() - size_offset * voxelsize * size, surface_topomesh.wisp_property('barycenter', 0).keys())) surface_topomesh = topomesh_triangle_split(surface_topomesh) property_topomesh_vertices_deformation( surface_topomesh, iterations=20, omega_forces=dict(taubin_smoothing=0.65), sigma_deformation=2.0) end_time = time() print "--> Generating topomesh [", end_time - start_time, "s]" start_time = time() surface_points = surface_topomesh.wisp_property('barycenter', 0).values() surface_density, surface_potential = nuclei_density_function( nuclei_positions, cell_radius=cell_radius, k=density_k)(surface_points[:, 0], surface_points[:, 1], surface_points[:, 2], return_potential=True) surface_membership = np.transpose( surface_potential) / surface_density[:, np.newaxis] end_time = time() print "--> Computing surface membership [", end_time - start_time, "s]" start_time = time() # print np.argmax(surface_membership,axis=1).shape # print np.argmax(surface_membership,axis=0).shape # print nuclei_topomesh.nb_wisps(0) # print surface_topomesh.nb_wisps(0) surface_topomesh.update_wisp_property( 'cell', 0, array_dict( np.array(nuclei_positions.keys())[np.argmax(surface_membership, axis=1)], list(surface_topomesh.wisps(0)))) for property_name in nuclei_topomesh.wisp_property_names(0): if not property_name in ['barycenter']: #if not property_name in []: if nuclei_topomesh.wisp_property(property_name, 0).values().ndim == 1: # print (surface_membership*nuclei_topomesh.wisp_property(property_name,0).values()[np.newaxis,:]).sum(axis=1).shape surface_topomesh.update_wisp_property( property_name, 0, array_dict( (surface_membership * nuclei_topomesh.wisp_property( property_name, 0).values()[np.newaxis, :]).sum( axis=1), list(surface_topomesh.wisps(0)))) elif nuclei_topomesh.wisp_property(property_name, 0).values().ndim == 2: surface_topomesh.update_wisp_property( property_name, 0, array_dict( (surface_membership[:, :, np.newaxis] * nuclei_topomesh.wisp_property( property_name, 0).values()[np.newaxis, :]).sum( axis=1), list(surface_topomesh.wisps(0)))) end_time = time() print "--> Updating properties [", end_time - start_time, "s]" return surface_topomesh
def sphere_tissue_image(size=100, n_points=12, n_layers=1): center = np.array([size / 2, size / 2, size / 2], float) coords = np.transpose(np.mgrid[0:size, 0:size, 0:size], (1, 2, 3, 0)).reshape((np.power(size, 3), 3)).astype(int) coords_distances = np.linalg.norm(coords - center, axis=1) points = {} layer_img = {} for layer in xrange(n_layers): radius = (layer + 1) * size / float(2 * n_layers + 1) layer_n_points = n_points * np.power(layer + 1, 2) layer_points = {} for p in range(layer_n_points): theta = np.random.rand() * 2. * np.pi phi = np.random.rand() * np.pi - np.pi / 2. layer_points[p + np.power(layer, 2) * n_points + 3] = center + radius * np.array([ np.cos(theta) * np.cos(phi), np.sin(theta) * np.cos(phi), np.sin(phi) ]) layer_points = array_dict(layer_points) point_target_area = 4. * np.pi * np.power( radius, 2.) / float(layer_n_points) point_target_distance = np.power(point_target_area / np.pi, 0.5) sigma_deformation = (size / 100.) * (20. / layer_n_points) omega_forces = dict(distance=0.1 * size / 100., repulsion=100.0 * np.power(size / 100., 2)) for iterations in xrange(100): point_vectors = np.array([ layer_points[p] - layer_points.values() for p in layer_points.keys() ]) point_distances = np.array([ vq(layer_points.values(), np.array([layer_points[p]]))[1] for p in layer_points.keys() ]) point_vectors = point_vectors / ( point_distances[..., np.newaxis] + 1e-7) point_distance_forces = omega_forces['distance'] * ( (point_distances - point_target_distance)[..., np.newaxis] * point_vectors / point_target_distance).sum(axis=1) point_repulsion_forces = omega_forces['repulsion'] * np.power( point_target_distance, 2) * (point_vectors / (np.power(point_distances, 2) + 1e-7)[..., np.newaxis]).sum(axis=1) point_forces = np.zeros((len(layer_points), 3)) point_forces += point_distance_forces point_forces += point_repulsion_forces point_forces = np.minimum( 1.0, sigma_deformation / np.linalg.norm( point_forces, axis=1))[:, np.newaxis] * point_forces new_points = layer_points.values() + point_forces new_points = center + radius * ( (new_points - center) / np.linalg.norm( (new_points - center), axis=1)[:, np.newaxis]) layer_points = array_dict(new_points, layer_points.keys()) for p in layer_points.keys(): points[p] = layer_points[p] labels = layer_points.keys()[vq(coords, layer_points.values())[0]] layer_img[layer + 1] = np.ones((size, size, size), np.uint8) layer_img[layer + 1][tuple(np.transpose(coords))] = labels points[2] = center points = array_dict(points) # coords = np.transpose(np.mgrid[0:size,0:size,0:size],(1,2,3,0)).reshape((np.power(size,3),3)).astype(int) # labels = points.keys()[vq(coords,points.values())[0]] img = np.ones((size, size, size), np.uint8) for layer in xrange(n_layers): layer_coords = coords[ (coords_distances > (2 * layer + 1) * size / float(4 * (n_layers + 1))) & (coords_distances <= (2 * layer + 3) * size / float(4 * (n_layers + 1)))] img[tuple(np.transpose(layer_coords))] = layer_img[layer + 1][tuple( np.transpose(layer_coords))] center_coords = coords[coords_distances <= size / float(4 * (n_layers + 1))] img[tuple(np.transpose(center_coords))] = 2 ext_coords = coords[coords_distances > (n_layers + 1) * size / float(2 * (n_layers + 2))] img[tuple(np.transpose(ext_coords))] = 1 img = SpatialImage(img, voxelsize=(60. / size, 60. / size, 60. / size)) return img
def compute_image_adjacency(self): """Compute the adjacency relationships between cells in the tissue image. By default, the DRACO adjacency complex is set to the cell_vertices tetrahedra (!!NOT A VALID CELL COMPLEX!!) !!STRONG RISK OF TOPOLOGICAL ERRORS IF DUALIZING AT THIS STAGE!! Updates: image_graph (PropertyGraph): adjacency graph connecting adjacent cells by edges image_cell_vertex (dict): cell vertices representing 4 co-adjacent cells by the point where they meet cell_layer (int): information whether the cell belong to the first layer of cells (L1), the second one (L2) or lower layers (0) layer_edge_topomesh (PropertyTopomesh): adjacency graphs restricted to the L1 and L2 layers layer_triangle_topomesh (PropertyTopomesh): adjacency triangles between L1 and L2 layers (**TO BE COMPLETED**) triangulation_topomesh (PropertyTopomesh): the tetrahedra representing adjacencies between cells Returns: None """ self.image_graph = graph_from_image( self.segmented_image, spatio_temporal_properties=["volume", "barycenter", "L1"], ignore_cells_at_stack_margins=False, property_as_real=True, ) self.image_labels = np.array(list(self.image_graph.vertices())) self.image_cell_volumes = array_dict( [self.image_graph.vertex_property("volume")[v] for v in self.image_labels], self.image_labels ) img_center = np.nanmean(self.image_graph.vertex_property("barycenter").values(), axis=0) self.positions = array_dict(self.image_graph.vertex_property("barycenter")) self.point_topomesh = vertex_topomesh(self.positions) img_analysis = SpatialImageAnalysis(self.segmented_image) exterior_cells = np.array(list(img_analysis.neighbors(1))) self.image_wall_surfaces = img_analysis.wall_areas(real=True) self.image_graph.add_vertex(1) for c in exterior_cells: self.image_graph.add_edge(1, c) for v in self.image_cell_vertex.keys(): self.image_cell_vertex[v] = self.image_cell_vertex[v] * self.resolution image_cell_vertex_tetrahedra = np.sort(self.image_cell_vertex.keys()) image_cell_vertex_tetrahedra = np.delete( image_cell_vertex_tetrahedra, np.where(image_cell_vertex_tetrahedra[:, 0] == 1)[0], axis=0 ) self.image_cell_vertex_topomesh = tetrahedra_topomesh(image_cell_vertex_tetrahedra, self.positions) self.triangulation_topomesh = deepcopy(self.image_cell_vertex_topomesh) truncated_image = self.segmented_image[:, :, :] truncated_image_graph = graph_from_image( truncated_image, spatio_temporal_properties=["barycenter", "L1"], background=1, ignore_cells_at_stack_margins=True, property_as_real=True, ) self.cell_layer = array_dict(np.zeros_like(self.positions.keys()), self.positions.keys()) for c in truncated_image_graph.vertices(): if c > 1 and truncated_image_graph.vertex_property("L1")[c]: self.cell_layer[c] = 1 for c in self.cell_layer.keys(): if c > 1 and self.cell_layer[c] == 1: for n in truncated_image_graph.neighbors(c): if n > 1 and self.cell_layer[n] != 1: self.cell_layer[n] = 2 self.point_topomesh.update_wisp_property( "layer", 0, self.cell_layer.values(list(self.point_topomesh.wisps(0))), list(self.point_topomesh.wisps(0)) ) self.layer_edge_topomesh = {} if (self.cell_layer.values() == 1).sum() > 1: L1_edges = np.array( [ [(c, n) for n in self.image_graph.neighbors(c) if n > 1 and self.cell_layer[n] == 1] for c in self.cell_layer.keys() if self.cell_layer[c] == 1 ] ) L1_edges = np.concatenate([e for e in L1_edges if len(e) > 0]) L1_edges = L1_edges[L1_edges[:, 1] > L1_edges[:, 0]] L1_edge_topomesh = edge_topomesh(L1_edges, self.positions) self.layer_edge_topomesh["L1"] = L1_edge_topomesh if (self.cell_layer.values() == 2).sum() > 1: L2_edges = np.array( [ [(c, n) for n in self.image_graph.neighbors(c) if n > 1 and self.cell_layer[n] == 2] for c in self.cell_layer.keys() if self.cell_layer[c] == 2 ] ) L2_edges = np.concatenate([e for e in L2_edges if len(e) > 0]) L2_edges = L2_edges[L2_edges[:, 1] > L2_edges[:, 0]] L2_edge_topomesh = edge_topomesh(L2_edges, self.positions) self.layer_edge_topomesh["L2"] = L2_edge_topomesh self.layer_triangle_topomesh = {} if (self.cell_layer.values() == 1).sum() > 1 and (self.cell_layer.values() == 2).sum() > 1: L1_L2_edges = np.array( [ [(c, n) for n in self.image_graph.neighbors(c) if n > 1 and self.cell_layer[n] in [1, 2]] for c in self.cell_layer.keys() if self.cell_layer[c] in [1, 2] ] ) L1_L2_edges = np.concatenate([e for e in L1_L2_edges if len(e) > 0]) L1_L2_edges = L1_L2_edges[L1_L2_edges[:, 1] > L1_L2_edges[:, 0]] L1_L2_additional_edges = np.array( [ [ (c, n) for n in np.unique( np.array(self.image_cell_vertex.keys())[ np.where(np.array(self.image_cell_vertex.keys()) == c)[0] ] ) if n > 1 and n != c and (n not in self.image_graph.neighbors(c)) and (self.cell_layer[n] in [1, 2]) ] for c in self.cell_layer.keys() if self.cell_layer[c] in [1, 2] ] ) L1_L2_additional_edges = np.concatenate([e for e in L1_L2_additional_edges if len(e) > 0]) L1_L2_additional_edges = L1_L2_additional_edges[L1_L2_additional_edges[:, 1] > L1_L2_additional_edges[:, 0]] self.layer_triangle_topomesh["L1_L2"] = triangle_topomesh( triangles_from_adjacency_edges(np.concatenate([L1_L2_edges, L1_L2_additional_edges])), self.positions )
def layered_tetrahedra_topomesh_construction(layer_triangle_topomesh, positions, cell_layer, omega_criteria = {'distance':1.0,'wall_surface':2.0,'clique':10.0}, **kwargs): compute_topomesh_property(layer_triangle_topomesh,'length',1) compute_topomesh_property(layer_triangle_topomesh,'borders',2) compute_topomesh_property(layer_triangle_topomesh,'perimeter',2) if omega_criteria.has_key('wall_surface'): img_wall_surfaces = kwargs.get('wall_surfaces',None) img_volumes = kwargs.get('cell_volumes',dict(zip(positions.keys(),np.ones_like(positions.keys())))) assert layer_triangle_topomesh.has_wisp_property('wall_surface',1) or img_wall_surfaces is not None if not layer_triangle_topomesh.has_wisp_property('wall_surface',1): L1_L2_triangle_edge_vertices = np.array([np.sort([list(layer_triangle_topomesh.borders(1,e)) for e in layer_triangle_topomesh.borders(2,t)]) for t in layer_triangle_topomesh.wisps(2)]) L1_L2_triangle_edge_wall_surface = np.array([[-1. if tuple(e) not in img_wall_surfaces.keys() else img_wall_surfaces[tuple(e)]/np.power(img_volumes.values(e).mean(),2./3.) for e in t] for t in L1_L2_triangle_edge_vertices]) layer_triangle_topomesh.update_wisp_property('wall_surface',2,array_dict(L1_L2_triangle_edge_wall_surface.min(axis=1),list(layer_triangle_topomesh.wisps(2)))) layer_triangle_topomesh = layer_triangle_topomesh triangle_weights = np.zeros(layer_triangle_topomesh.nb_wisps(2)) if omega_criteria.has_key('distance'): triangle_weights += omega_criteria['distance']*np.exp(-np.power(layer_triangle_topomesh.wisp_property('length',1).values(layer_triangle_topomesh.wisp_property('borders',2).values()).max(axis=1)/15.0,1)) if omega_criteria.has_key('wall_surface'): triangle_weights += omega_criteria['wall_surface']*layer_triangle_topomesh.wisp_property('wall_surface',2).values() triangle_weights = array_dict(triangle_weights,list(layer_triangle_topomesh.wisps(2))) triangle_neighbor_edges = [np.concatenate([list(set(layer_triangle_topomesh.region_neighbors(1,e)))+[e] for e in layer_triangle_topomesh.borders(2,t)]) for t in layer_triangle_topomesh.wisps(2)] triangle_neighbor_edge_triangles = [np.concatenate([list(layer_triangle_topomesh.regions(1,n_e)) for n_e in n_edges]) for n_edges in triangle_neighbor_edges] triangle_tetrahedra_triangles = [np.unique(t)[nd.sum(np.ones_like(t),t,index=np.unique(t))>5] for t in triangle_neighbor_edge_triangles] if omega_criteria.has_key('clique'): triangle_neighbor_weights = array_dict([triangle_weights.values(t).min() - omega_criteria['clique']*(len(t)-4) for t in triangle_tetrahedra_triangles],list(layer_triangle_topomesh.wisps(2))) else: triangle_neighbor_weights = array_dict([triangle_weights.values(t).min() for t in triangle_tetrahedra_triangles],list(layer_triangle_topomesh.wisps(2))) triangle_tetrahedra_triangles = array_dict(triangle_tetrahedra_triangles,list(layer_triangle_topomesh.wisps(2))) tetrahedrization_triangles = np.array(list(layer_triangle_topomesh.wisps(2)))[np.array(map(len,triangle_tetrahedra_triangles))>=4] constructed_triangulation_topomesh = PropertyTopomesh(3) initial_triangle = np.array(list(layer_triangle_topomesh.wisps(2)))[tetrahedrization_triangles][np.argmax(triangle_neighbor_weights.values(tetrahedrization_triangles))] free_triangles = [initial_triangle] while len(free_triangles) > 0: fid_to_add = free_triangles.pop(0) print "--> Triangle",list(layer_triangle_topomesh.borders(2,fid_to_add))," : ",triangle_neighbor_weights[fid_to_add] triangle_vertex_edges = np.concatenate([list(set(layer_triangle_topomesh.regions(0,c)).difference(set(layer_triangle_topomesh.borders(2,fid_to_add)))) for c in layer_triangle_topomesh.borders(2,fid_to_add,2)]) triangle_vertex_edge_vertices = np.concatenate([c*np.ones(layer_triangle_topomesh.nb_regions(0,c)-2) for c in layer_triangle_topomesh.borders(2,fid_to_add,2)]) triangle_vertex_edge_neighbor_vertices = np.array([list(set(layer_triangle_topomesh.borders(1,e)).difference({v}))[0] for e,v in zip(triangle_vertex_edges,triangle_vertex_edge_vertices)]) candidate_tetra_vertices = np.unique(triangle_vertex_edge_neighbor_vertices)[nd.sum(np.ones_like(triangle_vertex_edge_neighbor_vertices),triangle_vertex_edge_neighbor_vertices,index=np.unique(triangle_vertex_edge_neighbor_vertices))==3] candidate_tetra_edges = np.array([triangle_vertex_edges[triangle_vertex_edge_neighbor_vertices==c] for c in candidate_tetra_vertices]) candidate_tetra_edge_triangles = [np.concatenate([list(set(layer_triangle_topomesh.regions(1,e)).difference({fid_to_add})) for e in candidate_edges]) for candidate_edges in candidate_tetra_edges] candidate_tetra_triangles = np.array([np.concatenate([[fid_to_add],np.unique(t)[nd.sum(np.ones_like(t),t,index=np.unique(t))==2]]) for t in candidate_tetra_edge_triangles]) if len(candidate_tetra_triangles)>0: candidate_tetra_free_triangles = np.array([np.sum([t in free_triangles for t in tetra_triangles]) for tetra_triangles in candidate_tetra_triangles]) candidate_tetra_triangle_weights = triangle_weights.values(candidate_tetra_triangles[:,1:]).min(axis=1) if (candidate_tetra_free_triangles == candidate_tetra_free_triangles.max()).sum() == 1: sorted_candidate_tetra_triangles = candidate_tetra_triangles[np.argsort(-candidate_tetra_free_triangles)] else: sorted_candidate_tetra_triangles = candidate_tetra_triangles[np.argsort(-candidate_tetra_triangle_weights)] for tetra_triangles in sorted_candidate_tetra_triangles: if np.all(np.array([0 if not constructed_triangulation_topomesh.has_wisp(2,t) else constructed_triangulation_topomesh.nb_regions(2,t) for t in tetra_triangles])<2): tetra_vertices = np.unique([list(layer_triangle_topomesh.borders(2,t,2)) for t in tetra_triangles]) tetra_edges = np.unique([list(layer_triangle_topomesh.borders(2,t)) for t in tetra_triangles]) if constructed_triangulation_topomesh.nb_wisps(3)!=1 or vq(np.sort([tetra_vertices]),np.sort([list(constructed_triangulation_topomesh.borders(3,t,3)) for t in constructed_triangulation_topomesh.wisps(3)]))[1][0]>0: if len(np.unique(cell_layer.values(tetra_vertices)))==2: #tetra_triangle_tetras = np.unique([list(constructed_triangulation_topomesh.regions(2,t)) for t in tetra_triangles if constructed_triangulation_topomesh.has_wisp(2,t)]) tetra_triangle_tetras = np.array(list(constructed_triangulation_topomesh.wisps(3))) if len(tetra_triangle_tetras)>0: tetra_triangle_tetra_edges = np.unique([list(constructed_triangulation_topomesh.borders(3,t,2)) for t in tetra_triangle_tetras]) tetra_triangle_points = positions.values(np.array([list(layer_triangle_topomesh.borders(2,t,2)) for t in tetra_triangles])) tetra_triangle_tetra_edge_points = positions.values(np.array([list(layer_triangle_topomesh.borders(1,e)) for e in tetra_triangle_tetra_edges])) tetra_triangle_intersection = np.ravel([intersecting_triangle(edge_points,tetra_triangle_points) for edge_points in tetra_triangle_tetra_edge_points]) tetra_triangle_edges = np.unique([list(layer_triangle_topomesh.borders(2,t)) for t in tetra_triangles]) tetra_triangle_tetra_triangles = np.unique([list(constructed_triangulation_topomesh.borders(3,t)) for t in tetra_triangle_tetras]) tetra_triangle_edge_points = positions.values(np.array([list(layer_triangle_topomesh.borders(1,e)) for e in tetra_triangle_edges])) tetra_triangle_tetra_triangle_points = positions.values(np.array([list(layer_triangle_topomesh.borders(2,t,2)) for t in tetra_triangle_tetra_triangles])) tetra_edge_intersection = np.ravel([intersecting_triangle(edge_points,tetra_triangle_tetra_triangle_points) for edge_points in tetra_triangle_edge_points]) tetra_triangle_intersection = np.concatenate([tetra_triangle_intersection,tetra_edge_intersection]) else: tetra_triangle_intersection = [False] if not np.any(tetra_triangle_intersection): tid = constructed_triangulation_topomesh.add_wisp(3) print " --> Tetrahedron",tid,tetra_vertices," : ", triangle_weights.values(tetra_triangles[1:]).min() for c in tetra_vertices: if not constructed_triangulation_topomesh.has_wisp(0,c): constructed_triangulation_topomesh.add_wisp(0,c) for e in tetra_edges: if not constructed_triangulation_topomesh.has_wisp(1,e): constructed_triangulation_topomesh.add_wisp(1,e) for c in layer_triangle_topomesh.borders(1,e): constructed_triangulation_topomesh.link(1,e,c) for t in tetra_triangles: if not constructed_triangulation_topomesh.has_wisp(2,t): constructed_triangulation_topomesh.add_wisp(2,t) for e in layer_triangle_topomesh.borders(2,t): constructed_triangulation_topomesh.link(2,t,e) constructed_triangulation_topomesh.link(3,tid,t) if constructed_triangulation_topomesh.nb_regions(2,t)<2 and len(np.unique(cell_layer.values(list(constructed_triangulation_topomesh.borders(2,t,2)))))==2: if not t in free_triangles: free_triangles.append(t) triangle_future_tetra_triangles = list(set(triangle_tetrahedra_triangles[t]).difference(set(constructed_triangulation_topomesh.wisps(2)).difference(set(free_triangles)))) if omega_criteria.has_key('clique'): triangle_neighbor_weights[t] = np.min(triangle_weights.values(triangle_future_tetra_triangles)) - omega_criteria['clique']*(len(triangle_future_tetra_triangles)-4) else: triangle_neighbor_weights[t] = np.min(triangle_weights.values(triangle_future_tetra_triangles)) # print free_triangles if len(free_triangles)>0: free_triangles = list(np.array(free_triangles)[np.argsort(-triangle_neighbor_weights.values(free_triangles))]) constructed_triangulation_topomesh.update_wisp_property('barycenter',0,array_dict(positions.values(list(constructed_triangulation_topomesh.wisps(0))),list(constructed_triangulation_topomesh.wisps(0)))) return constructed_triangulation_topomesh
vtx = list(expert_topomesh.wisps(0)) if 0 in vtx or 1 in vtx: # --- Initialise relabelling dictionary: relabel = {v: v for v in vtx} # --- Change label values for 0 & 1: for label in [0, 1]: mk = max(relabel.values()) relabel[label] = mk + 1 # --- Create a temporary expert topomesh for label edition: expert_positions = expert_topomesh.wisp_property('barycenter', 0) expert_positions = {relabel[k]: v for k, v in expert_positions.items()} tmp_expert_topomesh = vertex_topomesh(expert_positions) # --- Relabel all existing properties: for ppty in expert_topomesh.wisp_property_names(0): ppty_dict = array_dict(expert_topomesh.wisp_property( ppty, 0).values(vtx), keys=vtx) ppty_dict = {relabel[k]: v for k, v in ppty_dict.items()} tmp_expert_topomesh.update_wisp_property(ppty, 0, ppty_dict) try: assert tmp_expert_topomesh.has_wisp_property('layer', 0, True) except AssertionError: raise ValueError("Error during relabelling, please check!") else: expert_topomesh = tmp_expert_topomesh # -- Create a seed image from expertised seed positions: print "\n# - Creating seed image from EXPERT seed positions..." xp_seed_pos = expert_topomesh.wisp_property('barycenter', 0) xp_seed_pos = { k: v * microscope_orientation for k, v in xp_seed_pos.items()
def layer_triangle_topomesh_construction(layer_edge_topomesh, positions, omega_criteria = {'distance':1.0,'wall_surface':2.0,'clique':10.0}, **kwargs): compute_topomesh_property(layer_edge_topomesh,'length',1) edge_weights = np.zeros(layer_edge_topomesh.nb_wisps(1)) if omega_criteria.has_key('distance'): edge_weights += omega_criteria['distance']*np.exp(-np.power(layer_edge_topomesh.wisp_property('length',1).values()/15.0,1)) if omega_criteria.has_key('wall_surface'): img_wall_surfaces = kwargs.get('wall_surfaces',None) img_volumes = kwargs.get('cell_volumes',dict(zip(positions.keys(),np.ones_like(positions.keys())))) assert layer_edge_topomesh.has_wisp_property('wall_surface',1) or img_wall_surfaces is not None if not layer_edge_topomesh.has_wisp_property('wall_surface',1): layer_edge_vertices = np.sort([list(layer_edge_topomesh.borders(1,e)) for e in layer_edge_topomesh.wisps(1)]) layer_edge_wall_surface = np.array([img_wall_surfaces[tuple(e)]/np.power(img_volumes.values(e).mean(),2./3.) for e in layer_edge_vertices]) layer_edge_topomesh.update_wisp_property('wall_surface',1,array_dict(layer_edge_wall_surface,list(layer_edge_topomesh.wisps(1)))) edge_weights += omega_criteria['wall_surface']*layer_edge_topomesh.wisp_property('wall_surface',1).values() edge_weights = array_dict(edge_weights,list(layer_edge_topomesh.wisps(1))) edge_neighbor_vertices = [np.concatenate([list(set(layer_edge_topomesh.region_neighbors(0,c)))+[c] for c in layer_edge_topomesh.borders(1,e)]) for e in layer_edge_topomesh.wisps(1)] edge_neighbor_vertices_edges = [np.concatenate([list(layer_edge_topomesh.regions(0,n_v)) for n_v in n_vertices]) for n_vertices in edge_neighbor_vertices] edge_triangle_edges = [np.unique(e)[nd.sum(np.ones_like(e),e,index=np.unique(e))>3] for e in edge_neighbor_vertices_edges] if omega_criteria.has_key('clique'): edge_neighbor_weights = array_dict([edge_weights.values(e).min() - omega_criteria['clique']*(len(e)>3) for e in edge_triangle_edges],list(layer_edge_topomesh.wisps(1))) else: edge_neighbor_weights = array_dict([edge_weights.values(e).min() for e in edge_triangle_edges],list(layer_edge_topomesh.wisps(1))) edge_triangle_edges = array_dict(edge_triangle_edges,list(layer_edge_topomesh.wisps(1))) triangulation_edges = np.array(list(layer_edge_topomesh.wisps(1)))[np.array(map(len,edge_triangle_edges))>=3] layer_triangulation_topomesh = PropertyTopomesh(3) layer_triangulation_topomesh.add_wisp(3,1) initial_edge = np.array(list(layer_edge_topomesh.wisps(1)))[triangulation_edges][np.argmax(edge_neighbor_weights.values(triangulation_edges))] free_edges = [initial_edge] while len(free_edges) > 0: eid_to_add = free_edges.pop(0) print "--> Edge",list(layer_edge_topomesh.borders(1,eid_to_add))," : ",edge_neighbor_weights[eid_to_add] edge_vertex_edges = np.concatenate([list(set(layer_edge_topomesh.regions(0,c)).difference({eid_to_add})) for c in layer_edge_topomesh.borders(1,eid_to_add)]) edge_vertex_edge_vertices = np.concatenate([c*np.ones(layer_edge_topomesh.nb_regions(0,c)-1) for c in layer_edge_topomesh.borders(1,eid_to_add)]) edge_vertex_edge_neighbor_vertices = np.array([list(set(layer_edge_topomesh.borders(1,e)).difference({v}))[0] for e,v in zip(edge_vertex_edges,edge_vertex_edge_vertices)]) candidate_triangle_vertices = np.unique(edge_vertex_edge_neighbor_vertices)[nd.sum(np.ones_like(edge_vertex_edge_neighbor_vertices),edge_vertex_edge_neighbor_vertices,index=np.unique(edge_vertex_edge_neighbor_vertices))==2] candidate_triangle_edges = np.array([np.concatenate([[eid_to_add],edge_vertex_edges[edge_vertex_edge_neighbor_vertices==c]]) for c in candidate_triangle_vertices]) if len(candidate_triangle_edges)>0: candidate_triangle_free_edges = np.array([np.sum([e in free_edges for e in triangle_edges]) for triangle_edges in candidate_triangle_edges]) candidate_triangle_edge_weights = edge_weights.values(candidate_triangle_edges[:,1:]).min(axis=1) if (candidate_triangle_free_edges ==candidate_triangle_free_edges.max()).sum() == 1: sorted_candidate_triangle_edges = candidate_triangle_edges[np.argsort(-candidate_triangle_free_edges)] else: sorted_candidate_triangle_edges = candidate_triangle_edges[np.argsort(-candidate_triangle_edge_weights)] for triangle_edges in sorted_candidate_triangle_edges: if np.all(np.array([0 if not layer_triangulation_topomesh.has_wisp(1,e) else layer_triangulation_topomesh.nb_regions(1,e) for e in triangle_edges])<2): triangle_vertices = np.unique([list(layer_edge_topomesh.borders(1,e)) for e in triangle_edges]) if layer_triangulation_topomesh.nb_wisps(2)!=1 or vq(np.sort([triangle_vertices]),np.sort([list(layer_triangulation_topomesh.borders(2,t,2)) for t in layer_triangulation_topomesh.wisps(2)]))[1][0]>0: fid = layer_triangulation_topomesh.add_wisp(2) layer_triangulation_topomesh.link(3,1,fid) print " --> Triangle",fid,triangle_vertices," : ",edge_weights.values(triangle_edges[1:]).min() for c in triangle_vertices: if not layer_triangulation_topomesh.has_wisp(0,c): layer_triangulation_topomesh.add_wisp(0,c) for e in triangle_edges: if not layer_triangulation_topomesh.has_wisp(1,e): layer_triangulation_topomesh.add_wisp(1,e) for c in layer_edge_topomesh.borders(1,e): layer_triangulation_topomesh.link(1,e,c) layer_triangulation_topomesh.link(2,fid,e) if layer_triangulation_topomesh.nb_regions(1,e)<2: if not e in free_edges: free_edges.append(e) edge_future_triangle_edges = list(set(edge_triangle_edges[e]).difference(set(layer_triangulation_topomesh.wisps(1)).difference(set(free_edges)))) if omega_criteria.has_key('clique'): edge_neighbor_weights[e] = np.min(edge_weights.values(edge_future_triangle_edges)) - omega_criteria['clique']*(len(edge_future_triangle_edges)>3) else: edge_neighbor_weights[e] = np.min(edge_weights.values(edge_future_triangle_edges)) print free_edges if len(free_edges)>0: free_edges = list(np.array(free_edges)[np.argsort(-edge_neighbor_weights.values(free_edges))]) layer_triangulation_topomesh.update_wisp_property('barycenter',0,array_dict(positions.values(list(layer_triangulation_topomesh.wisps(0))),list(layer_triangulation_topomesh.wisps(0)))) return layer_triangulation_topomesh
def star_interface_topomesh(topomesh, inner_interfaces=True, verbose=False): from time import time triangle_edge_list = np.array([[1, 2],[0, 2],[0, 1]]) triangular_topomesh = PropertyTopomesh(3) triangle_vertex_positions = {} for v in topomesh.wisps(0): triangular_topomesh.add_wisp(0,v) triangle_vertex_positions[v] = topomesh.wisp_property('barycenter',0)[v] for e in topomesh.wisps(1): triangular_topomesh.add_wisp(1,e) for v in topomesh.borders(1,e): triangular_topomesh.link(1,e,v) for c in topomesh.wisps(3): triangular_topomesh.add_wisp(3,c) compute_topomesh_property(topomesh,'regions',2) compute_topomesh_property(topomesh,'edges',2) compute_topomesh_property(topomesh,'vertices',1) compute_topomesh_property(topomesh,'vertices',2) face_centers = {} face_triangles = {} start_time = time() print "--> Triangulating Interfaces" for interface in topomesh.wisps(2): if interface%100 == 0: interface_start_time = time() if topomesh.nb_borders(2,interface)>0: interface_cells = topomesh.wisp_property('regions',2)[interface] interface_edges = topomesh.wisp_property('vertices',1).values(topomesh.wisp_property('edges',2)[interface]) interface_vertices = np.unique(interface_edges) if (len(interface_vertices)>2) and (inner_interfaces or (len(interface_cells) == 1)): interface_positions = array_dict(topomesh.wisp_property('barycenter',0).values(interface_vertices),interface_vertices) interface_center = interface_positions.values().mean(axis=0) center_pid = triangular_topomesh.add_wisp(0) triangle_vertex_positions[center_pid] = interface_center face_centers[interface] = center_pid face_triangles[interface] = [] vertex_center_edges = {} for v in interface_vertices: eid = triangular_topomesh.add_wisp(1) triangular_topomesh.link(1,eid,v) triangular_topomesh.link(1,eid,center_pid) vertex_center_edges[v] = eid for e in topomesh.borders(2,interface): fid = triangular_topomesh.add_wisp(2) face_triangles[interface] += [fid] triangular_topomesh.link(2,fid,e) for v in topomesh.borders(1,e): triangular_topomesh.link(2,fid,vertex_center_edges[v]) for cid in interface_cells: triangular_topomesh.link(3,cid,fid) if verbose: if interface%100 == 0: interface_end_time = time() # print " --> Interface ",interface," / ",topomesh.nb_wisps(2),' ',interface_cells,' [',interface_end_time-interface_start_time,'s]' print " --> Interface ",interface," / ",topomesh.nb_wisps(2),' [',(interface_end_time-interface_start_time),'s]' end_time = time() # for property_name in topomesh.wisp_property_names(0): # try: # center_property = [topomesh.wisp_property(property_name,0).values(topomesh.wisp_property('vertices',2)[f]).mean(axis=0) for f in face_centers.keys()] # except: # center_property = [topomesh.wisp_property(property_name,0).values(topomesh.wisp_property('vertices',2)[f])[0] for f in face_centers.keys()] # vertex_property = array_dict(list(topomesh.wisp_property(property_name,0).values(list(topomesh.wisps(0))))+center_property,list(topomesh.wisps(0))+[face_centers[f] for f in face_centers.keys()]) # triangular_topomesh.update_wisp_property(property_name,0,vertex_property) for property_name in topomesh.wisp_property_names(2): triangle_faces = np.concatenate([[f for t in face_triangles[f]] for f in face_triangles.keys()]) triangle_keys = np.concatenate([face_triangles[f] for f in face_triangles.keys()]) triangle_property = array_dict(topomesh.wisp_property(property_name,2).values(triangle_faces),triangle_keys) triangular_topomesh.update_wisp_property(property_name,2,triangle_property) for property_name in topomesh.wisp_property_names(3): triangular_topomesh.update_wisp_property(property_name,3,topomesh.wisp_property(property_name,3)) print "--> Triangulating Interfaces [",end_time-start_time,"s]" triangular_topomesh.update_wisp_property('barycenter',degree=0,values=triangle_vertex_positions) return triangular_topomesh
membrane_img = imread(membrane_image_filename) mask_filename = image_dirname + "/" + nomenclature_names[ filename] + "/" + nomenclature_names[filename] + "_mask.inr.gz" mask_img = imread(mask_filename) membrane_img[mask_img == 0] = 0 # world.add(membrane_img,'membrane_image',colormap='invert_grey') #world['membrane_image']['intensity_range'] = (5000,30000) topomesh_file = image_dirname + "/" + nomenclature_names[ filename] + "/" + nomenclature_names[ filename] + "_nuclei_detection_topomesh_corrected.ply" topomesh = read_ply_property_topomesh(topomesh_file) positions = topomesh.wisp_property('barycenter', 0) positions = array_dict(microscope_orientation * positions.values(), positions.keys()) # Create a seed image fro the nuclei barycenters: seed_img = seed_image_from_points(membrane_img.shape, membrane_img.voxelsize, positions, background_label=0) # Add the "background seed": background_threshold = 2000. smooth_img_bck = linearfilter(membrane_img, param_str_2='-x 0 -y 0 -z 0 -sigma 3.0') background_img = (smooth_img_bck < background_threshold).astype(np.uint16) for it in xrange(10): background_img = morphology( background_img, param_str_2='-operation erosion -iterations 10')
def nuclei_image_topomesh(image_dict, reference_name='TagBFP', signal_names=['DIIV','CLV3'], compute_ratios=[True,False], microscope_orientation=1, radius_range=(0.8,1.4), threshold=1000, subsampling=4, surface_voxelsize=1, nuclei_sigma=2.0, compute_layer=True, surface_mode='image', compute_curvature=True, return_surface=False): """Compute a point cloud PropertyTopomesh with image nuclei. The function runs a nuclei detection on the reference channel of the image, and then computes the signal intensities from the other channels (ratiometric or not) for each detected point. Additionnally, it can estimate the first layer of cells and compute the curvature on the surface. Args: image_dict (dict): An SatialImage dictionary with channel names as keys. reference_name (str): The name of the channel containing nuclei marker. signal_names (list): A list of the channel names on which to quantify signal. compute_ratios (list): A list of booleans stating if signal is to be computed as channel intensity (False) or as a ratio between channel intensity and reference channel intensity (True) for each channel name in signal_names argument. microscope_orientation (int): 1 for an upright microscope, -1 for an inverted one, in order to estimate consistently the upper layer of cells. radius_range (tuple): A tuple of two lengths (in microns) corresponding to the typical size of nuclei to be detected in the image. threshold (int): A response intensity threshold for the detection, to eliminate weak local maxima of response intensity. subsampling (int): A downsampling factor to make the region growing part of the detection faster. nuclei_sigma (float): The standard deviation (in microns) of the gaussian kernel used to quantify the signals. compute_layer (bool): Whether to estimate the first layer of cells based on the point cloud geometry. compute_curvature (bool): Whether to estimate surface curvature on the epidermal layer of cells (compute_layer must be set to True) Returns: topomesh (:class:`openaela.mesh.PropertyTopomesh`): A point cloud structure with properties defined for each quantified signal, cell layer (if compute_layer argument is set to True) and mean and gaussian curvatures (if compute_curvature argument is set to true) """ try: assert isinstance(image_dict,dict) except: print "Image channels should be passed as a Python dictionary with channel names as keys" raise assert reference_name in image_dict.keys() assert np.all([s in image_dict.keys() for s in signal_names]) assert len(compute_ratios)==len(signal_names) reference_img = image_dict[reference_name] size = np.array(reference_img.shape) voxelsize = microscope_orientation*np.array(reference_img.voxelsize) positions = nuclei_detection(reference_img, threshold=threshold, radius_range=radius_range, subsampling=subsampling, microscope_orientation=1) signal_values = {} for signal_name, compute_ratio in zip(signal_names,compute_ratios): signal_img = image_dict[signal_name] ratio_img = reference_img if compute_ratio else np.ones_like(reference_img) signal_values[signal_name] = compute_fluorescence_ratios(ratio_img,signal_img,positions) positions = array_dict(positions) positions = array_dict(positions.values()*microscope_orientation,positions.keys()).to_dict() topomesh = vertex_topomesh(positions) for signal_name in signal_names: topomesh.update_wisp_property(signal_name,0,signal_values[signal_name]) # cell_layer, surface_topomesh = nuclei_layer(positions,reference_img,microscope_orientation=microscope_orientation,density_voxelsize=surface_voxelsize,return_topomesh=True) cell_layer, surface_topomesh = nuclei_layer(positions,reference_img,microscope_orientation=microscope_orientation,density_voxelsize=surface_voxelsize,surface_mode=surface_mode,return_topomesh=True) # cell_layer, surface_topomesh = nuclei_layer(positions,size,np.array(reference_img.voxelsize),return_topomesh=True) topomesh.update_wisp_property('layer',0,cell_layer) compute_curvature = False if compute_curvature: triangulation_topomesh = nuclei_topomesh_curvature(topomesh,surface_subdivision=0,return_topomesh=True) from copy import deepcopy topomesh._borders[1] = deepcopy(triangulation_topomesh._borders[1]) topomesh._regions[0] = deepcopy(triangulation_topomesh._regions[0]) for v in cell_layer.keys(): if not v in topomesh._regions[0]: topomesh._regions[0][v] = [] topomesh._borders[2] = deepcopy(triangulation_topomesh._borders[2]) topomesh._regions[1] = deepcopy(triangulation_topomesh._regions[1]) for t in topomesh.wisps(2): topomesh._regions[2][t] = [] topomesh.add_wisps(3,0) for t in topomesh.wisps(2): topomesh.link(3,0,t) if return_surface: return topomesh, surface_topomesh else: return topomesh
voxelsize) # ??? expert_coords = np.maximum(0, np.minimum(size - 1, expert_coords)).astype(np.uint16) expert_coords = tuple(np.transpose(expert_coords)) ## Mask application : expert_mask_value = mask_img[expert_coords] expert_cells_to_remove = expert_positions.keys()[expert_mask_value == 0] for c in expert_cells_to_remove: expert_topomesh.remove_wisp(0, c) for property_name in expert_topomesh.wisp_property_names(0): expert_topomesh.update_wisp_property( property_name, 0, array_dict(expert_topomesh.wisp_property(property_name, 0).values( list(expert_topomesh.wisps(0))), keys=list(expert_topomesh.wisps(0)))) # world.add(expert_topomesh,"expert_seed") # world["expert_seed"]["property_name_0"] = 'layer' # world["expert_seed_vertices"]["polydata_colormap"] = load_colormaps()['Greens'] # - Filter L1-corrected seed (ground truth): L1_expert_topomesh = deepcopy(expert_topomesh) L1_expert_cells = np.array(list(L1_expert_topomesh.wisps(0)))[ L1_expert_topomesh.wisp_property('layer', 0).values() == 1] non_L1_expert_cells = [ c for c in L1_expert_topomesh.wisps(0) if not c in L1_expert_cells ] for c in non_L1_expert_cells: L1_expert_topomesh.remove_wisp(0, c)