Skip to content

Commit 03048ee

Browse files
Implement CLI for the annotators
1 parent b4c316c commit 03048ee

File tree

5 files changed

+192
-6
lines changed

5 files changed

+192
-6
lines changed

micro_sam/sam_annotator/annotator_2d.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -120,3 +120,59 @@ def clear_prompts(v):
120120
# clear the initial points needed for workaround
121121
clear_prompts(v)
122122
napari.run()
123+
124+
125+
def main():
126+
import argparse
127+
import warnings
128+
129+
parser = argparse.ArgumentParser(
130+
description="Run interactive segmentation for an image."
131+
)
132+
parser.add_argument(
133+
"-i", "--input", required=True,
134+
help="The filepath to the image data. Supports all data types that can be read by imageio (e.g. tif, png, ...) "
135+
"or elf.io.open_file (e.g. hdf5, zarr, mrc) For the latter you also need to pass the 'key' parameter."
136+
)
137+
parser.add_argument(
138+
"-k", "--key",
139+
help="The key for opening data with elf.io.open_file. This is the internal path for a hdf5 or zarr container, "
140+
"for a image series it is a wild-card, e.g. '*.png' and for mrc it is 'data'."
141+
)
142+
parser.add_argument(
143+
"-e", "--embedding_path",
144+
help="The filepath for saving/loading the pre-computed image embeddings. "
145+
"NOTE: It is recommended to pass this argument and store the embeddings, "
146+
"otherwise they will be recomputed every time (which can take a long time)."
147+
)
148+
parser.add_argument(
149+
"-s", "--segmentation",
150+
help="Optional filepath to a precomputed segmentation. If passed this will be used to initialize the "
151+
"'committed_objects' layer. This can be useful if you want to correct an existing segmentation or if you "
152+
"have saved intermediate results from the annotator and want to continue with your annotations. "
153+
"Supports the same file formats as 'input'."
154+
)
155+
parser.add_argument(
156+
"-sk", "--segmentation_key",
157+
help="The key for opening the segmentation data. Same rules as for 'key' apply."
158+
)
159+
parser.add_argument(
160+
"--show_embeddings", action="store_true",
161+
help="Visualize the embeddings computed by SegmentAnything. This can be helpful for debugging."
162+
)
163+
164+
args = parser.parse_args()
165+
raw = util.load_image_data(args.input, ndim=2, key=args.key)
166+
167+
if args.segmentation is None:
168+
segmentation = None
169+
else:
170+
segmentation = util.load_image_data(args.segmentation, args.segmentation_key)
171+
172+
if args.embedding_path is None:
173+
warnings.warn("You have not passed an embedding_path. Restarting the annotator may take a long time.")
174+
175+
annotator_2d(
176+
raw, embedding_path=args.embedding_path,
177+
show_embeddings=args.show_embeddings, segmentation_result=segmentation
178+
)

micro_sam/sam_annotator/annotator_3d.py

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -249,3 +249,59 @@ def clear_prompts(v):
249249
# clear the initial points needed for workaround
250250
clear_prompts(v)
251251
napari.run()
252+
253+
254+
def main():
255+
import argparse
256+
import warnings
257+
258+
parser = argparse.ArgumentParser(
259+
description="Run interactive segmentation for an image volume."
260+
)
261+
parser.add_argument(
262+
"-i", "--input", required=True,
263+
help="The filepath to the image data. Supports all data types that can be read by imageio (e.g. tif, png, ...) "
264+
"or elf.io.open_file (e.g. hdf5, zarr, mrc) For the latter you also need to pass the 'key' parameter."
265+
)
266+
parser.add_argument(
267+
"-k", "--key",
268+
help="The key for opening data with elf.io.open_file. This is the internal path for a hdf5 or zarr container, "
269+
"for a image series it is a wild-card, e.g. '*.png' and for mrc it is 'data'."
270+
)
271+
parser.add_argument(
272+
"-e", "--embedding_path",
273+
help="The filepath for saving/loading the pre-computed image embeddings. "
274+
"NOTE: It is recommended to pass this argument and store the embeddings, "
275+
"otherwise they will be recomputed every time (which can take a long time)."
276+
)
277+
parser.add_argument(
278+
"-s", "--segmentation",
279+
help="Optional filepath to a precomputed segmentation. If passed this will be used to initialize the "
280+
"'committed_objects' layer. This can be useful if you want to correct an existing segmentation or if you "
281+
"have saved intermediate results from the annotator and want to continue with your annotations. "
282+
"Supports the same file formats as 'input'."
283+
)
284+
parser.add_argument(
285+
"-sk", "--segmentation_key",
286+
help="The key for opening the segmentation data. Same rules as for 'key' apply."
287+
)
288+
parser.add_argument(
289+
"--show_embeddings", action="store_true",
290+
help="Visualize the embeddings computed by SegmentAnything. This can be helpful for debugging."
291+
)
292+
293+
args = parser.parse_args()
294+
raw = util.load_image_data(args.input, ndim=3, key=args.key)
295+
296+
if args.segmentation is None:
297+
segmentation = None
298+
else:
299+
segmentation = util.load_image_data(args.segmentation, args.segmentation_key)
300+
301+
if args.embedding_path is None:
302+
warnings.warn("You have not passed an embedding_path. Restarting the annotator may take a long time.")
303+
304+
annotator_3d(
305+
raw, embedding_path=args.embedding_path,
306+
show_embeddings=args.show_embeddings, segmentation_result=segmentation
307+
)

