Exemple #1
0
    def adjacency_complex_optimization(
        self, n_iterations=1, omega_energies={"image": 10.0, "geometry": 0.1, "adjacency": 0.01}
    ):
        """Optimize the adjacency complex to match better the actual cell adjacencies in the tissue.

        The optimization is performed as an iterative energy minimization process of local topological transformations 
        (edge flips and triangle swaps) following a simulated annealing heuristic.

        Args:
            n_iterations (int): number of iterations (cycles of simulated annealing) to perform
            omega_energies (dict): weights of the different terms of the energy functional :
                • 'image' : energy measuring the difference between the adjacency complex simplices and the ones extracted from the image
                • 'geometry' : energy penalizing irregular tetrahedra in the adjacency complex
                • 'adjacency' : energy pulling the number of neighbors of each cell to an empirical optimal value according to its layer

        Updates:
            triangulation_topomesh (PropertyTopomesh) : the DracoMesh adjacency complex is set to this optimized complex.

        Returns:
            None
        """

        self.optimized_delaunay_topomesh = deepcopy(self.delaunay_topomesh)
        compute_tetrahedrization_geometrical_properties(self.optimized_delaunay_topomesh)
        tetrahedrization_topomesh_add_exterior(self.optimized_delaunay_topomesh)
        self.optimized_delaunay_topomesh = tetrahedrization_topomesh_topological_optimization(
            self.optimized_delaunay_topomesh,
            image_cell_vertex=self.image_cell_vertex,
            omega_energies=omega_energies,
            image_graph=self.image_graph,
            n_iterations=n_iterations,
        )
        tetrahedrization_topomesh_remove_exterior(self.optimized_delaunay_topomesh)
        clean_tetrahedrization(self.optimized_delaunay_topomesh, min_cell_neighbors=2)
        self.triangulation_topomesh = deepcopy(self.optimized_delaunay_topomesh)
Exemple #2
0
    def dual_reconstruction(self, reconstruction_triangulation=None, adjacency_complex_degree=3, cell_vertex_constraint=True, maximal_edge_length=None):
        """Compute the dual geometry of the DRACO adjacency complex as a 3D interface mesh.

        Several options are possible for the interface triangulation:
            - 'star' : a vertex is inserted at the center of the interface, creating star-arranged triangles
            - 'delaunay' : the interface polygon is triangulated using Delaunay (!!ASSUMES INTERFACE IS CONVEX!!)
            - 'split' : all the triangles are split into 4 new triangles with vertices inserted at the middle of the edges
            - 'remeshed' : an isotropic remeshing algorithm is performed on the whole mesh
            - 'regular' : optimize the quality of the triangles as much as possible (!!CELL SHAPES WON'T BE PRESERVED!!)
            - 'realistic' : optimize the quality of the triangles while keeping plausible cell shapes (STEM optimization)
            - 'projected' : project the exterior mesh vertices onto the actual object surface
            - 'flat' : flatten all cell interfaces by projecting vertices on the interface median plane (3D complex required)
            - 'straight' : straighten all cell boundaries by local laplacian operator (best for 2D complex)
            - 'exact' : ensure cell vertices are well preserved during all geometrical optimization processes
            !!IF "reconstruction_triangulation" IS SET AS EMPTY A POLYGONAL INTERFACE MESH WILL BE RETURNED!!

        Args:
            reconstruction_triangulation (list): parameters of the interface triangulation method :
                • initial tirangulation (mandatory) : 'star' or 'delaunay'
                • triangulation refinement (optional) : 'split' or 'remeshed'
                • geometrical optimization (optional, multiple choice) : 'regular', 'realistic', 'projected', 'flat', 'straight'

            adjacency_complex_degree (int): 2 or 3, whether the adjacency complex is made of single layer triangles or tetrahedra
            cell_vertex_constraint (bool): whether the cell corners should be constrained to their position in the image or not
            maximal_edge_length (float): in micrometers, the maximal length for the remeshing algorithm

        Returns:
            dual_reconstruction_topomesh (PropertyTopomesh): triangular mesh representing the cell geometry
        """
        
        if reconstruction_triangulation is not None:
            self.reconstruction_triangulation = reconstruction_triangulation

        self.mesh_image_surface()

        if adjacency_complex_degree == 3:
            tetrahedrization_topomesh_add_exterior(self.triangulation_topomesh)
        elif adjacency_complex_degree == 2:
            tetrahedrization_topomesh_remove_exterior(self.triangulation_topomesh)
            if not self.triangulation_topomesh.has_wisp(3,1):
                self.triangulation_topomesh.add_wisp(3,1)
                for t in self.triangulation_topomesh.wisps(2):
                    self.triangulation_topomesh.link(3,1,t)
            tetrahedrization_topomesh_add_exterior(self.triangulation_topomesh)
            if self.triangulation_topomesh.has_wisp(3,1):
                self.triangulation_topomesh.remove_wisp(3,1)

        self.dual_reconstruction_topomesh = tetrahedra_dual_triangular_topomesh(self.triangulation_topomesh,triangular=self.reconstruction_triangulation,image_cell_vertex=self.image_cell_vertex, voronoi=True, vertex_motion=cell_vertex_constraint, surface_topomesh=self.surface_topomesh, maximal_length=maximal_edge_length)
        
        if adjacency_complex_degree == 3:
            tetrahedrization_topomesh_remove_exterior(self.triangulation_topomesh)
        
        return self.dual_reconstruction_topomesh
