micro_sam.sam_annotator.annotator_tracking
1from typing import Optional, Tuple, Union, List 2 3import numpy as np 4 5import torch 6 7import napari 8from magicgui.widgets import ComboBox, Container 9 10from .. import util 11from . import util as vutil 12from . import _widgets as widgets 13from ._tooltips import get_tooltip 14from ._state import AnnotatorState 15from ._annotator import _AnnotatorBase 16 17 18# Cyan (track) and Magenta (division) 19STATE_COLOR_CYCLE = ["#00FFFF", "#FF00FF", ] 20"""@private""" 21 22 23# This solution is a bit hacky, so I won't move it to _widgets.py yet. 24def create_tracking_menu(points_layer, box_layer, states, track_ids, tracking_widget=None): 25 """@private""" 26 state = AnnotatorState() 27 28 def _get_widget_menu(container, label): 29 for w in container: 30 if isinstance(w, ComboBox) and w.label == label: 31 return w 32 raise ValueError(f"ComboBox with label '{label}' not found.") 33 34 if tracking_widget is None: 35 state_menu = ComboBox( 36 label="track_state", choices=states, tooltip=get_tooltip("annotator_tracking", "track_state") 37 ) 38 track_id_menu = ComboBox( 39 label="track_id", choices=list(map(str, track_ids)), tooltip=get_tooltip("annotator_tracking", "track_id") 40 ) 41 tracking_widget = Container(widgets=[state_menu, track_id_menu]) 42 else: 43 state_menu = _get_widget_menu(tracking_widget, "track_state") 44 track_id_menu = _get_widget_menu(tracking_widget, "track_id") 45 46 def update_state(event): 47 if "state" in points_layer.current_properties: 48 new_state = str(points_layer.current_properties["state"][0]) 49 if new_state != state_menu.value: 50 state_menu.value = new_state 51 52 def update_track_id(event): 53 if "track_id" in points_layer.current_properties: 54 new_id = str(points_layer.current_properties["track_id"][0]) 55 if new_id != track_id_menu.value: 56 track_id_menu.value = new_id 57 state.current_track_id = int(new_id) 58 59 # def update_state_boxes(event): 60 # new_state = str(box_layer.current_properties["state"][0]) 61 # if new_state != state_menu.value: 62 # state_menu.value = new_state 63 64 def update_track_id_boxes(event): 65 if "track_id" in box_layer.current_properties: 66 new_id = str(box_layer.current_properties["track_id"][0]) 67 if new_id != track_id_menu.value: 68 track_id_menu.value = new_id 69 state.current_track_id = int(new_id) 70 71 points_layer.events.current_properties.connect(update_state) 72 points_layer.events.current_properties.connect(update_track_id) 73 # box_layer.events.current_properties.connect(update_state_boxes) 74 box_layer.events.current_properties.connect(update_track_id_boxes) 75 76 def state_changed(new_state): 77 current_properties = points_layer.current_properties 78 current_properties["state"] = np.array([new_state]) 79 points_layer.current_properties = current_properties 80 points_layer.refresh_colors() 81 82 def track_id_changed(new_track_id): 83 current_properties = points_layer.current_properties 84 current_properties["track_id"] = np.array([new_track_id]) 85 # Note: this fails with a key error after committing a lineage with multiple tracks. 86 # I think this does not cause any further errors, so we just skip this. 87 try: 88 points_layer.current_properties = current_properties 89 except KeyError: 90 pass 91 state.current_track_id = int(new_track_id) 92 93 # def state_changed_boxes(new_state): 94 # current_properties = box_layer.current_properties 95 # current_properties["state"] = np.array([new_state]) 96 # box_layer.current_properties = current_properties 97 # box_layer.refresh_colors() 98 99 def track_id_changed_boxes(new_track_id): 100 current_properties = box_layer.current_properties 101 current_properties["track_id"] = np.array([new_track_id]) 102 box_layer.current_properties = current_properties 103 state.current_track_id = int(new_track_id) 104 105 state_menu.changed.connect(state_changed) 106 track_id_menu.changed.connect(track_id_changed) 107 # state_menu.changed.connect(state_changed_boxes) 108 track_id_menu.changed.connect(track_id_changed_boxes) 109 110 state_menu.set_choice("track") 111 return tracking_widget 112 113 114class AnnotatorTracking(_AnnotatorBase): 115 116 # The tracking annotator needs different settings for the prompt layers 117 # to support the additional tracking state. 118 # That's why we over-ride this function. 119 def _require_layers(self, layer_choices: Optional[List[str]] = None): 120 121 # Check whether the image is initialized already. And use the image shape and scale for the layers. 122 state = AnnotatorState() 123 shape = self._shape if state.image_shape is None else state.image_shape 124 125 # Add the label layers for the current object, the automatic segmentation and the committed segmentation. 126 dummy_data = np.zeros(shape, dtype="uint32") 127 image_scale = state.image_scale 128 129 # Before adding new layers, we always check whether a layer with this name already exists or not. 130 if "current_object" not in self._viewer.layers: 131 if layer_choices and "current_object" in layer_choices: # Check at 'commit' call button. 132 widgets._validation_window_for_missing_layer("current_object") 133 self._viewer.add_labels(data=dummy_data, name="current_object") 134 if image_scale is not None: 135 self.layers["current_objects"].scale = image_scale 136 137 if "auto_segmentation" not in self._viewer.layers: 138 if layer_choices and "auto_segmentation" in layer_choices: # Check at 'commit' call button. 139 widgets._validation_window_for_missing_layer("auto_segmentation") 140 self._viewer.add_labels(data=dummy_data, name="auto_segmentation") 141 if image_scale is not None: 142 self.layers["auto_segmentation"].scale = image_scale 143 144 if "committed_objects" not in self._viewer.layers: 145 if layer_choices and "committed_objects" in layer_choices: # Check at 'commit' call button. 146 widgets._validation_window_for_missing_layer("committed_objects") 147 self._viewer.add_labels(data=dummy_data, name="committed_objects") 148 # Randomize colors so it is easy to see when object committed. 149 self._viewer.layers["committed_objects"].new_colormap() 150 if image_scale is not None: 151 self.layers["committed_objects"].scale = image_scale 152 153 # Add the point prompts layer. 154 self._point_labels = ["positive", "negative"] 155 self._track_state_labels = ["track", "division"] 156 _point_prompt_property_choices = { 157 "label": self._point_labels, 158 "state": self._track_state_labels, 159 "track_id": ["1"], # we use string to avoid pandas warning 160 } 161 162 point_layer_mismatch = True 163 if "point_prompts" in self._viewer.layers: 164 # Check whether the 'property_choices' match or not. 165 curr_property_choices = self._viewer.layers["point_prompts"].property_choices 166 point_layer_mismatch = set(curr_property_choices.keys()) != set(_point_prompt_property_choices.keys()) 167 168 if point_layer_mismatch and "point_prompts" not in self._viewer.layers: 169 self._point_prompt_layer = self._viewer.add_points( 170 name="point_prompts", 171 property_choices=_point_prompt_property_choices, 172 border_color="label", 173 border_color_cycle=vutil.LABEL_COLOR_CYCLE, 174 symbol="o", 175 face_color="state", 176 face_color_cycle=STATE_COLOR_CYCLE, 177 border_width=0.4, 178 size=12, 179 ndim=self._ndim, 180 ) 181 self._point_prompt_layer.border_color_mode = "cycle" 182 self._point_prompt_layer.face_color_mode = "cycle" 183 _new_point_layer = True 184 else: 185 self._point_prompt_layer = self._viewer.layers["point_prompts"] 186 _new_point_layer = False 187 188 # Add the point prompts layer. 189 _box_prompt_property_choices = {"track_id": ["1"]} 190 191 box_layer_mismatch = True 192 if "prompts" in self._viewer.layers: 193 # Check whether the 'property_choices' match or not. 194 curr_property_choices = self._viewer.layers["prompts"].property_choices 195 box_layer_mismatch = set(curr_property_choices.keys()) != set(_box_prompt_property_choices.keys()) 196 197 if box_layer_mismatch and "prompts" not in self._viewer.layers: 198 # Using the box layer to set divisions currently doesn't work. 199 # That's why some of the code below is commented out. 200 self._box_prompt_layer = self._viewer.add_shapes( 201 shape_type="rectangle", 202 edge_width=4, 203 ndim=self._ndim, 204 face_color="transparent", 205 name="prompts", 206 edge_color="green", 207 property_choices=_box_prompt_property_choices, 208 # property_choices={"track_id": ["1"], "state": self._track_state_labels}, 209 # edge_color_cycle=STATE_COLOR_CYCLE, 210 ) 211 # self._box_prompt_layer.edge_color_mode = "cycle" 212 _new_box_layer = True 213 else: 214 self._box_prompt_layer = self._viewer.layers["prompts"] 215 _new_box_layer = False 216 217 # Trigger a new connection for the tracking state menu only when a new layer is (re)created. 218 if _new_point_layer or _new_box_layer: 219 self._tracking_widget = create_tracking_menu( 220 points_layer=self._point_prompt_layer, 221 box_layer=self._box_prompt_layer, 222 states=self._track_state_labels, 223 track_ids=list(state.lineage.keys()), 224 tracking_widget=state.widgets.get("tracking"), 225 ) 226 state.widgets["tracking"] = self._tracking_widget 227 228 def _get_widgets(self): 229 state = AnnotatorState() 230 self._require_layers() 231 232 # Create the tracking state menu. 233 # NOTE: Check whether it exists already from `_require_layers` or needs to be created. 234 if state.widgets.get("tracking") is None: 235 self._tracking_widget = create_tracking_menu( 236 ponts_layer=self._point_prompt_layer, 237 box_layer=self._box_prompt_layer, 238 states=self._track_state_labels, 239 track_ids=list(state.lineage.keys()), 240 ) 241 else: 242 self._tracking_widget = state.widgets.get("tracking") 243 244 segment_nd = widgets.SegmentNDWidget(self._viewer, tracking=True) 245 autotrack = widgets.AutoTrackWidget(self._viewer, with_decoder=self._with_decoder, volumetric=True) 246 return { 247 "tracking": self._tracking_widget, 248 "segment": widgets.segment_frame(), 249 "segment_nd": segment_nd, 250 "autosegment": autotrack, 251 "commit": widgets.commit_track(), 252 "clear": widgets.clear_track(), 253 } 254 255 def __init__(self, viewer: "napari.viewer.Viewer", reset_state: bool = True) -> None: 256 # Initialize the state for tracking. 257 self._init_track_state() 258 self._with_decoder = AnnotatorState().decoder is not None 259 super().__init__(viewer=viewer, ndim=3) 260 # Go to t=0. 261 self._viewer.dims.current_step = (0, 0, 0) + tuple(sh // 2 for sh in self._shape[1:]) 262 263 # Set the expected annotator class to the state. 264 state = AnnotatorState() 265 266 # Reset the state. 267 if reset_state: 268 state.reset_state() 269 270 state.annotator = self 271 272 def _init_track_state(self): 273 state = AnnotatorState() 274 state.current_track_id = 1 275 state.lineage = {1: []} 276 state.committed_lineages = [] 277 278 def _update_image(self): 279 super()._update_image() 280 self._init_track_state() 281 state = AnnotatorState() 282 if self._with_decoder: 283 state.amg_state = vutil._load_is_state(state.embedding_path) 284 else: 285 state.amg_state = vutil._load_amg_state(state.embedding_path) 286 287 288def annotator_tracking( 289 image: np.ndarray, 290 embedding_path: Optional[str] = None, 291 # tracking_result: Optional[str] = None, 292 model_type: str = util._DEFAULT_MODEL, 293 tile_shape: Optional[Tuple[int, int]] = None, 294 halo: Optional[Tuple[int, int]] = None, 295 return_viewer: bool = False, 296 viewer: Optional["napari.viewer.Viewer"] = None, 297 precompute_amg_state: bool = False, 298 checkpoint_path: Optional[str] = None, 299 device: Optional[Union[str, torch.device]] = None, 300) -> Optional["napari.viewer.Viewer"]: 301 """Start the tracking annotation tool fora given timeseries. 302 303 Args: 304 image: The image data. 305 embedding_path: Filepath for saving the precomputed embeddings. 306 model_type: The Segment Anything model to use. For details on the available models check out 307 https://computational-cell-analytics.github.io/micro-sam/micro_sam.html#finetuned-models. 308 tile_shape: Shape of tiles for tiled embedding prediction. 309 If `None` then the whole image is passed to Segment Anything. 310 halo: Shape of the overlap between tiles, which is needed to segment objects on tile boarders. 311 return_viewer: Whether to return the napari viewer to further modify it before starting the tool. 312 By default, does not return the napari viewer. 313 viewer: The viewer to which the Segment Anything functionality should be added. 314 This enables using a pre-initialized viewer. 315 precompute_amg_state: Whether to precompute the state for automatic mask generation. 316 This will take more time when precomputing embeddings, but will then make 317 automatic mask generation much faster. By default, set to 'False'. 318 checkpoint_path: Path to a custom checkpoint from which to load the SAM model. 319 device: The computational device to use for the SAM model. 320 By default, automatically chooses the best available device. 321 322 Returns: 323 The napari viewer, only returned if `return_viewer=True`. 324 """ 325 326 # Initialize the predictor state. 327 state = AnnotatorState() 328 state.initialize_predictor( 329 image, model_type=model_type, save_path=embedding_path, 330 halo=halo, tile_shape=tile_shape, prefer_decoder=True, 331 ndim=3, checkpoint_path=checkpoint_path, device=device, 332 precompute_amg_state=precompute_amg_state, use_cli=True, 333 ) 334 state.image_shape = image.shape[:-1] if image.ndim == 4 else image.shape 335 336 if viewer is None: 337 viewer = napari.Viewer() 338 339 viewer.add_image(image, name="image") 340 annotator = AnnotatorTracking(viewer, reset_state=False) 341 342 # Trigger layer update of the annotator so that layers have the correct shape. 343 annotator._update_image() 344 345 # Add the annotator widget to the viewer and sync widgets. 346 viewer.window.add_dock_widget(annotator) 347 vutil._sync_embedding_widget( 348 widget=state.widgets["embeddings"], 349 model_type=model_type if checkpoint_path is None else state.predictor.model_type, 350 save_path=embedding_path, 351 checkpoint_path=checkpoint_path, 352 device=device, 353 tile_shape=tile_shape, 354 halo=halo, 355 ) 356 357 if return_viewer: 358 return viewer 359 360 napari.run() 361 362 363def main(): 364 """@private""" 365 parser = vutil._initialize_parser( 366 description="Run interactive segmentation for an image volume.", 367 with_segmentation_result=False, 368 with_instance_segmentation=False, 369 ) 370 371 # Tracking result is not yet supported, we need to also deserialize the lineage. 372 # parser.add_argument( 373 # "-t", "--tracking_result", 374 # help="Optional filepath to a precomputed tracking result. If passed this will be used to initialize the " 375 # "'committed_tracks' layer. This can be useful if you want to correct an existing tracking result or if you " 376 # "have saved intermediate results from the annotator and want to continue. " 377 # "Supports the same file formats as 'input'." 378 # ) 379 # parser.add_argument( 380 # "-tk", "--tracking_key", 381 # help="The key for opening the tracking result. Same rules as for 'key' apply." 382 # ) 383 384 args = parser.parse_args() 385 image = util.load_image_data(args.input, key=args.key) 386 387 annotator_tracking( 388 image, embedding_path=args.embedding_path, model_type=args.model_type, 389 tile_shape=args.tile_shape, halo=args.halo, 390 checkpoint_path=args.checkpoint, device=args.device, 391 )
115class AnnotatorTracking(_AnnotatorBase): 116 117 # The tracking annotator needs different settings for the prompt layers 118 # to support the additional tracking state. 119 # That's why we over-ride this function. 120 def _require_layers(self, layer_choices: Optional[List[str]] = None): 121 122 # Check whether the image is initialized already. And use the image shape and scale for the layers. 123 state = AnnotatorState() 124 shape = self._shape if state.image_shape is None else state.image_shape 125 126 # Add the label layers for the current object, the automatic segmentation and the committed segmentation. 127 dummy_data = np.zeros(shape, dtype="uint32") 128 image_scale = state.image_scale 129 130 # Before adding new layers, we always check whether a layer with this name already exists or not. 131 if "current_object" not in self._viewer.layers: 132 if layer_choices and "current_object" in layer_choices: # Check at 'commit' call button. 133 widgets._validation_window_for_missing_layer("current_object") 134 self._viewer.add_labels(data=dummy_data, name="current_object") 135 if image_scale is not None: 136 self.layers["current_objects"].scale = image_scale 137 138 if "auto_segmentation" not in self._viewer.layers: 139 if layer_choices and "auto_segmentation" in layer_choices: # Check at 'commit' call button. 140 widgets._validation_window_for_missing_layer("auto_segmentation") 141 self._viewer.add_labels(data=dummy_data, name="auto_segmentation") 142 if image_scale is not None: 143 self.layers["auto_segmentation"].scale = image_scale 144 145 if "committed_objects" not in self._viewer.layers: 146 if layer_choices and "committed_objects" in layer_choices: # Check at 'commit' call button. 147 widgets._validation_window_for_missing_layer("committed_objects") 148 self._viewer.add_labels(data=dummy_data, name="committed_objects") 149 # Randomize colors so it is easy to see when object committed. 150 self._viewer.layers["committed_objects"].new_colormap() 151 if image_scale is not None: 152 self.layers["committed_objects"].scale = image_scale 153 154 # Add the point prompts layer. 155 self._point_labels = ["positive", "negative"] 156 self._track_state_labels = ["track", "division"] 157 _point_prompt_property_choices = { 158 "label": self._point_labels, 159 "state": self._track_state_labels, 160 "track_id": ["1"], # we use string to avoid pandas warning 161 } 162 163 point_layer_mismatch = True 164 if "point_prompts" in self._viewer.layers: 165 # Check whether the 'property_choices' match or not. 166 curr_property_choices = self._viewer.layers["point_prompts"].property_choices 167 point_layer_mismatch = set(curr_property_choices.keys()) != set(_point_prompt_property_choices.keys()) 168 169 if point_layer_mismatch and "point_prompts" not in self._viewer.layers: 170 self._point_prompt_layer = self._viewer.add_points( 171 name="point_prompts", 172 property_choices=_point_prompt_property_choices, 173 border_color="label", 174 border_color_cycle=vutil.LABEL_COLOR_CYCLE, 175 symbol="o", 176 face_color="state", 177 face_color_cycle=STATE_COLOR_CYCLE, 178 border_width=0.4, 179 size=12, 180 ndim=self._ndim, 181 ) 182 self._point_prompt_layer.border_color_mode = "cycle" 183 self._point_prompt_layer.face_color_mode = "cycle" 184 _new_point_layer = True 185 else: 186 self._point_prompt_layer = self._viewer.layers["point_prompts"] 187 _new_point_layer = False 188 189 # Add the point prompts layer. 190 _box_prompt_property_choices = {"track_id": ["1"]} 191 192 box_layer_mismatch = True 193 if "prompts" in self._viewer.layers: 194 # Check whether the 'property_choices' match or not. 195 curr_property_choices = self._viewer.layers["prompts"].property_choices 196 box_layer_mismatch = set(curr_property_choices.keys()) != set(_box_prompt_property_choices.keys()) 197 198 if box_layer_mismatch and "prompts" not in self._viewer.layers: 199 # Using the box layer to set divisions currently doesn't work. 200 # That's why some of the code below is commented out. 201 self._box_prompt_layer = self._viewer.add_shapes( 202 shape_type="rectangle", 203 edge_width=4, 204 ndim=self._ndim, 205 face_color="transparent", 206 name="prompts", 207 edge_color="green", 208 property_choices=_box_prompt_property_choices, 209 # property_choices={"track_id": ["1"], "state": self._track_state_labels}, 210 # edge_color_cycle=STATE_COLOR_CYCLE, 211 ) 212 # self._box_prompt_layer.edge_color_mode = "cycle" 213 _new_box_layer = True 214 else: 215 self._box_prompt_layer = self._viewer.layers["prompts"] 216 _new_box_layer = False 217 218 # Trigger a new connection for the tracking state menu only when a new layer is (re)created. 219 if _new_point_layer or _new_box_layer: 220 self._tracking_widget = create_tracking_menu( 221 points_layer=self._point_prompt_layer, 222 box_layer=self._box_prompt_layer, 223 states=self._track_state_labels, 224 track_ids=list(state.lineage.keys()), 225 tracking_widget=state.widgets.get("tracking"), 226 ) 227 state.widgets["tracking"] = self._tracking_widget 228 229 def _get_widgets(self): 230 state = AnnotatorState() 231 self._require_layers() 232 233 # Create the tracking state menu. 234 # NOTE: Check whether it exists already from `_require_layers` or needs to be created. 235 if state.widgets.get("tracking") is None: 236 self._tracking_widget = create_tracking_menu( 237 ponts_layer=self._point_prompt_layer, 238 box_layer=self._box_prompt_layer, 239 states=self._track_state_labels, 240 track_ids=list(state.lineage.keys()), 241 ) 242 else: 243 self._tracking_widget = state.widgets.get("tracking") 244 245 segment_nd = widgets.SegmentNDWidget(self._viewer, tracking=True) 246 autotrack = widgets.AutoTrackWidget(self._viewer, with_decoder=self._with_decoder, volumetric=True) 247 return { 248 "tracking": self._tracking_widget, 249 "segment": widgets.segment_frame(), 250 "segment_nd": segment_nd, 251 "autosegment": autotrack, 252 "commit": widgets.commit_track(), 253 "clear": widgets.clear_track(), 254 } 255 256 def __init__(self, viewer: "napari.viewer.Viewer", reset_state: bool = True) -> None: 257 # Initialize the state for tracking. 258 self._init_track_state() 259 self._with_decoder = AnnotatorState().decoder is not None 260 super().__init__(viewer=viewer, ndim=3) 261 # Go to t=0. 262 self._viewer.dims.current_step = (0, 0, 0) + tuple(sh // 2 for sh in self._shape[1:]) 263 264 # Set the expected annotator class to the state. 265 state = AnnotatorState() 266 267 # Reset the state. 268 if reset_state: 269 state.reset_state() 270 271 state.annotator = self 272 273 def _init_track_state(self): 274 state = AnnotatorState() 275 state.current_track_id = 1 276 state.lineage = {1: []} 277 state.committed_lineages = [] 278 279 def _update_image(self): 280 super()._update_image() 281 self._init_track_state() 282 state = AnnotatorState() 283 if self._with_decoder: 284 state.amg_state = vutil._load_is_state(state.embedding_path) 285 else: 286 state.amg_state = vutil._load_amg_state(state.embedding_path)
Base class for micro_sam annotation plugins.
Implements the logic for the 2d, 3d and tracking annotator. The annotators differ in their data dimensionality and the widgets.
AnnotatorTracking(viewer: napari.viewer.Viewer, reset_state: bool = True)
256 def __init__(self, viewer: "napari.viewer.Viewer", reset_state: bool = True) -> None: 257 # Initialize the state for tracking. 258 self._init_track_state() 259 self._with_decoder = AnnotatorState().decoder is not None 260 super().__init__(viewer=viewer, ndim=3) 261 # Go to t=0. 262 self._viewer.dims.current_step = (0, 0, 0) + tuple(sh // 2 for sh in self._shape[1:]) 263 264 # Set the expected annotator class to the state. 265 state = AnnotatorState() 266 267 # Reset the state. 268 if reset_state: 269 state.reset_state() 270 271 state.annotator = self
Create the annotator GUI.
Arguments:
- viewer: The napari viewer.
- ndim: The number of spatial dimension of the image data (2 or 3).
Inherited Members
- PyQt5.QtWidgets.QScrollArea
- alignment
- ensureVisible
- ensureWidgetVisible
- event
- eventFilter
- focusNextPrevChild
- resizeEvent
- scrollContentsBy
- setAlignment
- setWidget
- setWidgetResizable
- sizeHint
- takeWidget
- viewportSizeHint
- widget
- widgetResizable
- PyQt5.QtWidgets.QAbstractScrollArea
- SizeAdjustPolicy
- addScrollBarWidget
- contextMenuEvent
- cornerWidget
- dragEnterEvent
- dragLeaveEvent
- dragMoveEvent
- dropEvent
- horizontalScrollBar
- horizontalScrollBarPolicy
- keyPressEvent
- maximumViewportSize
- minimumSizeHint
- mouseDoubleClickEvent
- mouseMoveEvent
- mousePressEvent
- mouseReleaseEvent
- paintEvent
- scrollBarWidgets
- setCornerWidget
- setHorizontalScrollBar
- setHorizontalScrollBarPolicy
- setSizeAdjustPolicy
- setVerticalScrollBar
- setVerticalScrollBarPolicy
- setViewport
- setViewportMargins
- setupViewport
- sizeAdjustPolicy
- verticalScrollBar
- verticalScrollBarPolicy
- viewport
- viewportEvent
- viewportMargins
- wheelEvent
- AdjustIgnored
- AdjustToContents
- AdjustToContentsOnFirstShow
- PyQt5.QtWidgets.QFrame
- Shadow
- Shape
- StyleMask
- changeEvent
- drawFrame
- frameRect
- frameShadow
- frameShape
- frameStyle
- frameWidth
- initStyleOption
- lineWidth
- midLineWidth
- setFrameRect
- setFrameShadow
- setFrameShape
- setFrameStyle
- setLineWidth
- setMidLineWidth
- Box
- HLine
- NoFrame
- Panel
- Plain
- Raised
- Shadow_Mask
- Shape_Mask
- StyledPanel
- Sunken
- VLine
- WinPanel
- PyQt5.QtWidgets.QWidget
- RenderFlag
- RenderFlags
- acceptDrops
- accessibleDescription
- accessibleName
- actionEvent
- actions
- activateWindow
- addAction
- addActions
- adjustSize
- autoFillBackground
- backgroundRole
- baseSize
- childAt
- childrenRect
- childrenRegion
- clearFocus
- clearMask
- close
- closeEvent
- contentsMargins
- contentsRect
- contextMenuPolicy
- create
- createWindowContainer
- cursor
- destroy
- devType
- effectiveWinId
- ensurePolished
- enterEvent
- find
- focusInEvent
- focusNextChild
- focusOutEvent
- focusPolicy
- focusPreviousChild
- focusProxy
- focusWidget
- font
- fontInfo
- fontMetrics
- foregroundRole
- frameGeometry
- frameSize
- geometry
- getContentsMargins
- grab
- grabGesture
- grabKeyboard
- grabMouse
- grabShortcut
- graphicsEffect
- graphicsProxyWidget
- hasFocus
- hasHeightForWidth
- hasMouseTracking
- hasTabletTracking
- height
- heightForWidth
- hide
- hideEvent
- initPainter
- inputMethodEvent
- inputMethodHints
- inputMethodQuery
- insertAction
- insertActions
- isActiveWindow
- isAncestorOf
- isEnabled
- isEnabledTo
- isFullScreen
- isHidden
- isLeftToRight
- isMaximized
- isMinimized
- isModal
- isRightToLeft
- isVisible
- isVisibleTo
- isWindow
- isWindowModified
- keyReleaseEvent
- keyboardGrabber
- layout
- layoutDirection
- leaveEvent
- locale
- lower
- mapFrom
- mapFromGlobal
- mapFromParent
- mapTo
- mapToGlobal
- mapToParent
- mask
- maximumHeight
- maximumSize
- maximumWidth
- metric
- minimumHeight
- minimumSize
- minimumWidth
- mouseGrabber
- move
- moveEvent
- nativeEvent
- nativeParentWidget
- nextInFocusChain
- normalGeometry
- overrideWindowFlags
- overrideWindowState
- paintEngine
- palette
- parentWidget
- pos
- previousInFocusChain
- raise_
- rect
- releaseKeyboard
- releaseMouse
- releaseShortcut
- removeAction
- render
- repaint
- resize
- restoreGeometry
- saveGeometry
- screen
- scroll
- setAcceptDrops
- setAccessibleDescription
- setAccessibleName
- setAttribute
- setAutoFillBackground
- setBackgroundRole
- setBaseSize
- setContentsMargins
- setContextMenuPolicy
- setCursor
- setDisabled
- setEnabled
- setFixedHeight
- setFixedSize
- setFixedWidth
- setFocus
- setFocusPolicy
- setFocusProxy
- setFont
- setForegroundRole
- setGeometry
- setGraphicsEffect
- setHidden
- setInputMethodHints
- setLayout
- setLayoutDirection
- setLocale
- setMask
- setMaximumHeight
- setMaximumSize
- setMaximumWidth
- setMinimumHeight
- setMinimumSize
- setMinimumWidth
- setMouseTracking
- setPalette
- setParent
- setShortcutAutoRepeat
- setShortcutEnabled
- setSizeIncrement
- setSizePolicy
- setStatusTip
- setStyle
- setStyleSheet
- setTabOrder
- setTabletTracking
- setToolTip
- setToolTipDuration
- setUpdatesEnabled
- setVisible
- setWhatsThis
- setWindowFilePath
- setWindowFlag
- setWindowFlags
- setWindowIcon
- setWindowIconText
- setWindowModality
- setWindowModified
- setWindowOpacity
- setWindowRole
- setWindowState
- setWindowTitle
- show
- showEvent
- showFullScreen
- showMaximized
- showMinimized
- showNormal
- size
- sizeIncrement
- sizePolicy
- stackUnder
- statusTip
- style
- styleSheet
- tabletEvent
- testAttribute
- toolTip
- toolTipDuration
- underMouse
- ungrabGesture
- unsetCursor
- unsetLayoutDirection
- unsetLocale
- update
- updateGeometry
- updateMicroFocus
- updatesEnabled
- visibleRegion
- whatsThis
- width
- winId
- window
- windowFilePath
- windowFlags
- windowHandle
- windowIcon
- windowIconText
- windowModality
- windowOpacity
- windowRole
- windowState
- windowTitle
- windowType
- x
- y
- DrawChildren
- DrawWindowBackground
- IgnoreMask
- windowIconTextChanged
- windowIconChanged
- windowTitleChanged
- customContextMenuRequested
- PyQt5.QtCore.QObject
- blockSignals
- childEvent
- children
- connectNotify
- customEvent
- deleteLater
- disconnect
- disconnectNotify
- dumpObjectInfo
- dumpObjectTree
- dynamicPropertyNames
- findChild
- findChildren
- inherits
- installEventFilter
- isSignalConnected
- isWidgetType
- isWindowType
- killTimer
- metaObject
- moveToThread
- objectName
- parent
- property
- pyqtConfigure
- receivers
- removeEventFilter
- sender
- senderSignalIndex
- setObjectName
- setProperty
- signalsBlocked
- startTimer
- thread
- timerEvent
- tr
- staticMetaObject
- objectNameChanged
- destroyed
- PyQt5.QtGui.QPaintDevice
- PaintDeviceMetric
- colorCount
- depth
- devicePixelRatio
- devicePixelRatioF
- devicePixelRatioFScale
- heightMM
- logicalDpiX
- logicalDpiY
- paintingActive
- physicalDpiX
- physicalDpiY
- widthMM
- PdmDepth
- PdmDevicePixelRatio
- PdmDevicePixelRatioScaled
- PdmDpiX
- PdmDpiY
- PdmHeight
- PdmHeightMM
- PdmNumColors
- PdmPhysicalDpiX
- PdmPhysicalDpiY
- PdmWidth
- PdmWidthMM
def
annotator_tracking( image: numpy.ndarray, embedding_path: Optional[str] = None, model_type: str = 'vit_b_lm', tile_shape: Optional[Tuple[int, int]] = None, halo: Optional[Tuple[int, int]] = None, return_viewer: bool = False, viewer: Optional[napari.viewer.Viewer] = None, precompute_amg_state: bool = False, checkpoint_path: Optional[str] = None, device: Union[str, torch.device, NoneType] = None) -> Optional[napari.viewer.Viewer]:
289def annotator_tracking( 290 image: np.ndarray, 291 embedding_path: Optional[str] = None, 292 # tracking_result: Optional[str] = None, 293 model_type: str = util._DEFAULT_MODEL, 294 tile_shape: Optional[Tuple[int, int]] = None, 295 halo: Optional[Tuple[int, int]] = None, 296 return_viewer: bool = False, 297 viewer: Optional["napari.viewer.Viewer"] = None, 298 precompute_amg_state: bool = False, 299 checkpoint_path: Optional[str] = None, 300 device: Optional[Union[str, torch.device]] = None, 301) -> Optional["napari.viewer.Viewer"]: 302 """Start the tracking annotation tool fora given timeseries. 303 304 Args: 305 image: The image data. 306 embedding_path: Filepath for saving the precomputed embeddings. 307 model_type: The Segment Anything model to use. For details on the available models check out 308 https://computational-cell-analytics.github.io/micro-sam/micro_sam.html#finetuned-models. 309 tile_shape: Shape of tiles for tiled embedding prediction. 310 If `None` then the whole image is passed to Segment Anything. 311 halo: Shape of the overlap between tiles, which is needed to segment objects on tile boarders. 312 return_viewer: Whether to return the napari viewer to further modify it before starting the tool. 313 By default, does not return the napari viewer. 314 viewer: The viewer to which the Segment Anything functionality should be added. 315 This enables using a pre-initialized viewer. 316 precompute_amg_state: Whether to precompute the state for automatic mask generation. 317 This will take more time when precomputing embeddings, but will then make 318 automatic mask generation much faster. By default, set to 'False'. 319 checkpoint_path: Path to a custom checkpoint from which to load the SAM model. 320 device: The computational device to use for the SAM model. 321 By default, automatically chooses the best available device. 322 323 Returns: 324 The napari viewer, only returned if `return_viewer=True`. 325 """ 326 327 # Initialize the predictor state. 328 state = AnnotatorState() 329 state.initialize_predictor( 330 image, model_type=model_type, save_path=embedding_path, 331 halo=halo, tile_shape=tile_shape, prefer_decoder=True, 332 ndim=3, checkpoint_path=checkpoint_path, device=device, 333 precompute_amg_state=precompute_amg_state, use_cli=True, 334 ) 335 state.image_shape = image.shape[:-1] if image.ndim == 4 else image.shape 336 337 if viewer is None: 338 viewer = napari.Viewer() 339 340 viewer.add_image(image, name="image") 341 annotator = AnnotatorTracking(viewer, reset_state=False) 342 343 # Trigger layer update of the annotator so that layers have the correct shape. 344 annotator._update_image() 345 346 # Add the annotator widget to the viewer and sync widgets. 347 viewer.window.add_dock_widget(annotator) 348 vutil._sync_embedding_widget( 349 widget=state.widgets["embeddings"], 350 model_type=model_type if checkpoint_path is None else state.predictor.model_type, 351 save_path=embedding_path, 352 checkpoint_path=checkpoint_path, 353 device=device, 354 tile_shape=tile_shape, 355 halo=halo, 356 ) 357 358 if return_viewer: 359 return viewer 360 361 napari.run()
Start the tracking annotation tool fora given timeseries.
Arguments:
- image: The image data.
- embedding_path: Filepath for saving the precomputed embeddings.
- model_type: The Segment Anything model to use. For details on the available models check out https://computational-cell-analytics.github.io/micro-sam/micro_sam.html#finetuned-models.
- tile_shape: Shape of tiles for tiled embedding prediction.
If
None
then the whole image is passed to Segment Anything. - halo: Shape of the overlap between tiles, which is needed to segment objects on tile boarders.
- return_viewer: Whether to return the napari viewer to further modify it before starting the tool. By default, does not return the napari viewer.
- viewer: The viewer to which the Segment Anything functionality should be added. This enables using a pre-initialized viewer.
- precompute_amg_state: Whether to precompute the state for automatic mask generation. This will take more time when precomputing embeddings, but will then make automatic mask generation much faster. By default, set to 'False'.
- checkpoint_path: Path to a custom checkpoint from which to load the SAM model.
- device: The computational device to use for the SAM model. By default, automatically chooses the best available device.
Returns:
The napari viewer, only returned if
return_viewer=True
.