コード例 #1
0
    print "\n# - Seeded watershed using seed EXPERT seed positions..."
    smooth_img = linear_filtering(img,
                                  std_dev=std_dev,
                                  method='gaussian_smoothing')
    seg_im = segmentation(smooth_img, seed_img)
    # Use largest bounding box to determine background value:
    background = get_background_value(seg_im, microscope_orientation)
    print "Detected background value:", background
    # world.add(seg_im,"seg_image", colormap="glasbey", alphamap="constant",voxelsize=microscope_orientation*voxelsize, bg_id=background)

    # -- Create a vertex_topomesh from detected cell positions:
    print "\n# - Extracting 'barycenter' & 'L1' properties from segmented image..."
    # --- Compute 'L1' and 'barycenter' properties using 'graph_from_image'
    img_graph = graph_from_image(
        seg_im,
        background=background,
        spatio_temporal_properties=['L1', 'barycenter'],
        ignore_cells_at_stack_margins=True)
    print img_graph.nb_vertices(), " cells detected"
    print "\n# - Creating a vertex_topomesh..."
    vtx = list(img_graph.vertices())
    vtx2labels = img_graph.vertex_property('labels')
    # --- Get cell barycenters positions and L1 cells:
    bary = img_graph.vertex_property('barycenter')
    in_L1 = img_graph.vertex_property('L1')
    # --- Create a topomesh using detected cell barycenters:
    label_positions = {
        l: bary[v] * microscope_orientation
        for v, l in vtx2labels.items()
    }
    detected_topomesh = vertex_topomesh(label_positions)
コード例 #2
0
 nb_connectec_comp = len(np.unique(con_img.get_array()))
 print nb_connectec_comp, "seeds detected!"
 if nb_connectec_comp <= 3:
     print "Not enough seeds, aborting!"
     continue
 # world.add(con_img, 'labelled_seeds', voxelsize=vxs)
 del ext_img
 print " --> Seeded watershed..."
 seg_im = segmentation(img,
                       con_img,
                       method='seeded_watershed')
 # - Performs topomesh creation from detected seeds:
 print " --> Analysing segmented image...",
 img_graph = graph_from_image(
     seg_im,
     background=1,
     spatio_temporal_properties=['barycenter', 'L1'],
     ignore_cells_at_stack_margins=False)
 print img_graph.nb_vertices(
 ), "seeds extracted by 'graph_from_image'!"
 # -- Create a topomesh from 'seed_positions':
 print " --> Topomesh creation..."
 seed_positions = {
     v: img_graph.vertex_property('barycenter')[v] *
     microscope_orientation
     for v in img_graph.vertices()
 }
 detected_topomesh = vertex_topomesh(seed_positions)
 # -- Detect L1 using 'nuclei_layer':
 oriented_seeds = {
     k: np.array([1., 1., -1.]) * v
コード例 #3
0
ファイル: draco.py プロジェクト: VirtualPlants/draco_stem
    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
            )
