Skip to content

Commit

Permalink
fix: Fix rendering of alternative representation if there are more co…
Browse files Browse the repository at this point in the history
…mponents in the alternative representation than in ROI (#1240)

## Summary by Sourcery

Bug Fixes:
- Fixed an issue where alternative representations with more components
than the ROI were not rendered correctly.

<!-- This is an auto-generated comment: release notes by coderabbit.ai
-->
## Summary by CodeRabbit

- **New Features**
- Enhanced ROI visualization with dynamic color assignment, providing
more accurate and flexible display when different ROI alternatives are
selected.
- Improved handling of ROI component sizing, ensuring that visual
representations adjust seamlessly based on varied component
configurations.
- Added functionality to test alternative representations of ROI data,
enhancing test coverage for component size retrieval.
- Updated project version and included new ROI entry in the project
dictionary.

- **Bug Fixes**
- Corrected logic in ROI component index retrieval for improved
accuracy.
<!-- end of auto-generated comment: release notes by coderabbit.ai -->
  • Loading branch information
Czaki authored Feb 6, 2025
1 parent d178e72 commit cc63206
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 4 deletions.
3 changes: 2 additions & 1 deletion .github/project_dict.pws
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
personal_ws-1.1 en 14
personal_ws-1.1 en 15
napari
autoupdate
aspell
Expand All @@ -13,3 +13,4 @@ bool
changelog
czi
PartSeg
ROI
6 changes: 4 additions & 2 deletions package/PartSeg/common_gui/napari_image_view.py
Original file line number Diff line number Diff line change
Expand Up @@ -483,8 +483,10 @@ def get_roi_view_parameters(self, image_info: ImageInfo) -> ColorInfo:
or colors.size == 0
):
return {0: [0, 0, 0, 0], None: [0, 0, 0, 0]}

res = {x: colors[(x - 1) % colors.shape[0]] for x in range(1, image_info.roi_count + 1)}
res = {
x: colors[(x - 1) % colors.shape[0]]
for x in range(1, image_info.roi_info.get_components_num(self.roi_alternative_selection) + 1)
}
res[0] = [0, 0, 0, 0]
res[None] = [0, 0, 0, 0]
return res
Expand Down
18 changes: 18 additions & 0 deletions package/PartSegCore/roi_info.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ def __init__(
self.roi = roi
self.bound_info = self.calc_bounds(roi)
self.sizes = np.bincount(roi.flat)
self._alternative_component_size = {}

def fit_to_image(self, image: Image) -> "ROIInfo":
if self.roi is None:
Expand All @@ -70,6 +71,23 @@ def fit_to_image(self, image: Image) -> "ROIInfo":
alternatives = {k: image.fit_array_to_image(v) for k, v in self.alternative.items()}
return ROIInfo(roi, self.annotations, alternatives)

def get_components_num(self, name):
"""
Get the number of components for a given representation.
Args:
name (str): Name of the representation. Use "ROI" for the main ROI,
or the name of an alternative representation.
Returns:
int: Maximum component number in the specified representation.
"""
if name == "ROI" or name not in self.alternative:
return max(self.bound_info)
if name not in self._alternative_component_size:
self._alternative_component_size[name] = np.max(self.alternative[name])
return self._alternative_component_size[name]

def __str__(self):
return f"ROIInfo; components: {len(self.bound_info)}, sizes: {self.sizes}"

Expand Down
17 changes: 16 additions & 1 deletion package/tests/test_PartSegCore/test_segmentation.py
Original file line number Diff line number Diff line change
Expand Up @@ -761,7 +761,7 @@ def test__convex_fill(self):
assert _convex_fill(arr) is None


class TestSegmentationInfo:
class TestROIInfo:
def test_none(self):
si = ROIInfo(None)
assert si.roi is None
Expand Down Expand Up @@ -817,6 +817,21 @@ def test_multiple_components(self, comp_num):
assert np.all(si.bound_info[1].lower == 2)
assert np.all(si.bound_info[1].upper == [10 * comp_num - 1, 8])

def test_alternative(self):
data = np.zeros((10, 10), dtype=np.uint8)
data[2:8, 2:4] = 1
data[2:8, 4:8] = 2
alt1 = np.copy(data)
alt1[data == 1] = 4
alt1[data == 2] = 1
alt2 = np.zeros((10, 10), dtype=np.uint8)

ri = ROIInfo(data, alternative={"alt1": alt1, "alt2": alt2})
assert ri.get_components_num("ROI") == 2
assert ri.get_components_num("alt1") == 4
assert ri.get_components_num("alt2") == 0
assert ri.get_components_num("alt3") == 2


def test_bound_info():
bi = BoundInfo(lower=np.array([1, 1, 1]), upper=np.array([5, 6, 7]))
Expand Down

0 comments on commit cc63206

Please sign in to comment.