66from skimage .measure import regionprops
77from skimage .segmentation import find_boundaries
88
9- from synapse_net .file_utils import read_mrc
10- from synapse_net .sample_data import get_sample_data
119from synapse_net .distance_measurements import measure_segmentation_to_object_distances
10+ from synapse_net .file_utils import read_mrc
11+ from synapse_net .imod .to_imod import convert_segmentation_to_spheres
1212from synapse_net .inference import compute_scale_from_voxel_size , get_model , run_segmentation
13+ from synapse_net .sample_data import get_sample_data
1314
1415
1516def segment_structures (tomogram , voxel_size ):
@@ -72,15 +73,23 @@ def postprocess_segmentation(segmentations):
7273
7374
7475def measure_distances (segmentations , voxel_size ):
76+ # Here, we measure the distances from each vesicle to the active zone.
77+ # We use the function 'measure_segmentation_to_object_distances' for this,
78+ # which uses an euclidean distance transform scaled with the voxel size
79+ # to determine distances.
7580 vesicles , active_zone = segmentations ["vesicles" ], segmentations ["active_zone" ]
7681 voxel_size = tuple (voxel_size [ax ] for ax in "zyx" )
7782 distances , _ , _ , vesicle_ids = measure_segmentation_to_object_distances (
7883 vesicles , active_zone , resolution = voxel_size
7984 )
85+ # We convert the result to a pandas data frame.
8086 return pd .DataFrame ({"vesicle_id" : vesicle_ids , "distance" : distances })
8187
8288
8389def assign_vesicle_pools (vesicle_attributes ):
90+ # We assign the vesicles to their respective pool, 'docked' and 'non-attached',
91+ # based on the criterion of being within 2 nm from the active zone.
92+ # We add the pool assignment as a new column to the dataframe with vesicle attributes.
8493 docked_vesicle_distance = 2 # nm
8594 vesicle_attributes ["pool" ] = vesicle_attributes ["distance" ].apply (
8695 lambda x : "docked" if x < docked_vesicle_distance else "non-attached"
@@ -89,6 +98,7 @@ def assign_vesicle_pools(vesicle_attributes):
8998
9099
91100def visualize_results (tomogram , segmentations , vesicle_attributes ):
101+ # Here, we visualize the segmentation and pool assignment result in napari.
92102
93103 # Create a segmentation to visualize the vesicle pools.
94104 docked_ids = vesicle_attributes [vesicle_attributes .pool == "docked" ].vesicle_id
@@ -97,6 +107,7 @@ def visualize_results(tomogram, segmentations, vesicle_attributes):
97107 vesicle_pools = np .isin (vesicles , docked_ids ).astype ("uint8" )
98108 vesicle_pools [np .isin (vesicles , non_attached_ids )] = 2
99109
110+ # Create a napari viewer, add the tomogram data and the segmentation results.
100111 viewer = napari .Viewer ()
101112 viewer .add_image (tomogram )
102113 for name , segmentation in segmentations .items ():
@@ -105,9 +116,16 @@ def visualize_results(tomogram, segmentations, vesicle_attributes):
105116 napari .run ()
106117
107118
108- # TODO compute the vesicle radii and other features and then save the attributes.
109119def save_analysis (segmentations , vesicle_attributes , save_path ):
110- pass
120+ # Here, we compute the radii and centroid positions of the vesicles,
121+ # add them to the vesicle attributes and then save all vesicle attributes to
122+ # an excel table. You can use this table for evaluation of the analysis.
123+ vesicles = segmentations ["vesicles" ]
124+ coordinates , radii = convert_segmentation_to_spheres (vesicles , radius_factor = 0.7 )
125+ vesicle_attributes ["radius" ] = radii
126+ for ax_id , ax_name in enumerate ("zyx" ):
127+ vesicle_attributes [f"center-{ ax_name } " ] = coordinates [:, ax_id ]
128+ vesicle_attributes .to_excel (save_path , index = False )
111129
112130
113131def main ():
@@ -119,16 +137,7 @@ def main():
119137 tomogram , voxel_size = read_mrc (mrc_path )
120138
121139 # Segment synaptic vesicles, the active zone, and the synaptic compartment.
122- # segmentations = segment_structures(tomogram, voxel_size)
123-
124- # Load saved segmentations for development.
125- import h5py
126- segmentations = {}
127- with h5py .File ("seg.h5" , "r" ) as f :
128- for name , ds in f .items ():
129- # f.create_dataset(name, data=seg, compression="gzip")
130- seg = ds [:]
131- segmentations [name ] = seg
140+ segmentations = segment_structures (tomogram , voxel_size )
132141
133142 # Post-process the segmentations, to find the presynaptic terminal,
134143 # filter out vesicles not in the terminal, and to 'snape' the AZ to the presynaptic boundary.
0 commit comments