1414import z5py
1515import napari
1616import numpy as np
17+ import nifty .ground_truth as ngt
1718
1819import elf .parallel
1920
@@ -358,7 +359,22 @@ def clear_track(viewer: "napari.viewer.Viewer", all_frames: bool = True) -> None
358359 gc .collect ()
359360
360361
361- def _commit_impl (viewer , layer , preserve_committed ):
362+ def _mask_matched_objects (seg , prev_seg , preservation_threshold ):
363+ prev_ids = np .unique (prev_seg )
364+ ovlp = ngt .overlap (prev_seg , seg )
365+
366+ mask_ids , prev_mask_ids = [], []
367+ for prev_id in prev_ids :
368+ seg_ids , overlaps = ovlp .overlapArrays (prev_id , True )
369+ if seg_ids [0 ] != 0 and overlaps [0 ] >= preservation_threshold :
370+ mask_ids .append (seg_ids [0 ])
371+ prev_mask_ids .append (prev_id )
372+
373+ preserve_mask = np .logical_or (np .isin (seg , mask_ids ), np .isin (prev_seg , prev_mask_ids ))
374+ return preserve_mask
375+
376+
377+ def _commit_impl (viewer , layer , preserve_mode , preservation_threshold ):
362378 # Check if we have a z_range. If yes, use it to set a bounding box.
363379 state = AnnotatorState ()
364380 if state .z_range is None :
@@ -373,7 +389,7 @@ def _commit_impl(viewer, layer, preserve_committed):
373389 seg = viewer .layers [layer ].data [bb ].astype (dtype )
374390 shape = seg .shape
375391
376- # We parallelize these operatios because they take quite long for large volumes.
392+ # We parallelize these operations because they take quite long for large volumes.
377393
378394 # Compute the max id in the commited objects.
379395 # id_offset = int(viewer.layers["committed_objects"].data.max())
@@ -388,9 +404,16 @@ def _commit_impl(viewer, layer, preserve_committed):
388404 mask = elf .parallel .apply_operation (
389405 seg , 0 , np .not_equal , out = mask , block_shape = util .get_block_shape (shape )
390406 )
391- if preserve_committed :
407+ if preserve_mode != "none" :
392408 prev_seg = viewer .layers ["committed_objects" ].data [bb ]
393- mask [prev_seg != 0 ] = 0
409+ # The mode 'pixels' corresponds to a naive implementation where only committed pixels are preserved.
410+ if preserve_mode == "pixels" :
411+ preserve_mask = prev_seg != 0
412+ # In the other mode 'objects' we preserve committed objects instead, by comparing the overlaps
413+ # of already committed and newly committed objects.
414+ else :
415+ preserve_mask = _mask_matched_objects (seg , prev_seg , preservation_threshold )
416+ mask [preserve_mask ] = 0
394417
395418 # Write the current object to committed objects.
396419 seg [mask ] += id_offset
@@ -580,13 +603,15 @@ def write_prompts(object_id, prompts, point_prompts, point_labels, track_state=N
580603
581604@magic_factory (
582605 call_button = "Commit [C]" ,
583- layer = {"choices" : ["current_object" , "auto_segmentation" ]},
584- commit_path = {"mode" : "d" }, # choose a directory
606+ layer = {"choices" : ["current_object" , "auto_segmentation" ], "tooltip" : get_tooltip ("commit" , "layer" )},
607+ preserve_mode = {"choices" : ["objects" , "pixels" , "none" ], "tooltip" : get_tooltip ("commit" , "preserve_mode" )},
608+ commit_path = {"mode" : "d" , "tooltip" : get_tooltip ("commit" , "commit_path" )},
585609)
586610def commit (
587611 viewer : "napari.viewer.Viewer" ,
588612 layer : str = "current_object" ,
589- preserve_committed : bool = True ,
613+ preserve_mode : str = "objects" ,
614+ preservation_threshold : float = 0.75 ,
590615 commit_path : Optional [Path ] = None ,
591616) -> None :
592617 """Widget for committing the segmented objects from automatic or interactive segmentation.
@@ -595,11 +620,15 @@ def commit(
595620 viewer: The napari viewer.
596621 layer: Select the layer to commit. Can be either 'current_object' to commit interacitve segmentation results.
597622 Or 'auto_segmentation' to commit automatic segmentation results.
598- preserve_committed: If active already committted objects are not over-written by new commits.
623+ preserve_mode: The mode for preserving already committed objects, in order to prevent over-writing
624+ them by a new commit. Supports the modes 'objects', which preserves on the object level and is the default,
625+ 'pixels', which preserves on the pixel-level, or 'none', which does not preserve commited objects.
626+ preservation_threshold: The overlap threshold for preserving objects. This is only used if
627+ preservation_mode is set to 'objects'.
599628 commit_path: Select a file path where the committed results and prompts will be saved.
600629 This feature is still experimental.
601630 """
602- _ , seg , mask , bb = _commit_impl (viewer , layer , preserve_committed )
631+ _ , seg , mask , bb = _commit_impl (viewer , layer , preserve_mode , preservation_threshold )
603632
604633 if commit_path is not None :
605634 _commit_to_file (commit_path , viewer , layer , seg , mask , bb )
@@ -620,12 +649,14 @@ def commit(
620649@magic_factory (
621650 call_button = "Commit [C]" ,
622651 layer = {"choices" : ["current_object" , "auto_segmentation" ]},
652+ preserve_mode = {"choices" : ["objects" , "pixels" , "none" ]},
623653 commit_path = {"mode" : "d" }, # choose a directory
624654)
625655def commit_track (
626656 viewer : "napari.viewer.Viewer" ,
627657 layer : str = "current_object" ,
628- preserve_committed : bool = True ,
658+ preserve_mode : str = "objects" ,
659+ preservation_threshold : float = 0.75 ,
629660 commit_path : Optional [Path ] = None ,
630661) -> None :
631662 """Widget for committing the objects from interactive tracking.
@@ -634,12 +665,16 @@ def commit_track(
634665 viewer: The napari viewer.
635666 layer: Select the layer to commit. Can be either 'current_object' to commit interacitve segmentation results.
636667 Or 'auto_segmentation' to commit automatic segmentation results.
637- preserve_committed: If active already committted objects are not over-written by new commits.
668+ preserve_mode: The mode for preserving already committed objects, in order to prevent over-writing
669+ them by a new commit. Supports the modes 'objects', which preserves on the object level and is the default,
670+ 'pixels', which preserves on the pixel-level, or 'none', which does not preserve commited objects.
671+ preservation_threshold: The overlap threshold for preserving objects. This is only used if
672+ preservation_mode is set to 'objects'.
638673 commit_path: Select a file path where the committed results and prompts will be saved.
639674 This feature is still experimental.
640675 """
641676 # Commit the segmentation layer.
642- id_offset , seg , mask , bb = _commit_impl (viewer , layer , preserve_committed )
677+ id_offset , seg , mask , bb = _commit_impl (viewer , layer , preserve_mode , preservation_threshold )
643678
644679 # Update the lineages.
645680 state = AnnotatorState ()
0 commit comments