Exemple #3
0
def test_tetrahedrization_optimization():

    topomesh = octahedron_tetrahedra()

    compute_tetrahedrization_topological_properties(topomesh)
    compute_tetrahedrization_geometrical_properties(topomesh)

    tetrahedrization_topomesh_add_exterior(topomesh)

    target_tetrahedra = []
    target_tetrahedra += [(2, 3, 5, 6)]
    target_tetrahedra += [(3, 4, 5, 6)]
    target_tetrahedra += [(2, 3, 5, 7)]
    target_tetrahedra += [(3, 4, 5, 7)]

    target_tetrahedra += [(1, 2, 3, 6)]
    target_tetrahedra += [(1, 3, 4, 6)]
    target_tetrahedra += [(1, 4, 5, 6)]
    target_tetrahedra += [(1, 2, 5, 6)]

    target_tetrahedra += [(1, 2, 3, 7)]
    target_tetrahedra += [(1, 3, 4, 7)]
    target_tetrahedra += [(1, 4, 5, 7)]
    target_tetrahedra += [(1, 2, 5, 7)]

    target_tetrahedra = dict(zip(target_tetrahedra, np.zeros((4, 3))))

    kwargs = {}
    kwargs['simulated_annealing_initial_temperature'] = 0.1
    kwargs['simulated_annealing_lambda'] = 0.9
    kwargs['simulated_annealing_minimal_temperature'] = 0.09
    kwargs['n_iterations'] = 1

    topomesh = tetrahedrization_topomesh_topological_optimization(
        topomesh,
        image_cell_vertex=target_tetrahedra,
        omega_energies=dict(image=1.0),
        **kwargs)
    tetrahedrization_topomesh_remove_exterior(topomesh)

    assert topomesh.nb_wisps(3) == 4

    for t in topomesh.wisps(3):
        print t, list(topomesh.borders(3, t, 3))

    optimized_tetras = np.sort(
        [list(topomesh.borders(3, t, 3)) for t in topomesh.wisps(3)])
    target_tetras = np.sort(target_tetrahedra.keys())
    target_tetras = target_tetras[target_tetras[:, 0] != 1]

    assert jaccard_index(optimized_tetras, target_tetras) == 1.0
def test_tetrahedrization_optimization():

    topomesh = octahedron_tetrahedra()

    compute_tetrahedrization_topological_properties(topomesh)
    compute_tetrahedrization_geometrical_properties(topomesh)

    tetrahedrization_topomesh_add_exterior(topomesh)

    target_tetrahedra = []
    target_tetrahedra += [(2,3,5,6)]
    target_tetrahedra += [(3,4,5,6)]
    target_tetrahedra += [(2,3,5,7)]
    target_tetrahedra += [(3,4,5,7)]

    target_tetrahedra += [(1,2,3,6)]
    target_tetrahedra += [(1,3,4,6)]
    target_tetrahedra += [(1,4,5,6)]
    target_tetrahedra += [(1,2,5,6)]

    target_tetrahedra += [(1,2,3,7)]
    target_tetrahedra += [(1,3,4,7)]
    target_tetrahedra += [(1,4,5,7)]
    target_tetrahedra += [(1,2,5,7)]


    target_tetrahedra = dict(zip(target_tetrahedra,np.zeros((4,3))))

    kwargs = {}
    kwargs['simulated_annealing_initial_temperature'] = 0.1
    kwargs['simulated_annealing_lambda'] =  0.9
    kwargs['simulated_annealing_minimal_temperature'] = 0.09
    kwargs['n_iterations'] = 1

    topomesh = tetrahedrization_topomesh_topological_optimization(topomesh,image_cell_vertex=target_tetrahedra,omega_energies=dict(image=1.0),**kwargs)
    tetrahedrization_topomesh_remove_exterior(topomesh)

    assert topomesh.nb_wisps(3) == 4

    for t in topomesh.wisps(3):
        print t, list(topomesh.borders(3,t,3))

    optimized_tetras = np.sort([list(topomesh.borders(3,t,3)) for t in topomesh.wisps(3)])
    target_tetras = np.sort(target_tetrahedra.keys())
    target_tetras = target_tetras[target_tetras[:,0] != 1]

    assert jaccard_index(optimized_tetras,target_tetras) == 1.0