コード例 #4
0
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
コード例 #5
0
def evaluate_topomesh_quality(topomesh,quality_criteria=["Mesh Complexity","Triangle Area Deviation","Triangle Eccentricity","Cell Volume Error","Vertex Distance","Cell Convexity","Epidermis Cell Angle","Vertex Valence","Cell 2 Adjacency"],image=None,image_cell_vertex=None,image_labels=None,image_cell_volumes=None,**kwargs):
    """
    """

    quality_data = {}

    if "Mesh Complexity" in quality_criteria:
        start_time = time()
        print "--> Computing mesh complexity"
        quality_data["Mesh Complexity"] = np.minimum(1.0,(152.*topomesh.nb_wisps(3))/np.sum([len(list(topomesh.border_neighbors(3,c))) for c in topomesh.wisps(3)]))
        end_time = time()
        print "<-- Computing mesh complexity          [",end_time-start_time,"s]"

    compute_topomesh_property(topomesh,'length',degree=1)

    triangular = kwargs.get('triangular',True)
    display = kwargs.get('display',False)

    if triangular:
        compute_topomesh_triangle_properties(topomesh)
        compute_topomesh_property(topomesh,'normal',degree=2)
        compute_topomesh_property(topomesh,'angles',degree=2)

    if "Triangle Area Deviation" in quality_criteria:
        start_time = time()
        print "--> Computing triangle area deviation"
        # area_deviation = np.nanmean(np.abs(topomesh.wisp_property('area',degree=2).values()-np.nanmean(topomesh.wisp_property('area',degree=2).values())))/np.nanmean(topomesh.wisp_property('area',degree=2).values())
        area_deviation = np.nanstd(topomesh.wisp_property('area',degree=2).values())/np.nanmean(topomesh.wisp_property('area',degree=2).values())
        # quality_data["Triangle Area Deviation"] = np.minimum(1.0,1.0-area_deviation/np.sqrt(2))
        # quality_data["Triangle Area Deviation"] = np.minimum(1.0,1.0-area_deviation/2.)
        quality_data["Triangle Area Deviation"] = np.minimum(1.0,np.sqrt(2)-area_deviation/np.sqrt(2))
        end_time = time()
        print "<-- Computing triangle area deviation  [",end_time-start_time,"s]"

    if "Triangle Eccentricity" in quality_criteria:
        start_time = time()
        print "--> Computing triangle eccentricity"
        quality_data["Triangle Eccentricity"] = 1.-2.*np.nanmean(topomesh.wisp_property('eccentricity',degree=2).values())
        end_time = time()
        print "<-- Computing triangle eccentricity    [",end_time-start_time,"s]"

    compute_topomesh_property(topomesh,'borders',degree=3)
    compute_topomesh_property(topomesh,'borders',degree=2)
    compute_topomesh_property(topomesh,'borders',degree=1)

    compute_topomesh_property(topomesh,'vertices',degree=3)
    compute_topomesh_property(topomesh,'vertices',degree=2)

    compute_topomesh_property(topomesh,'barycenter',degree=3)
    compute_topomesh_property(topomesh,'barycenter',degree=2)
    compute_topomesh_property(topomesh,'barycenter',degree=1)

    compute_topomesh_property(topomesh,'triangles',degree=0)

    compute_topomesh_property(topomesh,'cells',degree=0)
    compute_topomesh_property(topomesh,'cells',degree=1)
    compute_topomesh_property(topomesh,'cells',degree=2)

    compute_topomesh_property(topomesh,'epidermis',degree=0)
    compute_topomesh_property(topomesh,'epidermis',degree=1)
    compute_topomesh_property(topomesh,'epidermis',degree=3)


    if "Cell Volume Error" in quality_criteria or "Cell Convexity" in quality_criteria:
        compute_topomesh_property(topomesh,'volume',degree=3)
        compute_topomesh_property(topomesh,'convexhull_volume',degree=3)
    
    img_graph = kwargs.get('image_graph',None)

    if "Cell Volume Error" in quality_criteria:
        start_time = time()
        print "--> Computing cell volume error"

        from vplants.tissue_analysis.temporal_graph_from_image   import graph_from_image
        if (image_cell_volumes == None) or (image_labels == None) or (image_cell_vertex == None):
            img_graph = graph_from_image(image, spatio_temporal_properties=['volume','barycenter'],background=0,ignore_cells_at_stack_margins = False,property_as_real=True)
            image_labels = np.array(list(img_graph.vertices()))
            image_cell_volumes = np.array([img_graph.vertex_property('volume')[v] for v in image_labels])
        else:
            img_graph = None

        img_volumes = array_dict(image_cell_volumes,image_labels)

        if triangular:
            volume_error = array_dict([(c,(topomesh.wisp_property('volume',degree=3)[c] - img_volumes[c])/img_volumes[c]) for c in topomesh.wisps(3)])
        else:
            volume_error = array_dict([(c,(topomesh.wisp_property('convexhull_volume',degree=3)[c] - img_volumes[c])/img_volumes[c]) for c in topomesh.wisps(3)])


        quality_data["Cell Volume Error"] = np.maximum(1.-abs(volume_error.values()).mean(),0.0)
        end_time = time()
        print "<-- Computing cell volume error        [",end_time-start_time,"s]"

    if "Image Accuracy" in quality_criteria:
        start_time = time()
        print "--> Computing image accuracy"

        from openalea.mesh.utils.image_tools import compute_topomesh_image

        topomesh_img = compute_topomesh_image(topomesh,image)

        cells_img = deepcopy(image)
        for c in set(np.unique(image)).difference(set(topomesh.wisps(3))):
            cells_img[image==c] = 1

        true_positives = ((cells_img != 1)&(cells_img == topomesh_img)).sum()
        false_positives = ((cells_img == 1) & (topomesh_img != 1)).sum() + ((cells_img != 1)&(topomesh_img != 1)&(cells_img != topomesh_img)).sum()
        false_negatives = ((cells_img != 1) & (topomesh_img == 1)).sum() + ((cells_img != 1)&(topomesh_img != 1)&(cells_img != topomesh_img)).sum()
        true_negatives = ((cells_img == 1)&(cells_img == topomesh_img)).sum()

        estimators = {}
        estimators['Precision'] = float(true_positives/float(true_positives+false_positives))
        estimators['Recall'] = float(true_positives/float(true_positives+false_negatives))
        estimators['Dice'] = float(2*true_positives/float(2*true_positives+false_positives+false_negatives))
        estimators['Jaccard'] = float(true_positives/float(true_positives+false_positives+false_negatives))
        estimators['Accuracy'] = float(true_positives+true_negatives)/float(true_positives+true_negatives+false_positives+false_negatives)
        estimators['Identity'] = float((cells_img == topomesh_img).sum())/np.prod(cells_img.shape)
        print estimators

        quality_data["Image Accuracy"] = estimators['Dice']

        end_time = time()
        print "<-- Computing image accuracy           [",end_time-start_time,"s]"

    vertex_cell_neighbours = topomesh.wisp_property('cells',degree=0)

    vertex_cell_degree = np.array(map(len,vertex_cell_neighbours.values()))

    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: 
                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):
            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 = np.unique(mesh_cell_vertex.values())
    mesh_cell_vertices = topomesh.wisp_property('barycenter',degree=0).values(cell_vertex)  

    if "Vertex Distance" in quality_criteria:
        start_time = time()
        print "--> Computing vertex distance"
        if image_cell_vertex is None:
            image_cell_vertex = cell_vertex_extraction(image,hollow_out=False,verbose=False)
            if img_graph is None:
                img_graph = graph_from_image(image, spatio_temporal_properties=['volume','barycenter'],background=0,ignore_cells_at_stack_margins = False,property_as_real=True)
            img_edges = np.array([img_graph.edge_vertices(e) for e in img_graph.edges()])

            tetra_edge_index_list = np.array([[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]])
            img_vertex_edges = np.concatenate(np.sort(image_cell_vertex.keys())[:,tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges,img_edges)[1] > 0).reshape(len(image_cell_vertex),6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(vertex_edge_matching==0)[0]]

            image_cell_vertex = array_dict(np.array([image_cell_vertex[tuple(vertex)] for vertex in img_cell_vertex]),np.sort(img_cell_vertex))
        else:
            image_cell_vertex = deepcopy(image_cell_vertex)
        # for v in image_cell_vertex.keys():
        #     image_cell_vertex[v] = image_cell_vertex[v]*np.array(image.resolution)
    
        image_cell_vertices = np.array(image_cell_vertex.values())
        print mesh_cell_vertices[np.where(1-np.isnan(mesh_cell_vertices)[:,0])]*image.resolution
        print image_cell_vertices*image.resolution
        vertex_distances_mesh = array_dict(vq(mesh_cell_vertices[np.where(1-np.isnan(mesh_cell_vertices)[:,0])]*image.resolution,image_cell_vertices*image.resolution)[1],cell_vertex)
        vertex_distances_image = vq(image_cell_vertices[np.where(1-np.isnan(image_cell_vertices)[:,0])],mesh_cell_vertices)[1]

        # quality_data["Vertex Distance"] = np.sqrt(3)/(np.maximum(np.sqrt(3),vertex_distances_image.mean()))
        quality_data["Vertex Distance"] = (0.25*np.sqrt(3))/(np.maximum((0.25*np.sqrt(3)),vertex_distances_image.mean()))
        end_time = time()
        print "<-- Computing vertex distance          [",end_time-start_time,"s]"


    if "Cell Convexity" in quality_criteria:
        start_time = time()
        print "--> Computing cell convexity"
       
        # quality_data["Cell Convexity"] = (topomesh.wisp_property('volume',degree=3).values()/topomesh.wisp_property('convexhull_volume',degree=3).values()).mean()
        quality_data["Cell Convexity"] = 1 - (((topomesh.wisp_property('convexhull_volume',3).values() - topomesh.wisp_property('volume',3).values()).mean())/topomesh.wisp_property('volume',3).values().mean())
        end_time = time()
        print "<-- Computing cell convexity           [",end_time-start_time,"s]"


    if "Epidermis Cell Angle" in quality_criteria:
        start_time = time()
        print "--> Computing epidermis cell angle"
        epidermis_vertex_cell_angles=np.array([])
        epidermis_vertex_angles = array_dict()
        angle_keys = np.concatenate([np.concatenate([[(t,v)] for v in topomesh.wisp_property('vertices',2)[t]],axis=0) for t in topomesh.wisps(2)],axis=0)
        angle_dict = dict([(tuple(k),0.) for k in angle_keys])

        for v in cell_vertex:
            if topomesh.wisp_property('epidermis',0)[v]:
                vertex_triangles = np.array([t for t in topomesh.wisp_property('triangles',0)[v] if topomesh.wisp_property('epidermis',2)[t]])

                vertex_triangle_cells = np.concatenate(topomesh.wisp_property('cells',degree=2).values(vertex_triangles))
                vertex_cells = np.unique(vertex_triangle_cells)

                vertex_triangle_cell_directions = topomesh.wisp_property('barycenter',2).values(vertex_triangles) - topomesh.wisp_property('barycenter',3).values(vertex_triangle_cells)
                vertex_triangle_normals = topomesh.wisp_property('normal',2).values(vertex_triangles)
                reversed_normals = np.where(np.einsum('ij,ij->i',vertex_triangle_normals,vertex_triangle_cell_directions) < 0)[0]
                vertex_triangle_normals[reversed_normals] = -vertex_triangle_normals[reversed_normals]
                vertex_normal = np.mean(vertex_triangle_normals,axis=0)
                vertex_normal = vertex_normal/np.linalg.norm(vertex_normal)

                triangle_vertices = topomesh.wisp_property('vertices',degree=2).values(vertex_triangles)
                triangle_positions = topomesh.wisp_property('barycenter',degree=0).values(triangle_vertices)

                triangle_proj_vectors = triangle_positions - topomesh.wisp_property('barycenter',degree=0)[v]
                triangle_proj_dot = np.einsum('...ij,...j->...i',triangle_proj_vectors,vertex_normal)
                triangle_proj_vectors = -triangle_proj_dot[...,np.newaxis]*vertex_normal

                triangle_proj_positions = triangle_positions + triangle_proj_vectors

                edge_index_list = np.array([[1, 2],[0, 1],[0, 2]])

                triangle_edge_positions = triangle_proj_positions[:,edge_index_list]
                triangle_edge_vectors = triangle_edge_positions[:,:,1] - triangle_edge_positions[:,:,0]

                triangle_edge_lengths = np.linalg.norm(triangle_edge_vectors,axis=2)

                triangle_cosines = np.zeros_like(triangle_edge_lengths,np.float32)
                triangle_cosines[:,0] = (triangle_edge_lengths[:,1]**2+triangle_edge_lengths[:,2]**2-triangle_edge_lengths[:,0]**2)/(2.0*triangle_edge_lengths[:,1]*triangle_edge_lengths[:,2])
                triangle_cosines[:,2] = (triangle_edge_lengths[:,2]**2+triangle_edge_lengths[:,0]**2-triangle_edge_lengths[:,1]**2)/(2.0*triangle_edge_lengths[:,2]*triangle_edge_lengths[:,0])
                triangle_cosines[:,1] = (triangle_edge_lengths[:,0]**2+triangle_edge_lengths[:,1]**2-triangle_edge_lengths[:,2]**2)/(2.0*triangle_edge_lengths[:,0]*triangle_edge_lengths[:,1])
                triangle_angles = 180.*np.arccos(triangle_cosines)/np.pi

                vertex_triangle_angles = triangle_angles[np.where(triangle_vertices==v)]

                vertex_cell_angles = array_dict(nd.sum(vertex_triangle_angles,vertex_triangle_cells,index=vertex_cells),vertex_cells)

                for t,c in zip(vertex_triangles,vertex_triangle_cells):
                    angle_dict[(t,v)] = vertex_cell_angles[c]
                
                epidermis_vertex_angles[v] = np.sum(vertex_cell_angles.values())
                if abs(epidermis_vertex_angles[v]-360)<10:
                    epidermis_vertex_cell_angles = np.concatenate([epidermis_vertex_cell_angles,vertex_cell_angles.values()])


        # quality_data["Epidermis Cell Angle"] = 1.0 - ((epidermis_vertex_cell_angles>180).sum()+(epidermis_vertex_cell_angles<90).sum())/(float(epidermis_vertex_cell_angles.shape[0]))
        
        quality_data["Epidermis Cell Angle"] = 1 - (np.sum(1 - np.exp(-np.power(np.maximum(100-epidermis_vertex_cell_angles,0.0)/20.,2.0))) + np.sum(1 - np.exp(-np.power(np.maximum(epidermis_vertex_cell_angles-170,0.0)/20.,2.0))))/(float(epidermis_vertex_cell_angles.shape[0]))
        # np.sqrt(np.sum(np.power(np.maximum(90-epidermis_vertex_cell_angles,0.0)/30.,2.0))) + np.sum(np.maximum(epidermis_vertex_cell_angles-180,0.0)/30.)
        # quality_data["Epidermis Cell Angle"] = np.minimum(1.0,3-np.sqrt(np.power(epidermis_vertex_cell_angles-120.,2.0).mean())/30.)
        # quality_data["Epidermis Cell Angle"] = np.minimum(1.0,1.0-np.sqrt(np.power(epidermis_vertex_cell_angles-120.,2.0).mean())/120.)
        # quality_data["Epidermis Cell Angle"] = 1.0-np.power(np.power(np.abs(epidermis_vertex_cell_angles-120.),1.0).mean(),1.0)/120.

        end_time = time()
        print "<-- Computing epidermis cell angle     [",end_time-start_time,"s]"


    if "Vertex Valence" in quality_criteria:
        start_time = time()
        print "--> Computing vertex degree"
        compute_topomesh_property(topomesh,'region_neighbors',degree=0)
        compute_topomesh_property(topomesh,'border_neighbors',degree=3)

        # interface_vertices = np.array(list(topomesh.wisps(0)))[np.where((np.array(map(len,topomesh.wisp_property('cells',0).values())) == 1) 
        #                                                          | ((np.array(map(len,topomesh.wisp_property('cells',0).values())) == 2) 
        #                                                           & (1- topomesh.wisp_property('epidermis',0).values())))]
        # interface_vertices_degree = np.array(map(len,topomesh.wisp_property('neighbors',0).values(interface_vertices)))

        target_neighborhood = array_dict((np.array(map(len,topomesh.wisp_property('cells',0).values())) + topomesh.wisp_property('epidermis',0).values())*3,list(topomesh.wisps(0)))
        vertices_neighborhood = array_dict(map(len,topomesh.wisp_property('neighbors',0).values()),list(topomesh.wisps(0)))
        
        interface_vertices = target_neighborhood.keys_where("==6")        
        # np.power(np.power(target_neighborhood.values(interface_vertices)-vertices_neighborhood.values(interface_vertices),2.0).mean(),0.5)/6.0

        quality_data["Vertex Valence"] = np.minimum(1.0,1.0-np.abs(target_neighborhood.values(interface_vertices)-vertices_neighborhood.values(interface_vertices)).mean()/6.0)
        # quality_data["Vertex Valence"] = np.minimum(1.0,1.0-np.nanmean(np.abs(interface_vertices_degree-6.0)))
        # quality_data["Vertex Valence"] = np.minimum(1.0,1.0-np.power(interface_vertices_degree-6.0,2.0).mean()/6.0)
        end_time = time()
        print "<-- Computing vertex degree            [",end_time-start_time,"s]"


    if "Cell 4 Adjacency" in quality_criteria:
        start_time = time()
        print "--> Computing cell adjacency"
        if image_cell_vertex==None:
            image_cell_vertex = cell_vertex_extraction(img,hollow_out=False,verbose=False)
            if img_graph == None:
                img_graph = graph_from_image(img, spatio_temporal_properties=['volume','barycenter'],background=0,ignore_cells_at_stack_margins = False,property_as_real=False,min_contact_surface=0.5)
            img_edges = np.array([img_graph.edge_vertices(e) for e in img_graph.edges()])

            tetra_edge_index_list = np.array([[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]])
            img_vertex_edges = np.concatenate(np.sort(image_cell_vertex.keys())[:,tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges,img_edges)[1] > 0).reshape(len(image_cell_vertex),6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(vertex_edge_matching==0)[0]]

            image_cell_vertex = array_dict(np.array([image_cell_vertex[tuple(vertex)] for vertex in img_cell_vertex]),np.sort(img_cell_vertex))


        cell_vertex_VP = (vq(np.sort(array_dict(mesh_cell_vertex).keys()),np.sort(array_dict(image_cell_vertex).keys()))[1]==0).sum()
        cell_vertex_FP = (vq(np.sort(array_dict(mesh_cell_vertex).keys()),np.sort(array_dict(image_cell_vertex).keys()))[1]>0).sum()
        cell_vertex_FN = (vq(np.sort(array_dict(image_cell_vertex).keys()),np.sort(array_dict(mesh_cell_vertex).keys()))[1]>0).sum()
        cell_vertex_jaccard = cell_vertex_VP/float(cell_vertex_VP+cell_vertex_FP+cell_vertex_FN)
        cell_vertex_dice = 2*cell_vertex_VP/float(2*cell_vertex_VP+cell_vertex_FP+cell_vertex_FN)


        quality_data["Cell 4 Adjacency"] = cell_vertex_jaccard
        end_time = time()
        print "<-- Computing cell adjacency           [",end_time-start_time,"s]"

    if "Cell 2 Adjacency" in quality_criteria:
        start_time = time()
        print "--> Computing cell adjacency"

        tetra_edge_index_list = np.array([[0,1],[0,2],[0,3],[1,2],[1,3],[2,3]])

        if image_cell_vertex==None:
            image_cell_vertex = cell_vertex_extraction(img,hollow_out=False,verbose=False)
            if img_graph == None:
                img_graph = graph_from_image(img, spatio_temporal_properties=['volume','barycenter'],background=0,ignore_cells_at_stack_margins = False,property_as_real=False,min_contact_surface=0.5)
            img_edges = np.array([img_graph.edge_vertices(e) for e in img_graph.edges()])

            img_vertex_edges = np.concatenate(np.sort(image_cell_vertex.keys())[:,tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges,img_edges)[1] > 0).reshape(len(image_cell_vertex),6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(vertex_edge_matching==0)[0]]

            image_cell_vertex = array_dict(np.array([image_cell_vertex[tuple(vertex)] for vertex in img_cell_vertex]),np.sort(img_cell_vertex))


        from vplants.meshing.array_tools import array_unique

        mesh_cell_edges = array_unique(np.concatenate(np.sort(array_dict(mesh_cell_vertex).keys())[:,tetra_edge_index_list]))
        image_cell_edges = array_unique(np.concatenate(np.sort(array_dict(image_cell_vertex).keys())[:,tetra_edge_index_list]))

        from vplants.meshing.evaluation_tools import jaccard_index

        cell_edge_jaccard = jaccard_index(image_cell_edges,mesh_cell_edges)

        quality_data["Cell 2 Adjacency"] = cell_edge_jaccard
        end_time = time()
        print "<-- Computing cell adjacency           [",end_time-start_time,"s]"

    if "Cell Cliques" in quality_criteria:

        vertex_cells = np.array([len(list(topomesh.regions(0,v,3))) for v in topomesh.wisps(0)])
        vertex_epidermis = topomesh.wisp_property('epidermis',degree=0).values()

        cell_vertices = ((vertex_cells>=3)*(vertex_epidermis)+(vertex_cells>=4)*(True-vertex_epidermis)).sum()
        clique_cell_vertices = ((vertex_cells>3)*(vertex_epidermis)+(vertex_cells>4)*(True-vertex_epidermis)).sum()

        quality_data["Cell Cliques"] = 1.0 - float(clique_cell_vertices)/float(cell_vertices)


    print quality_data

    # if display:
    #     spider_figure = plt.figure(kwargs.get('figure_title',"Topomesh Quality"))
    #     spider_figure.clf()
    #     spider_data = np.array([quality_data[c] for c in quality_criteria])
    #     spider_fields= quality_criteria
    #     # spider_targets = [0.8,0.7,0.8,0.8,0.9,0.8,0.7]
    #     spider_targets = 0.8 * np.ones_like(quality_criteria,float)
    #     spider_plot(spider_figure,spider_data,color1=np.array([0.3,0.6,1.]),color2=np.array([1.,0.,0.]),xlabels=spider_fields,ytargets=spider_targets,n_points=100*len(quality_criteria),linewidth=2,smooth_factor=0.0,spline_order=1)
    #     plt.show(block=False)

    return quality_data
