Skip to content

Split confulent lesions scil_labels_from_mask#1308

Open
zinelya wants to merge 3 commits intoscilus:masterfrom
zinelya:connectivity_labels_from_mask
Open

Split confulent lesions scil_labels_from_mask#1308
zinelya wants to merge 3 commits intoscilus:masterfrom
zinelya:connectivity_labels_from_mask

Conversation

@zinelya
Copy link
Contributor

@zinelya zinelya commented Feb 11, 2026

Quick description

This PR introduces a new optional parameter --min_distance to the scil_labels_from_mask script. This feature allows the user to split "confluent" lesions—multiple lesions that have merged into a single connected component—using the Watershed algorithm.

Type of change

Check the relevant options.

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Breaking change (fix or feature that would cause existing functionality to not work as expected)
  • This change requires a documentation update

Provide data, screenshots, command line to test (if relevant)

mask.nii.gz
default_labels.nii.gz
min_dist_labels.nii.gz

image

Checklist

  • My code follows the style guidelines of this project (run autopep8)
  • I added relevant citations to scripts, modules and functions docstrings and descriptions
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas
  • I have made corresponding changes to the documentation
  • My changes generate no new warnings
  • I moved all functions from the script file (except the argparser and main) to scilpy modules
  • I have added tests that prove my fix is effective or that my feature works
  • New and existing unit tests pass locally with my changes

@codecov
Copy link

codecov bot commented Feb 11, 2026

Codecov Report

❌ Patch coverage is 38.46154% with 8 lines in your changes missing coverage. Please review.
✅ Project coverage is 72.70%. Comparing base (fc390bf) to head (e26e123).

Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1308      +/-   ##
==========================================
- Coverage   72.72%   72.70%   -0.02%     
==========================================
  Files         295      295              
  Lines       25445    25457      +12     
  Branches     3565     3566       +1     
==========================================
+ Hits        18505    18509       +4     
- Misses       5437     5443       +6     
- Partials     1503     1505       +2     
Flag Coverage Δ
smoketests 69.70% <38.46%> (-0.02%) ⬇️
unittests 13.83% <23.07%> (+<0.01%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Components Coverage Δ
Scripts 75.39% <100.00%> (+<0.01%) ⬆️
Library 69.50% <27.27%> (-0.05%) ⬇️
🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

p.add_argument('--min_volume', type=float, default=7,
help='Minimum volume in mm3 [%(default)s],'
'Useful for lesions.')
p.add_argument('--min_distance', type=int, default=None,
Copy link
Member

Choose a reason for hiding this comment

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

I think this will allow you to do what you want here:
p.add_argument('--watershed', metavar='MIN_DISTANCE', type=int, nargs='?', const=1, help='Use a watershed algorithm, if provided the parameter (default: 1 voxel) allow to ...')

This make so p.watershed is None by default, if you use --watershep it is 1 by default, but you can do --watershed 10 to change it.

min_voxel_count: int, optional
Minimum number of voxels for a blob to be considered. Blobs with fewer
voxels will be ignored.
min_distance : int, optional
Copy link
Member

Choose a reason for hiding this comment

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

I think it should be explicit in the docstring that this trigger a change to a watershed algorithm

label_map = watershed(-distance, markers, mask=mask_data)
nb_structures = np.max(label_map)
else:
label_map, nb_structures = ndi.label(mask_data)
Copy link
Member

Choose a reason for hiding this comment

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

Maybe a small comment saying "Any contigous regions touching even by a single voxel will be considered a single label"


def get_labels_from_mask(mask_data, labels=None, background_label=0,
min_voxel_count=0):
min_voxel_count=0, min_distance=0):
Copy link
Member

Choose a reason for hiding this comment

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

It would be clearer if it was None and if your condition was if min_distance is not None: later

@ThoumyreStanislas
Copy link
Contributor

Very cool extension, it works very well for me, but there are some ( small) lesions for which segmentation is a bit messy, and I don't know how to adjust the minimum distance to compensate for this. I'm having a little trouble understanding how the minimum distance system works in the algorithm. Perhaps it needs to be a little more verbose in the min distance parameter. For the code, I have nothing to add at this point other than François' comments.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants