def test_pipeline(image, algorithm_parameters, mask_property, tmp_path, use_mask): elem = SegmentationPipelineElement( segmentation=ROIExtractionProfile( name="", algorithm=algorithm_parameters["algorithm_name"], values=algorithm_parameters["values"]), mask_property=mask_property, ) algorithm_parameters = deepcopy(algorithm_parameters) algorithm_parameters["values"]["channel"] = 1 pipeline = SegmentationPipeline( name="", segmentation=ROIExtractionProfile( name="", algorithm=algorithm_parameters["algorithm_name"], values=algorithm_parameters["values"]), mask_history=[elem], ) mask = np.ones(image.get_channel(0).shape, dtype=np.uint8) if use_mask else None result = calculate_pipeline(image, mask, pipeline, lambda x, y: None) assert np.max(result.roi) == 2 pt = ProjectTuple( file_path=image.file_path, image=image, roi=result.roi, mask=result.mask, history=result.history, algorithm_parameters=algorithm_parameters, ) SaveProject.save(tmp_path / "project.tgz", pt) assert os.path.exists(tmp_path / "project.tgz") loaded = LoadProject.load([tmp_path / "project.tgz"]) assert np.all(loaded.roi == result.roi)
def save_pipeline(self): history = self._settings.get_history() if not history: QMessageBox.information(self, "No mask created", "There is no new mask created", QMessageBox.Ok) return mask_history = [] for el in history: mask = el.mask_property segmentation = ROIExtractionProfile( name="Unknown", algorithm=el.segmentation_parameters["algorithm_name"], values=el.segmentation_parameters["values"], ) new_el = SegmentationPipelineElement(mask_property=mask, segmentation=segmentation) mask_history.append(new_el) name = self._settings.last_executed_algorithm if not name: QMessageBox.information(self, "No segmentation", "No segmentation executed", QMessageBox.Ok) return values = self._settings.get(f"algorithms.{name}", {}) if len(values) == 0: QMessageBox.information(self, "Some problem", "Pleas run execution again", QMessageBox.Ok) return current_segmentation = ROIExtractionProfile(name="Unknown", algorithm=name, values=values) while True: text, ok = QInputDialog.getText(self, "Pipeline name", "Input pipeline name here") if not ok: return if text in self._settings.segmentation_pipelines: if QMessageBox.No == QMessageBox.warning( self, "Already exists", "Profile with this name already exist. Overwrite?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ): continue profile = SegmentationPipeline(name=text, segmentation=current_segmentation, mask_history=mask_history) self._settings.segmentation_pipelines[text] = profile self._settings.dump() self.choose_pipe.addItem(text) break
def test_transform_state(self, stack_segmentation1): roi_extraction_parameters = defaultdict(lambda: ROIExtractionProfile("aa", "aa", {1: "aa"})) new_state = StackSettings.transform_state( state=stack_segmentation1, new_roi_info=stack_segmentation1.roi_info, new_roi_extraction_parameters=roi_extraction_parameters, list_of_components=[4], ) assert new_state.selected_components == [1, 2, 4] assert new_state.roi_extraction_parameters[1] == stack_segmentation1.roi_extraction_parameters[1] assert new_state.roi_extraction_parameters[2] == stack_segmentation1.roi_extraction_parameters[3] assert new_state.roi_extraction_parameters[3] == ROIExtractionProfile("aa", "aa", {1: "aa"}) assert np.all((new_state.roi_info.roi == 2) == (stack_segmentation1.roi_info.roi == 3))
def mask_segmentation_parameters(): return ROIExtractionProfile( name="", algorithm="Threshold", values={ "channel": 0, "noise_filtering": { "name": "None", "values": {} }, "threshold": { "name": "Manual", "values": { "threshold": 10 } }, "close_holes": False, "close_holes_size": 200, "smooth_border": { "name": "None", "values": {} }, "side_connection": False, "minimum_size": 10000, "use_convex": False, }, )
def test_profile_preview_dialog(part_settings, register, qtbot, monkeypatch, tmp_path): elem_name = next(iter(register)) profiles = { "prof1": ROIExtractionProfile("prof1", elem_name, register[elem_name].get_default_values()), "prof2": ROIExtractionProfile("prof2", elem_name, register[elem_name].get_default_values()), } dialog = ProfilePreviewDialog(profiles, register, part_settings) qtbot.add_widget(dialog) assert dialog.profile_view.toPlainText() == "" assert dialog.profile_list.count() == 2 with qtbot.waitSignal(dialog.profile_list.currentTextChanged): dialog.profile_list.setCurrentRow(0) assert dialog.profile_list.currentItem().text() == "prof1" assert dialog.profile_view.toPlainText() != "" monkeypatch.setattr(QInputDialog, "getText", get_text_mock("prof3")) monkeypatch.setattr(CustomSaveDialog, "exec_", lambda x: True) monkeypatch.setattr( CustomSaveDialog, "get_result", lambda x: (tmp_path / "profile.json", None, SaveProfilesToJSON, SaveProfilesToJSON.get_default_values()), ) monkeypatch.setattr(ExportDialog, "exec_", lambda x: True) monkeypatch.setattr(ExportDialog, "get_export_list", lambda x: ["prof1"]) dialog.export_action() dialog.rename_action() assert "prof3" in profiles assert len(profiles) == 2 with qtbot.waitSignal(dialog.profile_list.currentTextChanged): dialog.profile_list.setCurrentRow(0) assert dialog.profile_list.currentItem().text() == "prof2" dialog.delete_action() assert len(profiles) == 1 with qtbot.waitSignal(dialog.profile_list.currentTextChanged): dialog.profile_list.setCurrentRow(0) monkeypatch.setattr(ImportDialog, "exec_", lambda x: True) monkeypatch.setattr(ImportDialog, "get_import_list", lambda x: [("prof1", "prof1")]) monkeypatch.setattr(CustomLoadDialog, "exec_", lambda x: True) monkeypatch.setattr( CustomLoadDialog, "get_result", lambda x: ([tmp_path / "profile.json"], None, LoadProfileFromJSON) ) dialog.import_action() assert len(profiles) == 2 assert dialog.profile_list.count() == 2
def test_set_segmentation_result(self, stack_settings, stack_segmentation1, stack_image): stack_settings.set_project_info(stack_image) seg = ROIExtractionResult( roi=stack_segmentation1.roi_info.roi, parameters=ROIExtractionProfile("test", "test2", {}) ) stack_settings.set_segmentation_result(seg) assert stack_settings.last_executed_algorithm == "test2" assert np.array_equal(stack_settings.roi, stack_segmentation1.roi_info.roi)
def calculation_run( self, report_fun: Callable[[str, int], None]) -> Optional[ROIExtractionResult]: if self.raise_: raise RuntimeError("ee") if self.return_none: return report_fun("text", 1) return ROIExtractionResult(np.zeros((10, 10), dtype=np.uint8), ROIExtractionProfile("a", "a", {}))
def test_update_alternative_names(self): res = ROIExtractionResult( roi=np.zeros((10, 10), dtype=np.uint8), parameters=ROIExtractionProfile("test", "test", {}), additional_layers={ "test1": AdditionalLayerDescription(np.zeros((10, 10), dtype=np.uint8), "image", "aa"), "test2": AdditionalLayerDescription(np.zeros((10, 10), dtype=np.uint8), "image", ""), }, ) assert res.additional_layers["test1"].name == "aa" assert res.additional_layers["test2"].name == "test2"
def test_transform_state_simple(self, stack_image): roi = np.zeros(stack_image.image.get_channel(0).shape, dtype=np.uint8) roi[0, 1, 2:-2, 2:-2] = 1 roi[0, 2, 2:-2, 2:-2] = 2 roi[0, 3, 2:-2, 2:-2] = 3 roi_info = ROIInfo(roi).fit_to_image(stack_image.image) roi_extraction_parameters = defaultdict(lambda: ROIExtractionProfile("aa", "aa", {1: "aa"})) new_state = StackSettings.transform_state( state=stack_image, new_roi_info=roi_info, new_roi_extraction_parameters=roi_extraction_parameters, list_of_components=[2], ) assert len(new_state.roi_extraction_parameters) == 3 assert new_state.selected_components == [2]
def create_simple_plan(root_type: RootType, save: Save): parameters = { "channel": 0, "minimum_size": 200, "threshold": { "name": "Manual", "values": { "threshold": 13000 } }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, } segmentation = ROIExtractionProfile(name="test", algorithm="Lower threshold", values=parameters) chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=-1, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( root_type, [ CalculationTree(segmentation, [ CalculationTree(statistic_calculate, []), CalculationTree(save, []) ]) ], ) return CalculationPlan(tree=tree, name="test")
def save_profile(self): widget: InteractiveAlgorithmSettingsWidget = self.algorithm_choose_widget.current_widget( ) while True: text, ok = QInputDialog.getText(self, "Profile Name", "Input profile name here") if not ok: return if text in self._settings.roi_profiles and QMessageBox.No == QMessageBox.warning( self, "Already exists", "Profile with this name already exist. Overwrite?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ): continue resp = ROIExtractionProfile(text, widget.name, widget.get_values()) self._settings.roi_profiles[text] = resp self._settings.dump() break
def save_action(self): widget: NapariInteractiveAlgorithmSettingsWidget = self.algorithm_chose.current_widget( ) profiles = self.profile_dict while True: text, ok = QInputDialog.getText(self, "Profile Name", "Input profile name here") if not ok: return # pragma: no cover if text not in profiles or QMessageBox.Yes == QMessageBox.warning( self, "Already exists", "Profile with this name already exist. Overwrite?", QMessageBox.Yes | QMessageBox.No, QMessageBox.No, ): break # pragma: no cover resp = ROIExtractionProfile(text, widget.name, widget.get_values()) profiles[text] = resp self.settings.dump() self.profile_combo_box.addItem(text) self.update_tooltips()
def test_pipeline_simple(self, use_mask): image = self.get_image() prop1 = MaskProperty( dilate=RadiusType.NO, dilate_radius=-0, fill_holes=RadiusType.NO, max_holes_size=0, save_components=False, clip_to_mask=False, ) parameters1 = { "channel": 0, "minimum_size": 30, "threshold": { "name": "Manual", "values": { "threshold": 5 } }, "noise_filtering": { "name": "None", "values": {} }, "side_connection": False, } parameters2 = { "channel": 1, "minimum_size": 30, "threshold": { "name": "Manual", "values": { "threshold": 5 } }, "noise_filtering": { "name": "None", "values": {} }, "side_connection": False, } seg_profile1 = ROIExtractionProfile(name="Unknown", algorithm="Lower threshold", values=parameters1) pipeline_element = SegmentationPipelineElement( mask_property=prop1, segmentation=seg_profile1) seg_profile2 = ROIExtractionProfile(name="Unknown", algorithm="Lower threshold", values=parameters2) pipeline = SegmentationPipeline(name="test", segmentation=seg_profile2, mask_history=[pipeline_element]) mask = np.ones(image.get_channel(0).shape, dtype=np.uint8) if use_mask else None result = calculate_pipeline(image=image, mask=mask, pipeline=pipeline, report_fun=empty) result_segmentation = np.zeros((50, 100, 100), dtype=np.uint8) result_segmentation[10:40, 20:80, 40:60] = 1 assert np.all(result.roi == result_segmentation)
def create_calculation_plan(): parameters = { "channel": 1, "minimum_size": 200, "threshold": { "name": "Base/Core", "values": { "core_threshold": { "name": "Manual", "values": { "threshold": 30000 } }, "base_threshold": { "name": "Manual", "values": { "threshold": 13000 } }, }, }, "noise_filtering": { "name": "Gauss", "values": { "dimension_type": DimensionType.Layer, "radius": 1.0 } }, "side_connection": False, "sprawl_type": { "name": "Euclidean", "values": {} }, } segmentation = ROIExtractionProfile( name="test", algorithm="Lower threshold with watershed", values=parameters) mask_suffix = MaskSuffix(name="", suffix="_mask") chosen_fields = [ MeasurementEntry( name="Segmentation Volume", calculation_tree=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), ), MeasurementEntry( name="Segmentation Volume/Mask Volume", calculation_tree=Node( left=Leaf(name="Volume", area=AreaType.ROI, per_component=PerComponent.No), op="/", right=Leaf(name="Volume", area=AreaType.Mask, per_component=PerComponent.No), ), ), MeasurementEntry( "Segmentation Components Number", calculation_tree=Leaf("Components number", area=AreaType.ROI, per_component=PerComponent.No), ), ] statistic = MeasurementProfile(name="base_measure", chosen_fields=chosen_fields, name_prefix="") statistic_calculate = MeasurementCalculate( channel=0, units=Units.µm, measurement_profile=statistic, name_prefix="") tree = CalculationTree( RootType.Image, [ CalculationTree(mask_suffix, [ CalculationTree(segmentation, [CalculationTree(statistic_calculate, [])]) ]) ], ) return CalculationPlan(tree=tree, name="test")
def lower_threshold_profile(): return ROIExtractionProfile( "lower_profile", LowerThresholdAlgorithm.get_name(), LowerThresholdAlgorithm.get_default_values())
def get_segmentation_profile(self) -> ROIExtractionProfile: return ROIExtractionProfile("", self.algorithm.get_name(), self.get_values())
def current_parameters(self) -> ROIExtractionProfile: widget = self.current_widget() return ROIExtractionProfile("", widget.name, widget.get_values())
def preview_object(self, ob: ROIExtractionProfile): text = ob.pretty_print(analysis_algorithm_dict) self.setText(text)
def border_rim_profile(): return ROIExtractionProfile("border_profile", BorderRim.get_name(), BorderRim.get_default_values())