micro_sam/sam_annotator/annotator_tracking.py

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,3 +199,60 @@ def clear_prompts(v):
199199
# clear the initial points needed for workaround
200200
clear_prompts(v)
201201
napari.run()
202+
203+
204+
def main():
205+
import argparse
206+
import warnings
207+
208+
parser = argparse.ArgumentParser(
209+
description="Run interactive segmentation for an image volume."
210+
)
211+
parser.add_argument(
212+
"-i", "--input", required=True,
213+
help="The filepath to the image data. Supports all data types that can be read by imageio (e.g. tif, png, ...) "
214+
"or elf.io.open_file (e.g. hdf5, zarr, mrc) For the latter you also need to pass the 'key' parameter."
215+
)
216+
parser.add_argument(
217+
"-k", "--key",
218+
help="The key for opening data with elf.io.open_file. This is the internal path for a hdf5 or zarr container, "
219+
"for a image series it is a wild-card, e.g. '*.png' and for mrc it is 'data'."
220+
)
221+
parser.add_argument(
222+
"-e", "--embedding_path",
223+
help="The filepath for saving/loading the pre-computed image embeddings. "
224+
"NOTE: It is recommended to pass this argument and store the embeddings, "
225+
"otherwise they will be recomputed every time (which can take a long time)."
226+
)
227+
# Not implemented for the tracking annotator yet.
228+
# And we should change the name for it.
229+
# parser.add_argument(
230+
# "-s", "--segmentation",
231+
# help="Optional filepath to a precomputed segmentation. If passed this will be used to initialize the "
232+
# "'committed_objects' layer. This can be useful if you want to correct an existing segmentation or if you "
233+
# "have saved intermediate results from the annotator and want to continue with your annotations. "
234+
# "Supports the same file formats as 'input'."
235+
# )
236+
# parser.add_argument(
237+
# "-sk", "--segmentation_key",
238+
# help="The key for opening the segmentation data. Same rules as for 'key' apply."
239+
# )
240+
parser.add_argument(
241+
"--show_embeddings", action="store_true",
242+
help="Visualize the embeddings computed by SegmentAnything. This can be helpful for debugging."
243+
)
244+
245+
args = parser.parse_args()
246+
raw = util.load_image_data(args.input, ndim=3, key=args.key)
247+
248+
# if args.segmentation is None:
249+
# segmentation = None
250+
# else:
251+
# segmentation = util.load_image_data(args.segmentation, args.segmentation_key)
252+
253+
if args.embedding_path is None:
254+
warnings.warn("You have not passed an embedding_path. Restarting the annotator may take a long time.")
255+
256+
annotator_tracking(
257+
raw, embedding_path=args.embedding_path, show_embeddings=args.show_embeddings
258+
)

micro_sam/util.py

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4,13 +4,19 @@
44
import numpy as np
55
import requests
66
import torch
7+
import vigra
78
import zarr
89

9-
import vigra
10+
from elf.io import open_file
1011
from skimage.measure import regionprops
1112

1213
from segment_anything import sam_model_registry, SamPredictor
1314

15+
try:
16+
import imageio.v2 as imageio
17+
except ImportError:
18+
import imageio
19+
1420
try:
1521
from napari.utils import progress as tqdm
1622
except ImportError:
@@ -269,10 +275,20 @@ def get_cell_center_coordinates(gt, mode="p"):
269275
return center_coordinates, bbox_coordinates
270276

271277

278+
def load_image_data(path, ndim, key=None, lazy_loading=False):
279+
if key is None:
280+
image_data = imageio.imread(path) if ndim == 2 else imageio.volread(path)
281+
else:
282+
with open_file(path, mode="r") as f:
283+
image_data = f[key]
284+
if not lazy_loading:
285+
image_data = image_data[:]
286+
return image_data
287+
288+
272289
# TODO enable passing options for get_sam
273290
def main():
274291
import argparse
275-
from elf.io import open_file
276292

277293
parser = argparse.ArgumentParser()
278294
parser.add_argument("-i", "--input_path", required=True)
@@ -281,7 +297,7 @@ def main():
281297
args = parser.parse_args()
282298

283299
predictor = get_sam_model()
284-
with open_file(args.input_path) as f:
300+
with open_file(args.input_path, mode="r") as f:
285301
data = f[args.key]
286302
precompute_image_embeddings(predictor, data, save_path=args.output_path)
287303

setup.py

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,13 +8,14 @@
88
version="0.0.1",
99
description="SegmentAnything For Microscopy",
1010
author="Anwai Archit, Constantin Pape",
11-
1211
url="https://user.informatik.uni-goettingen.de/~pape41/",
1312
packages=["micro_sam"],
14-
license="MIT", # TODO add the license and check that it's fine with SegmentAnything
15-
# TODO add entry points for the napari annotator scripts
13+
license="MIT",
1614
entry_points={
1715
"console_scripts": [
16+
"micro_sam.annotator_2d = micro_sam.sam_annotator.annotator_2d:main",
17+
"micro_sam.annotator_3d = micro_sam.sam_annotator.annotator_3d:main",
18+
"micro_sam.annotator_tracking = micro_sam.sam_annotator.annotator_tracking:main",
1819
"micro_sam.precompute_embeddings = micro_sam.util:main",
1920
]
2021
}

0 commit comments

Comments
 (0)