コード例 #6
0
def evaluate_topomesh_quality(topomesh,
                              quality_criteria=[
                                  "Mesh Complexity", "Triangle Area Deviation",
                                  "Triangle Eccentricity", "Cell Volume Error",
                                  "Vertex Distance", "Cell Convexity",
                                  "Epidermis Cell Angle", "Vertex Valence",
                                  "Cell 2 Adjacency"
                              ],
                              image=None,
                              image_cell_vertex=None,
                              image_labels=None,
                              image_cell_volumes=None,
                              **kwargs):
    """
    """

    quality_data = {}

    if "Mesh Complexity" in quality_criteria:
        start_time = time()
        print "--> Computing mesh complexity"
        quality_data["Mesh Complexity"] = np.minimum(
            1.0, (152. * topomesh.nb_wisps(3)) / np.sum([
                len(list(topomesh.border_neighbors(3, c)))
                for c in topomesh.wisps(3)
            ]))
        end_time = time()
        print "<-- Computing mesh complexity          [", end_time - start_time, "s]"

    compute_topomesh_property(topomesh, 'length', degree=1)

    triangular = kwargs.get('triangular', True)
    display = kwargs.get('display', False)

    if triangular:
        compute_topomesh_triangle_properties(topomesh)
        compute_topomesh_property(topomesh, 'normal', degree=2)
        compute_topomesh_property(topomesh, 'angles', degree=2)

    if "Triangle Area Deviation" in quality_criteria:
        start_time = time()
        print "--> Computing triangle area deviation"
        # area_deviation = np.nanmean(np.abs(topomesh.wisp_property('area',degree=2).values()-np.nanmean(topomesh.wisp_property('area',degree=2).values())))/np.nanmean(topomesh.wisp_property('area',degree=2).values())
        area_deviation = np.nanstd(
            topomesh.wisp_property('area', degree=2).values()) / np.nanmean(
                topomesh.wisp_property('area', degree=2).values())
        # quality_data["Triangle Area Deviation"] = np.minimum(1.0,1.0-area_deviation/np.sqrt(2))
        # quality_data["Triangle Area Deviation"] = np.minimum(1.0,1.0-area_deviation/2.)
        quality_data["Triangle Area Deviation"] = np.minimum(
            1.0,
            np.sqrt(2) - area_deviation / np.sqrt(2))
        end_time = time()
        print "<-- Computing triangle area deviation  [", end_time - start_time, "s]"

    if "Triangle Eccentricity" in quality_criteria:
        start_time = time()
        print "--> Computing triangle eccentricity"
        quality_data["Triangle Eccentricity"] = 1. - 2. * np.nanmean(
            topomesh.wisp_property('eccentricity', degree=2).values())
        end_time = time()
        print "<-- Computing triangle eccentricity    [", end_time - start_time, "s]"

    compute_topomesh_property(topomesh, 'borders', degree=3)
    compute_topomesh_property(topomesh, 'borders', degree=2)
    compute_topomesh_property(topomesh, 'borders', degree=1)

    compute_topomesh_property(topomesh, 'vertices', degree=3)
    compute_topomesh_property(topomesh, 'vertices', degree=2)

    compute_topomesh_property(topomesh, 'barycenter', degree=3)
    compute_topomesh_property(topomesh, 'barycenter', degree=2)
    compute_topomesh_property(topomesh, 'barycenter', degree=1)

    compute_topomesh_property(topomesh, 'triangles', degree=0)

    compute_topomesh_property(topomesh, 'cells', degree=0)
    compute_topomesh_property(topomesh, 'cells', degree=1)
    compute_topomesh_property(topomesh, 'cells', degree=2)

    compute_topomesh_property(topomesh, 'epidermis', degree=0)
    compute_topomesh_property(topomesh, 'epidermis', degree=1)
    compute_topomesh_property(topomesh, 'epidermis', degree=3)

    if "Cell Volume Error" in quality_criteria or "Cell Convexity" in quality_criteria:
        compute_topomesh_property(topomesh, 'volume', degree=3)
        compute_topomesh_property(topomesh, 'convexhull_volume', degree=3)

    img_graph = kwargs.get('image_graph', None)

    if "Cell Volume Error" in quality_criteria:
        start_time = time()
        print "--> Computing cell volume error"

        from vplants.tissue_analysis.temporal_graph_from_image import graph_from_image
        if (image_cell_volumes == None) or (image_labels
                                            == None) or (image_cell_vertex
                                                         == None):
            img_graph = graph_from_image(
                image,
                spatio_temporal_properties=['volume', 'barycenter'],
                background=0,
                ignore_cells_at_stack_margins=False,
                property_as_real=True)
            image_labels = np.array(list(img_graph.vertices()))
            image_cell_volumes = np.array(
                [img_graph.vertex_property('volume')[v] for v in image_labels])
        else:
            img_graph = None

        img_volumes = array_dict(image_cell_volumes, image_labels)

        if triangular:
            volume_error = array_dict([
                (c, (topomesh.wisp_property('volume', degree=3)[c] -
                     img_volumes[c]) / img_volumes[c])
                for c in topomesh.wisps(3)
            ])
        else:
            volume_error = array_dict([
                (c, (topomesh.wisp_property('convexhull_volume', degree=3)[c] -
                     img_volumes[c]) / img_volumes[c])
                for c in topomesh.wisps(3)
            ])

        quality_data["Cell Volume Error"] = np.maximum(
            1. - abs(volume_error.values()).mean(), 0.0)
        end_time = time()
        print "<-- Computing cell volume error        [", end_time - start_time, "s]"

    if "Image Accuracy" in quality_criteria:
        start_time = time()
        print "--> Computing image accuracy"

        from openalea.mesh.utils.image_tools import compute_topomesh_image

        topomesh_img = compute_topomesh_image(topomesh, image)

        cells_img = deepcopy(image)
        for c in set(np.unique(image)).difference(set(topomesh.wisps(3))):
            cells_img[image == c] = 1

        true_positives = ((cells_img != 1) & (cells_img == topomesh_img)).sum()
        false_positives = ((cells_img == 1) & (topomesh_img != 1)).sum() + (
            (cells_img != 1) & (topomesh_img != 1) &
            (cells_img != topomesh_img)).sum()
        false_negatives = ((cells_img != 1) & (topomesh_img == 1)).sum() + (
            (cells_img != 1) & (topomesh_img != 1) &
            (cells_img != topomesh_img)).sum()
        true_negatives = ((cells_img == 1) & (cells_img == topomesh_img)).sum()

        estimators = {}
        estimators['Precision'] = float(
            true_positives / float(true_positives + false_positives))
        estimators['Recall'] = float(true_positives /
                                     float(true_positives + false_negatives))
        estimators['Dice'] = float(
            2 * true_positives /
            float(2 * true_positives + false_positives + false_negatives))
        estimators['Jaccard'] = float(
            true_positives /
            float(true_positives + false_positives + false_negatives))
        estimators['Accuracy'] = float(true_positives +
                                       true_negatives) / float(
                                           true_positives + true_negatives +
                                           false_positives + false_negatives)
        estimators['Identity'] = float(
            (cells_img == topomesh_img).sum()) / np.prod(cells_img.shape)
        print estimators

        quality_data["Image Accuracy"] = estimators['Dice']

        end_time = time()
        print "<-- Computing image accuracy           [", end_time - start_time, "s]"

    vertex_cell_neighbours = topomesh.wisp_property('cells', degree=0)

    vertex_cell_degree = np.array(map(len, vertex_cell_neighbours.values()))

    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:
                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):
            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 = np.unique(mesh_cell_vertex.values())
    mesh_cell_vertices = topomesh.wisp_property('barycenter',
                                                degree=0).values(cell_vertex)

    if "Vertex Distance" in quality_criteria:
        start_time = time()
        print "--> Computing vertex distance"
        if image_cell_vertex is None:
            image_cell_vertex = cell_vertex_extraction(image,
                                                       hollow_out=False,
                                                       verbose=False)
            if img_graph is None:
                img_graph = graph_from_image(
                    image,
                    spatio_temporal_properties=['volume', 'barycenter'],
                    background=0,
                    ignore_cells_at_stack_margins=False,
                    property_as_real=True)
            img_edges = np.array(
                [img_graph.edge_vertices(e) for e in img_graph.edges()])

            tetra_edge_index_list = np.array([[0, 1], [0, 2], [0, 3], [1, 2],
                                              [1, 3], [2, 3]])
            img_vertex_edges = np.concatenate(
                np.sort(image_cell_vertex.keys())[:, tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges, img_edges)[1] >
                                    0).reshape(len(image_cell_vertex),
                                               6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(
                vertex_edge_matching == 0)[0]]

            image_cell_vertex = array_dict(
                np.array([
                    image_cell_vertex[tuple(vertex)]
                    for vertex in img_cell_vertex
                ]), np.sort(img_cell_vertex))
        else:
            image_cell_vertex = deepcopy(image_cell_vertex)
        # for v in image_cell_vertex.keys():
        #     image_cell_vertex[v] = image_cell_vertex[v]*np.array(image.voxelsize)

        image_cell_vertices = np.array(image_cell_vertex.values())
        print mesh_cell_vertices[np.where(
            1 - np.isnan(mesh_cell_vertices)[:, 0])] * image.voxelsize
        print image_cell_vertices * image.voxelsize
        vertex_distances_mesh = array_dict(
            vq(
                mesh_cell_vertices[np.where(
                    1 - np.isnan(mesh_cell_vertices)[:, 0])] * image.voxelsize,
                image_cell_vertices * image.voxelsize)[1], cell_vertex)
        vertex_distances_image = vq(
            image_cell_vertices[np.where(1 -
                                         np.isnan(image_cell_vertices)[:, 0])],
            mesh_cell_vertices)[1]

        # quality_data["Vertex Distance"] = np.sqrt(3)/(np.maximum(np.sqrt(3),vertex_distances_image.mean()))
        quality_data["Vertex Distance"] = (0.25 * np.sqrt(3)) / (np.maximum(
            (0.25 * np.sqrt(3)), vertex_distances_image.mean()))
        end_time = time()
        print "<-- Computing vertex distance          [", end_time - start_time, "s]"

    if "Cell Convexity" in quality_criteria:
        start_time = time()
        print "--> Computing cell convexity"

        # quality_data["Cell Convexity"] = (topomesh.wisp_property('volume',degree=3).values()/topomesh.wisp_property('convexhull_volume',degree=3).values()).mean()
        quality_data["Cell Convexity"] = 1 - (
            ((topomesh.wisp_property('convexhull_volume', 3).values() -
              topomesh.wisp_property('volume', 3).values()).mean()) /
            topomesh.wisp_property('volume', 3).values().mean())
        end_time = time()
        print "<-- Computing cell convexity           [", end_time - start_time, "s]"

    if "Epidermis Cell Angle" in quality_criteria:
        start_time = time()
        print "--> Computing epidermis cell angle"
        epidermis_vertex_cell_angles = np.array([])
        epidermis_vertex_angles = array_dict()
        angle_keys = np.concatenate([
            np.concatenate([[(t, v)]
                            for v in topomesh.wisp_property('vertices', 2)[t]],
                           axis=0) for t in topomesh.wisps(2)
        ],
                                    axis=0)
        angle_dict = dict([(tuple(k), 0.) for k in angle_keys])

        for v in cell_vertex:
            if topomesh.wisp_property('epidermis', 0)[v]:
                vertex_triangles = np.array([
                    t for t in topomesh.wisp_property('triangles', 0)[v]
                    if topomesh.wisp_property('epidermis', 2)[t]
                ])

                vertex_triangle_cells = np.concatenate(
                    topomesh.wisp_property('cells',
                                           degree=2).values(vertex_triangles))
                vertex_cells = np.unique(vertex_triangle_cells)

                vertex_triangle_cell_directions = topomesh.wisp_property(
                    'barycenter',
                    2).values(vertex_triangles) - topomesh.wisp_property(
                        'barycenter', 3).values(vertex_triangle_cells)
                vertex_triangle_normals = topomesh.wisp_property(
                    'normal', 2).values(vertex_triangles)
                reversed_normals = np.where(
                    np.einsum('ij,ij->i', vertex_triangle_normals,
                              vertex_triangle_cell_directions) < 0)[0]
                vertex_triangle_normals[
                    reversed_normals] = -vertex_triangle_normals[
                        reversed_normals]
                vertex_normal = np.mean(vertex_triangle_normals, axis=0)
                vertex_normal = vertex_normal / np.linalg.norm(vertex_normal)

                triangle_vertices = topomesh.wisp_property(
                    'vertices', degree=2).values(vertex_triangles)
                triangle_positions = topomesh.wisp_property(
                    'barycenter', degree=0).values(triangle_vertices)

                triangle_proj_vectors = triangle_positions - topomesh.wisp_property(
                    'barycenter', degree=0)[v]
                triangle_proj_dot = np.einsum('...ij,...j->...i',
                                              triangle_proj_vectors,
                                              vertex_normal)
                triangle_proj_vectors = -triangle_proj_dot[
                    ..., np.newaxis] * vertex_normal

                triangle_proj_positions = triangle_positions + triangle_proj_vectors

                edge_index_list = np.array([[1, 2], [0, 1], [0, 2]])

                triangle_edge_positions = triangle_proj_positions[:,
                                                                  edge_index_list]
                triangle_edge_vectors = triangle_edge_positions[:, :,
                                                                1] - triangle_edge_positions[:, :,
                                                                                             0]

                triangle_edge_lengths = np.linalg.norm(triangle_edge_vectors,
                                                       axis=2)

                triangle_cosines = np.zeros_like(triangle_edge_lengths,
                                                 np.float32)
                triangle_cosines[:,
                                 0] = (triangle_edge_lengths[:, 1]**2 +
                                       triangle_edge_lengths[:, 2]**2 -
                                       triangle_edge_lengths[:, 0]**2) / (
                                           2.0 * triangle_edge_lengths[:, 1] *
                                           triangle_edge_lengths[:, 2])
                triangle_cosines[:,
                                 2] = (triangle_edge_lengths[:, 2]**2 +
                                       triangle_edge_lengths[:, 0]**2 -
                                       triangle_edge_lengths[:, 1]**2) / (
                                           2.0 * triangle_edge_lengths[:, 2] *
                                           triangle_edge_lengths[:, 0])
                triangle_cosines[:,
                                 1] = (triangle_edge_lengths[:, 0]**2 +
                                       triangle_edge_lengths[:, 1]**2 -
                                       triangle_edge_lengths[:, 2]**2) / (
                                           2.0 * triangle_edge_lengths[:, 0] *
                                           triangle_edge_lengths[:, 1])
                triangle_angles = 180. * np.arccos(triangle_cosines) / np.pi

                vertex_triangle_angles = triangle_angles[np.where(
                    triangle_vertices == v)]

                vertex_cell_angles = array_dict(
                    nd.sum(vertex_triangle_angles,
                           vertex_triangle_cells,
                           index=vertex_cells), vertex_cells)

                for t, c in zip(vertex_triangles, vertex_triangle_cells):
                    angle_dict[(t, v)] = vertex_cell_angles[c]

                epidermis_vertex_angles[v] = np.sum(
                    vertex_cell_angles.values())
                if abs(epidermis_vertex_angles[v] - 360) < 10:
                    epidermis_vertex_cell_angles = np.concatenate([
                        epidermis_vertex_cell_angles,
                        vertex_cell_angles.values()
                    ])

        # quality_data["Epidermis Cell Angle"] = 1.0 - ((epidermis_vertex_cell_angles>180).sum()+(epidermis_vertex_cell_angles<90).sum())/(float(epidermis_vertex_cell_angles.shape[0]))

        quality_data["Epidermis Cell Angle"] = 1 - (np.sum(1 - np.exp(-np.power(
            np.maximum(100 - epidermis_vertex_cell_angles, 0.0) /
            20., 2.0))) + np.sum(1 - np.exp(-np.power(
                np.maximum(epidermis_vertex_cell_angles - 170, 0.0) /
                20., 2.0)))) / (float(epidermis_vertex_cell_angles.shape[0]))
        # np.sqrt(np.sum(np.power(np.maximum(90-epidermis_vertex_cell_angles,0.0)/30.,2.0))) + np.sum(np.maximum(epidermis_vertex_cell_angles-180,0.0)/30.)
        # quality_data["Epidermis Cell Angle"] = np.minimum(1.0,3-np.sqrt(np.power(epidermis_vertex_cell_angles-120.,2.0).mean())/30.)
        # quality_data["Epidermis Cell Angle"] = np.minimum(1.0,1.0-np.sqrt(np.power(epidermis_vertex_cell_angles-120.,2.0).mean())/120.)
        # quality_data["Epidermis Cell Angle"] = 1.0-np.power(np.power(np.abs(epidermis_vertex_cell_angles-120.),1.0).mean(),1.0)/120.

        end_time = time()
        print "<-- Computing epidermis cell angle     [", end_time - start_time, "s]"

    if "Vertex Valence" in quality_criteria:
        start_time = time()
        print "--> Computing vertex degree"
        compute_topomesh_property(topomesh, 'region_neighbors', degree=0)
        compute_topomesh_property(topomesh, 'border_neighbors', degree=3)

        # interface_vertices = np.array(list(topomesh.wisps(0)))[np.where((np.array(map(len,topomesh.wisp_property('cells',0).values())) == 1)
        #                                                          | ((np.array(map(len,topomesh.wisp_property('cells',0).values())) == 2)
        #                                                           & (1- topomesh.wisp_property('epidermis',0).values())))]
        # interface_vertices_degree = np.array(map(len,topomesh.wisp_property('neighbors',0).values(interface_vertices)))

        target_neighborhood = array_dict(
            (np.array(map(len,
                          topomesh.wisp_property('cells', 0).values())) +
             topomesh.wisp_property('epidermis', 0).values()) * 3,
            list(topomesh.wisps(0)))
        vertices_neighborhood = array_dict(
            map(len,
                topomesh.wisp_property('neighbors', 0).values()),
            list(topomesh.wisps(0)))

        interface_vertices = target_neighborhood.keys_where("==6")
        # np.power(np.power(target_neighborhood.values(interface_vertices)-vertices_neighborhood.values(interface_vertices),2.0).mean(),0.5)/6.0

        quality_data["Vertex Valence"] = np.minimum(
            1.0, 1.0 - np.abs(
                target_neighborhood.values(interface_vertices) -
                vertices_neighborhood.values(interface_vertices)).mean() / 6.0)
        # quality_data["Vertex Valence"] = np.minimum(1.0,1.0-np.nanmean(np.abs(interface_vertices_degree-6.0)))
        # quality_data["Vertex Valence"] = np.minimum(1.0,1.0-np.power(interface_vertices_degree-6.0,2.0).mean()/6.0)
        end_time = time()
        print "<-- Computing vertex degree            [", end_time - start_time, "s]"

    if "Cell 4 Adjacency" in quality_criteria:
        start_time = time()
        print "--> Computing cell adjacency"
        if image_cell_vertex == None:
            image_cell_vertex = cell_vertex_extraction(img,
                                                       hollow_out=False,
                                                       verbose=False)
            if img_graph == None:
                img_graph = graph_from_image(
                    img,
                    spatio_temporal_properties=['volume', 'barycenter'],
                    background=0,
                    ignore_cells_at_stack_margins=False,
                    property_as_real=False,
                    min_contact_surface=0.5)
            img_edges = np.array(
                [img_graph.edge_vertices(e) for e in img_graph.edges()])

            tetra_edge_index_list = np.array([[0, 1], [0, 2], [0, 3], [1, 2],
                                              [1, 3], [2, 3]])
            img_vertex_edges = np.concatenate(
                np.sort(image_cell_vertex.keys())[:, tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges, img_edges)[1] >
                                    0).reshape(len(image_cell_vertex),
                                               6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(
                vertex_edge_matching == 0)[0]]

            image_cell_vertex = array_dict(
                np.array([
                    image_cell_vertex[tuple(vertex)]
                    for vertex in img_cell_vertex
                ]), np.sort(img_cell_vertex))

        cell_vertex_VP = (vq(
            np.sort(array_dict(mesh_cell_vertex).keys()),
            np.sort(array_dict(image_cell_vertex).keys()))[1] == 0).sum()
        cell_vertex_FP = (vq(np.sort(array_dict(mesh_cell_vertex).keys()),
                             np.sort(array_dict(image_cell_vertex).keys()))[1]
                          > 0).sum()
        cell_vertex_FN = (vq(np.sort(array_dict(image_cell_vertex).keys()),
                             np.sort(array_dict(mesh_cell_vertex).keys()))[1] >
                          0).sum()
        cell_vertex_jaccard = cell_vertex_VP / float(cell_vertex_VP +
                                                     cell_vertex_FP +
                                                     cell_vertex_FN)
        cell_vertex_dice = 2 * cell_vertex_VP / float(2 * cell_vertex_VP +
                                                      cell_vertex_FP +
                                                      cell_vertex_FN)

        quality_data["Cell 4 Adjacency"] = cell_vertex_jaccard
        end_time = time()
        print "<-- Computing cell adjacency           [", end_time - start_time, "s]"

    if "Cell 2 Adjacency" in quality_criteria:
        start_time = time()
        print "--> Computing cell adjacency"

        tetra_edge_index_list = np.array([[0, 1], [0, 2], [0, 3], [1, 2],
                                          [1, 3], [2, 3]])

        if image_cell_vertex == None:
            image_cell_vertex = cell_vertex_extraction(img,
                                                       hollow_out=False,
                                                       verbose=False)
            if img_graph == None:
                img_graph = graph_from_image(
                    img,
                    spatio_temporal_properties=['volume', 'barycenter'],
                    background=0,
                    ignore_cells_at_stack_margins=False,
                    property_as_real=False,
                    min_contact_surface=0.5)
            img_edges = np.array(
                [img_graph.edge_vertices(e) for e in img_graph.edges()])

            img_vertex_edges = np.concatenate(
                np.sort(image_cell_vertex.keys())[:, tetra_edge_index_list])
            vertex_edge_matching = (vq(img_vertex_edges, img_edges)[1] >
                                    0).reshape(len(image_cell_vertex),
                                               6).sum(axis=1)
            img_cell_vertex = np.array(image_cell_vertex.keys())[np.where(
                vertex_edge_matching == 0)[0]]

            image_cell_vertex = array_dict(
                np.array([
                    image_cell_vertex[tuple(vertex)]
                    for vertex in img_cell_vertex
                ]), np.sort(img_cell_vertex))

        from vplants.meshing.array_tools import array_unique

        mesh_cell_edges = array_unique(
            np.concatenate(
                np.sort(array_dict(mesh_cell_vertex).keys())
                [:, tetra_edge_index_list]))
        image_cell_edges = array_unique(
            np.concatenate(
                np.sort(array_dict(image_cell_vertex).keys())
                [:, tetra_edge_index_list]))

        from vplants.meshing.evaluation_tools import jaccard_index

        cell_edge_jaccard = jaccard_index(image_cell_edges, mesh_cell_edges)

        quality_data["Cell 2 Adjacency"] = cell_edge_jaccard
        end_time = time()
        print "<-- Computing cell adjacency           [", end_time - start_time, "s]"

    if "Cell Cliques" in quality_criteria:

        vertex_cells = np.array(
            [len(list(topomesh.regions(0, v, 3))) for v in topomesh.wisps(0)])
        vertex_epidermis = topomesh.wisp_property('epidermis',
                                                  degree=0).values()

        cell_vertices = ((vertex_cells >= 3) * (vertex_epidermis) +
                         (vertex_cells >= 4) *
                         (True - vertex_epidermis)).sum()
        clique_cell_vertices = ((vertex_cells > 3) * (vertex_epidermis) +
                                (vertex_cells > 4) *
                                (True - vertex_epidermis)).sum()

        quality_data["Cell Cliques"] = 1.0 - float(
            clique_cell_vertices) / float(cell_vertices)

    print quality_data

    # if display:
    #     spider_figure = plt.figure(kwargs.get('figure_title',"Topomesh Quality"))
    #     spider_figure.clf()
    #     spider_data = np.array([quality_data[c] for c in quality_criteria])
    #     spider_fields= quality_criteria
    #     # spider_targets = [0.8,0.7,0.8,0.8,0.9,0.8,0.7]
    #     spider_targets = 0.8 * np.ones_like(quality_criteria,float)
    #     spider_plot(spider_figure,spider_data,color1=np.array([0.3,0.6,1.]),color2=np.array([1.,0.,0.]),xlabels=spider_fields,ytargets=spider_targets,n_points=100*len(quality_criteria),linewidth=2,smooth_factor=0.0,spline_order=1)
    #     plt.show(block=False)

    return quality_data
コード例 #7
0
background_adjacency = False

img = imread(filename)

if 'world' in dir():
    world.add(img,
              'segmented_image',
              colormap='glasbey',
              alphamap='constant',
              alpha=0.2)

cell_vertex = cell_vertex_extraction(img)
tetras = np.array(cell_vertex.keys())

img_graph = graph_from_image(
    img,
    spatio_temporal_properties=['barycenter', 'volume'],
    ignore_cells_at_stack_margins=True)
positions = img_graph.vertex_property('barycenter')

if background_adjacency:
    positions[1] = np.array([0, 0, 0], float)
else:
    tetras = tetras[tetras[:, 0] != 1]

topomesh = tetrahedra_topomesh(tetras, positions)

if 'world' in dir():
    world.add(topomesh, 'adjacency')
    world['adjacency_cells']['polydata_colormap'] = load_colormaps()['grey']
    world['adjacency_cells']['intensity_range'] = (-1, 0)
    world['adjacency_cells']['polydata_alpha'] = 0.5