Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Extend automatic segmentation CLI to allow continuing annotation #858

Merged
merged 4 commits into from
Feb 11, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/annotator_3d.py
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,6 @@ def main():

# The corresponding CLI call for em_3d_annotator:
# (replace with cache directory on your machine)
# $ micro_sam.annotator_3d -i /home/pape/.cache/micro_sam/sample_data/lucchi_pp.zip.unzip/Lucchi++/Test_In -k *.png -e /home/pape/.cache/micro_sam/embeddings/embeddings-lucchi.zarr
# $ micro_sam.annotator_3d -i /home/pape/.cache/micro_sam/sample_data/lucchi_pp.zip.unzip/Lucchi++/Test_In -k *.png -e /home/pape/.cache/micro_sam/embeddings/embeddings-lucchi.zarr # noqa
if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion examples/annotator_tracking.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ def main():

# The corresponding CLI call for track_ctc_data:
# (replace with cache directory on your machine)
# $ micro_sam.annotator_tracking -i /home/pape/.cache/micro_sam/sample_data/DIC-C2DH-HeLa.zip.unzip/DIC-C2DH-HeLa/01 -k *.tif -e /home/pape/.cache/micro_sam/embeddings/embeddings-ctc.zarr
# $ micro_sam.annotator_tracking -i /home/pape/.cache/micro_sam/sample_data/DIC-C2DH-HeLa.zip.unzip/DIC-C2DH-HeLa/01 -k *.tif -e /home/pape/.cache/micro_sam/embeddings/embeddings-ctc.zarr # noqa
if __name__ == "__main__":
main()
2 changes: 1 addition & 1 deletion examples/image_series_annotator.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@ def main():

# The corresponding CLI call for track_ctc_data:
# (replace with cache directory on your machine)
# $ micro_sam.image_series_annotator -i /home/pape/.cache/micro_sam/sample_data/image-series.zip.unzip/series/ -e /home/pape/.cache/micro_sam/embeddings/series-embeddings/ -o segmentation_results
# $ micro_sam.image_series_annotator -i /home/pape/.cache/micro_sam/sample_data/image-series.zip.unzip/series/ -e /home/pape/.cache/micro_sam/embeddings/series-embeddings/ -o segmentation_results # noqa
if __name__ == "__main__":
main()
31 changes: 31 additions & 0 deletions micro_sam/automatic_segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ def automatic_instance_segmentation(
halo: Optional[Tuple[int, int]] = None,
verbose: bool = True,
return_embeddings: bool = False,
annotate: bool = False,
**generate_kwargs
) -> np.ndarray:
"""Run automatic segmentation for the input image.
Expand All @@ -94,6 +95,7 @@ def automatic_instance_segmentation(
halo: Overlap of the tiles for tiled prediction.
verbose: Verbosity flag.
return_embeddings: Whether to return the precomputed image embeddings.
annotate: Whether to activate the annotator for continue annotation process.
generate_kwargs: optional keyword arguments for the generate function of the AMG or AIS class.

Returns:
Expand Down Expand Up @@ -161,6 +163,30 @@ def automatic_instance_segmentation(
else:
instances = outputs

# Allow opening the automatic segmentation in the annotator for further annotation, if desired.
if annotate:
from micro_sam.sam_annotator import annotator_2d, annotator_3d
annotator_function = annotator_2d if ndim == 2 else annotator_3d

viewer = annotator_function(
image=image_data,
model_type=predictor.model_name,
embedding_path=embedding_path,
segmentation_result=instances, # Initializes the automatic segmentation to the annotator.
tile_shape=tile_shape,
halo=halo,
return_viewer=True, # Returns the viewer, which allows the user to store the updated segmentations.
)

# Start the GUI here
import napari
napari.run()

# We extract the segmentation in "committed_objects" layer, where the user either:
# a) Performed interactive segmentation / corrections and committed them, OR
# b) Did not do anything and closed the annotator, i.e. keeps the segmentations as it is.
instances = viewer.layers["committed_objects"].data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Have you tested once that this actually works? I am never sure about the actual state logic of napari.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I tried this out, by removing labels, adding segmentations and closing the annotator. It works for all cases!


# Save the instance segmentation, if 'output_path' provided.
if output_path is not None:
output_path = Path(output_path).with_suffix(".tif")
Expand Down Expand Up @@ -221,6 +247,10 @@ def main():
"--mode", type=str, default=None,
help="The choice of automatic segmentation with the Segment Anything models. Either 'amg' or 'ais'."
)
parser.add_argument(
"--annotate", action="store_true",
help="Whether to continue annotation after the automatic segmentation is generated."
)
parser.add_argument(
"-d", "--device", default=None,
help="The device to use for the predictor. Can be one of 'cuda', 'cpu' or 'mps' (only MAC)."
Expand Down Expand Up @@ -278,6 +308,7 @@ def _convert_argval(value):
ndim=args.ndim,
tile_shape=args.tile_shape,
halo=args.halo,
annotate=args.annotate,
**generate_kwargs,
)

Expand Down