def test_simple_mask(self): mask_array = np.zeros((10, 20, 20), dtype=np.uint8) mask_array[3:7, 6:14, 6:14] = 1 prop = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.NO, max_holes_size=0, save_components=False, clip_to_mask=False, ) new_mask = calculate_mask(prop, mask_array, None, (1, 1, 1)) assert np.all(new_mask == mask_array) mask_array2 = np.copy(mask_array) mask_array2[4:6, 8:12, 8:12] = 2 new_mask = calculate_mask(prop, mask_array2, None, (1, 1, 1)) assert np.all(new_mask == mask_array) prop2 = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.NO, max_holes_size=0, save_components=True, clip_to_mask=False, ) new_mask = calculate_mask(prop2, mask_array2, None, (1, 1, 1)) assert np.all(new_mask == mask_array2)
def test_fill_holes_components(self): mask_base_array = np.zeros((20, 30, 30), dtype=np.uint8) mask_base_array[4:16, 6:15, 6:24] = 1 mask_base_array[4:16, 15:24, 6:24] = 2 res_mask1 = (mask_base_array > 0).astype(np.uint8) res_mask2 = np.copy(mask_base_array) mask_base_array[6:14, 8:12, 8:22] = 0 mask_base_array[6:14, 18:22, 8:22] = 0 prop1 = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R3D, max_holes_size=0, save_components=False, clip_to_mask=False, ) prop2 = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R3D, max_holes_size=0, save_components=True, clip_to_mask=False, ) new_mask = calculate_mask(prop1, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == res_mask1) new_mask = calculate_mask(prop2, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == res_mask2) mask_base_array[6:14, 14:16, 8:22] = 0 res_mask2[6:14, 14:16, 8:22] = 0 new_mask = calculate_mask(prop1, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == res_mask1) new_mask = calculate_mask(prop2, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == res_mask2)
def test_fill_holes(self): mask_base_array = np.zeros((1, 20, 30, 30), dtype=np.uint8) mask_base_array[:, 4:16, 8:22, 8:22] = 1 mask1_array = np.copy(mask_base_array) mask1_array[:, 4:16, 10:15, 10:15] = 0 prop = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R2D, max_holes_size=0, save_components=False, clip_to_mask=False, ) new_mask = calculate_mask(prop, mask1_array, None, (1, 1, 1)) assert np.all(mask_base_array == new_mask) prop = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R3D, max_holes_size=0, save_components=False, clip_to_mask=False, ) new_mask = calculate_mask(prop, mask1_array, None, (1, 1, 1)) assert np.all(mask1_array == new_mask) mask2_array = np.copy(mask1_array) mask2_array[:, 5:15, 10:15, 17:20] = 0 new_mask = calculate_mask(prop, mask2_array, None, (1, 1, 1)) assert np.all(mask1_array == new_mask)
def test_fill_holes_size(self): mask_base_array = np.zeros((1, 20, 20, 40), dtype=np.uint8) mask_base_array[0, 2:18, 2:18, 4:36] = 1 mask_base_array[0, 4:16, 4:16, 6:18] = 0 mask1_array = np.copy(mask_base_array) mask1_array[0, 6:14, 6:14, 24:32] = 0 prop1 = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R2D, max_holes_size=70, save_components=False, clip_to_mask=False, ) prop2 = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.R3D, max_holes_size=530, save_components=True, clip_to_mask=False, ) new_mask = calculate_mask(prop1, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == mask_base_array) new_mask = calculate_mask(prop2, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == mask_base_array)
def test_reversed_mask(self): mask_base_array = np.zeros((30, 30, 30), dtype=np.uint8) mask_base_array[10:20, 10:20, 10:20] = 1 mask2_array = np.copy(mask_base_array) mask2_array[13:17, 13:17, 13:17] = 0 prop1 = MaskProperty( dilate=RadiusType.NO, dilate_radius=-0, fill_holes=RadiusType.NO, max_holes_size=0, save_components=False, clip_to_mask=False, reversed_mask=False, ) prop2 = MaskProperty( dilate=RadiusType.NO, dilate_radius=-0, fill_holes=RadiusType.NO, max_holes_size=0, save_components=False, clip_to_mask=False, reversed_mask=True, ) new_mask1 = calculate_mask(prop1, mask_base_array, mask2_array, (1, 1, 1)) new_mask2 = calculate_mask(prop2, mask_base_array, mask2_array, (1, 1, 1)) assert np.all(new_mask1 == mask_base_array) assert np.all(new_mask2 == (mask_base_array == 0))
def test_single(self): mask = np.zeros((10, 10, 10), dtype=np.uint8) mask[2:8, 2:8, 2:8] = 1 mask2 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, False, True), mask, None, (1, 1, 1)) assert np.all(mask2 == mask) mask3 = np.copy(mask) mask3[mask > 0] = 2 mask2 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, False, True), mask, None, (1, 1, 1)) assert np.all(mask2 == mask)
def test_dilate(self): mask = np.zeros((1, 10, 10, 10), dtype=np.uint8) mask[0, 2:8, 2:8, 2:8] = 1 mask2 = calculate_mask( MaskProperty(RadiusType.R3D, -1, RadiusType.NO, -1, False, True), mask, None, (1, 1, 1)) mask3 = np.zeros((1, 10, 10, 10), dtype=np.uint8) mask3[0, 3:7, 3:7, 3:7] = 1 assert np.all(mask2 == mask3) mask2 = calculate_mask( MaskProperty(RadiusType.R2D, -1, RadiusType.NO, -1, False, True), mask, None, (1, 1, 1)) mask3 = np.zeros((1, 10, 10, 10), dtype=np.uint8) mask3[0, 2:8, 3:7, 3:7] = 1 assert np.all(mask2 == mask3)
def test_mask_property_combinations(self, dilate, radius, fill_holes, max_holes_size, save_components, clip_to_mask, reversed_mask, old_mask): mask = np.zeros((1, 6, 6, 15), dtype=np.uint8) im = Image(data=mask.copy(), image_spacing=(3, 1, 1), file_path="", axes_order="TZYX") mask[:, 1:-1, 1:-1, 2:5] = 1 mask[:, 2:-2, 2:-2, 3:4] = 0 mask[:, 1:-1, 1:-1, 6:9] = 2 mask[:, 2:-2, 2:-2, 7:8] = 0 mask[:, 1:-1, 1:-1, 10:13] = 3 mask[:, 2:-2, 2:-2, 11:12] = 0 mask = im.fit_mask_to_image(mask) assert np.all(np.unique(mask.flat) == [0, 1, 2, 3]) _old_mask = np.zeros(mask.shape, dtype=mask.dtype) if old_mask else None mp = MaskProperty( dilate=dilate, dilate_radius=radius, fill_holes=fill_holes, max_holes_size=max_holes_size, save_components=save_components, clip_to_mask=clip_to_mask, reversed_mask=reversed_mask, ) mask1 = calculate_mask(mp, mask, _old_mask, im.spacing, time_axis=im.time_pos) assert mask1.shape == mask.shape
def test_save_component_fill_holes_problematic(self): mask = np.zeros((12, 12, 12), dtype=np.uint8) mask[2:7, 2:-2, 2:-2] = 3 mask[7:-2, 2:-2, 2:-2] = 2 mask[4:-4, 4:-4, 4:-4] = 1 mask2 = np.copy(mask) mask2[5, 5, 5] = 0 mask2[3, 3, 3] = 0 mask1 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R2D, -1, True, True), mask2, None, (1, 1, 1)) assert np.all(mask == mask1) mask1 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R3D, -1, True, True), mask2, None, (1, 1, 1)) assert np.all(mask == mask1)
def calculate_pipeline(image: Image, mask: typing.Optional[np.ndarray], pipeline: SegmentationPipeline, report_fun): history = [] report_fun("max", 2 * len(pipeline.mask_history) + 1) for i, el in enumerate(pipeline.mask_history): result, _ = calculate_segmentation_step(el.segmentation, image, mask) segmentation = image.fit_array_to_image(result.roi) report_fun("step", 2 * i + 1) new_mask = calculate_mask( mask_description=el.mask_property, segmentation=segmentation, old_mask=mask, spacing=image.spacing, time_axis=image.time_pos, ) segmentation_parameters = { "algorithm_name": el.segmentation.name, "values": el.segmentation.values } history.append( HistoryElement.create(segmentation, mask, segmentation_parameters, el.mask_property)) report_fun("step", 2 * i + 2) mask = image.fit_array_to_image(new_mask) result, text = calculate_segmentation_step(pipeline.segmentation, image, mask) report_fun("step", 2 * len(pipeline.mask_history) + 1) return PipelineResult(result.roi, result.additional_layers, mask, history, text)
def step_mask_create(self, operation: MaskCreate, children: List[CalculationTree]): """ Create mask from current segmentation state using definition :param MaskCreate operation: mask create description. :param List[CalculationTree] children: list of nodes to iterate over after perform segmentation """ mask = calculate_mask( mask_description=operation.mask_property, segmentation=self.segmentation, old_mask=self.mask, spacing=self.image.spacing, time_axis=self.image.time_pos, ) if operation.name in self.reused_mask: self.mask_dict[operation.name] = mask history_element = HistoryElement.create( self.segmentation, self.mask, self.algorithm_parameters, operation.mask_property, ) backup = self.mask, self.history self.mask = mask self.history.append(history_element) self.iterate_over(children) self.mask, self.history = backup
def test_fil_holes_2d(self): mask = np.zeros((10, 10, 10), dtype=np.uint8) mask[2:8, 2:8, 2:8] = 1 mask2 = np.copy(mask) mask2[:, 4:6, 4:6] = 0 mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R2D, -1, False, True), mask2, None, (1, 1, 1)) assert np.all(mask3 == mask) mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R2D, 3, False, True), mask2, None, (1, 1, 1)) assert np.all(mask3 == mask2) mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R2D, 4, False, True), mask2, None, (1, 1, 1)) assert np.all(mask3 == mask)
def test_dilate_spacing_positive(self): mask_base_array = np.zeros((1, 30, 30, 30), dtype=np.uint8) mask_base_array[:, 10:20, 10:20, 10:20] = 1 prop1 = MaskProperty( dilate=RadiusType.R3D, dilate_radius=1, fill_holes=RadiusType.NO, max_holes_size=70, save_components=False, clip_to_mask=False, ) prop2 = MaskProperty( dilate=RadiusType.R3D, dilate_radius=2, fill_holes=RadiusType.NO, max_holes_size=70, save_components=False, clip_to_mask=False, ) prop3 = MaskProperty( dilate=RadiusType.R3D, dilate_radius=3, fill_holes=RadiusType.NO, max_holes_size=70, save_components=False, clip_to_mask=False, ) res_array1 = np.zeros((30, 30, 30), dtype=np.uint8) res_array1[10:20, 9:21, 9:21] = 1 new_mask = calculate_mask(prop1, mask_base_array, None, (3, 1, 1)) assert np.all(new_mask[0] == res_array1) res_array2 = np.zeros((30, 30, 30), dtype=np.uint8) res_array2[10:20, 8:22, 8:22] = 1 res_array2[(9, 20), 9:21, 9:21] = 1 res_array2[:, (8, 21, 8, 21), (8, 8, 21, 21)] = 0 new_mask = calculate_mask(prop2, mask_base_array, None, (3, 1, 1)) assert np.all(new_mask[0] == res_array2) res_array3 = np.zeros((30, 30, 30), dtype=np.uint8) res_array3[(9, 20), 8:22, 9:21] = 1 res_array3[(9, 9, 20, 20), 9:21, (8, 21, 8, 21)] = 1 res_array3[10:20, 7:23, 9:21] = 1 res_array3[10:20, 8:22, (8, 21)] = 1 res_array3[10:20, 9:21, (7, 22)] = 1 new_mask = calculate_mask(prop3, mask_base_array, None, (3, 1, 1)) assert np.all(new_mask == res_array3)
def test_fil_holes_3d_torus(self): mask = np.zeros((1, 10, 10, 10), dtype=np.uint8) mask[0, 2:8, 2:8, 2:8] = 1 mask[0, :, 4:6, 4:6] = 0 mask2 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R3D, -1, False, True), mask, None, (1, 1, 1)) assert np.all(mask2 == mask)
def test_reverse(self): mask = np.zeros((10, 10, 10), dtype=np.uint8) mask[3:7, 3:7, 3:7] = 1 mask2 = np.ones((10, 10, 10), dtype=np.uint8) mask2[mask > 0] = 0 mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, False, True, True), mask, None, (1, 1, 1)) assert np.all(mask3 == mask2)
def test_chose_components(self): mask = np.zeros((12, 12, 12), dtype=np.uint8) mask[2:7, 2:-2, 2:-2] = 3 mask[7:-2, 2:-2, 2:-2] = 2 mask[4:-4, 4:-4, 4:-4] = 1 mask1 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.R2D, -1, True, True), mask, None, (1, 1, 1), [1, 3]) assert np.all(np.unique(mask1) == [0, 1, 3])
def test_save_components(self): mask = np.zeros((10, 10, 10), dtype=np.uint8) mask[2:8, 2:8, 2:8] = 1 mask2 = np.copy(mask) mask2[2:8, 4:6, 4:6] = 2 mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, False, True), mask2, None, (1, 1, 1)) assert np.all(mask3 == mask) mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, True, True), mask2, None, (1, 1, 1)) assert np.all(mask3 == mask2) mask4 = np.copy(mask2) mask4[mask4 == 2] = 3 mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, True, True), mask4, None, (1, 1, 1)) assert np.all(mask3 == mask4)
def test_clip(self): mask = np.zeros((10, 10, 10), dtype=np.uint8) mask[3:7, 3:7, 3:7] = 1 mask2 = calculate_mask( MaskProperty(RadiusType.R3D, 1, RadiusType.NO, -1, False, True), mask, mask, (1, 1, 1)) assert np.all(mask == mask2) mask2[:, 4:6, 4:6] = 0 mask3 = calculate_mask( MaskProperty(RadiusType.R3D, 1, RadiusType.NO, -1, False, True), mask, mask2, (1, 1, 1)) assert np.all(mask3 == mask2) mask2[:] = 0 mask2[4:6, 4:6, 4:6] = 1 mask3 = calculate_mask( MaskProperty(RadiusType.NO, 0, RadiusType.NO, -1, False, True, True), mask2, mask, (1, 1, 1)) mask[mask2 == 1] = 0 assert np.all(mask3 == mask)
def test_pipeline_manual(image, algorithm_parameters, mask_property): algorithm = analysis_algorithm_dict[ algorithm_parameters["algorithm_name"]]() algorithm.set_image(image) algorithm.set_parameters(**algorithm_parameters["values"]) result = algorithm.calculation_run(lambda x, y: None) mask = calculate_mask(mask_property, result.roi, None, image.spacing) algorithm_parameters["values"]["channel"] = 1 algorithm.set_parameters(**algorithm_parameters["values"]) algorithm.set_mask(mask) result2 = algorithm.calculation_run(lambda x, y: None) assert np.max(result2.roi) == 2
def test_time_axis(self, time): mask = np.zeros((time, 6, 6, 6), dtype=np.uint8) mask[:, 1:-1, 1:-1, 2:5] = 1 mask[:, 2:-2, 2:-2, 3:4] = 0 mp = MaskProperty( dilate=RadiusType.NO, dilate_radius=0, fill_holes=RadiusType.NO, max_holes_size=-1, save_components=False, clip_to_mask=False, ) mask1 = calculate_mask(mp, mask, None, (1, 1, 1)) assert mask1.shape == mask.shape
def test_dilate_spacing_negative(self, radius): mask_base_array = np.zeros((1, 30, 30, 30), dtype=np.uint8) mask_base_array[:, 10:20, 5:25, 5:25] = 1 res_array1 = np.zeros((1, 30, 30, 30), dtype=np.uint8) s = slice(10, 20) if radius == -1 else slice(11, 19) res_array1[:, s, 5 - radius:25 + radius, 5 - radius:25 + radius] = 1 prop1 = MaskProperty( dilate=RadiusType.R3D, dilate_radius=radius, fill_holes=RadiusType.NO, max_holes_size=70, save_components=False, clip_to_mask=False, ) new_mask = calculate_mask(prop1, mask_base_array, None, (3, 1, 1)) assert np.all(new_mask == res_array1)
def calculate_mask_from_project( mask_description: MaskProperty, project: ProjectInfoBase, components: Optional[List[int]] = None ) -> np.ndarray: """ Function for calculate mask base on MaskProperty. This function calls :py:func:`calculate_mask` with arguments from project. :param MaskProperty mask_description: information how calculate mask :param ProjectInfoBase project: project with information about segmentation :param Optional[List[int]] components: If present inform which components should be used when calculation mask, otherwise use all. :return: new mask :rtype: np.ndarray """ try: time_axis = project.image.time_pos except AttributeError: time_axis = None return calculate_mask( mask_description, project.roi_info.roi, project.mask, project.image.spacing, components, time_axis )
def create_mask(self): if self.roi_select.value is None: return layer_name = self.name.text() self.settings.set("mask_create_name", layer_name) mask_property = self.mask_widget.get_mask_property() if mask_property.clip_to_mask and self.mask_select.value is None: warnings.warn("Select base mask", RuntimeWarning) return base_mask = None if self.mask_select.value is None else self.mask_select.value.data scale = np.array(self.roi_select.value.scale) mask = np.array(calculate_mask(mask_property, self.roi_select.value.data, base_mask, scale[-3:])) if layer_name in self.viewer.layers: self.viewer.layers[layer_name].data = mask else: self.viewer.add_labels( mask, scale=scale[-int(mask.ndim) :], name=layer_name, ) self.settings.dump()
def test_dilate(self, radius_type, radius, time): mask_base_array = np.zeros((time, 30, 30, 30), dtype=np.uint8) mask_base_array[:, 10:20, 10:20, 10:20] = 1 prop1 = MaskProperty( dilate=radius_type, dilate_radius=radius, fill_holes=RadiusType.NO, max_holes_size=70, save_components=False, clip_to_mask=False, ) res_array1 = np.zeros((1, 30, 30, 30), dtype=np.uint8) slices: List[Union[int, slice]] = [slice(None)] * 4 for i in range(1, 4): slices[i] = slice(10 - radius, 20 + radius) if radius_type == RadiusType.R2D: slices[1] = slice(10, 20) res_array1[tuple(slices)] = 1 if radius_type == RadiusType.R3D: res_array1[:, (9, 9, 9, 9), (9, 9, 20, 20), (9, 20, 20, 9)] = 0 res_array1[:, (20, 20, 20, 20), (9, 9, 20, 20), (9, 20, 20, 9)] = 0 new_mask = calculate_mask(prop1, mask_base_array, None, (1, 1, 1)) assert np.all(new_mask == res_array1)