def _add_feature_source(self): self.feature_source = FeatureComboBox() self.feature_source.fill() self.feature_source.setMaximumWidth(250) widget = HWidgets("Feature:", self.feature_source, Spacing(35), stretch=1) self.add_row(widget)
def __init__(self, svid, svname, parent=None): super().__init__( title=svname, collapsible=True, removable=True, editable=True, parent=parent ) self.svid = svid self.svname = svname from survos2.frontend.plugins.features import FeatureComboBox self.svsource = FeatureComboBox() self.svsource.setMaximumWidth(250) self.svshape = LineEdit(parse=int, default=10) self.svshape.setMaximumWidth(250) self.svspacing = LineEdit3D(parse=float, default=1) self.svspacing.setMaximumWidth(250) self.svcompactness = LineEdit(parse=float, default=20) self.svcompactness.setMaximumWidth(250) self.int64_checkbox = CheckBox(checked=False) self.compute_btn = PushButton("Compute") self.view_btn = PushButton("View", accent=True) self.add_row(HWidgets("Source:", self.svsource, stretch=1)) self.add_row(HWidgets("Shape:", self.svshape, stretch=1)) self.add_row(HWidgets("Spacing:", self.svspacing, stretch=1)) self.add_row(HWidgets("Compactness:", self.svcompactness, stretch=1)) self.add_row(HWidgets("Int64:", self.int64_checkbox, stretch=1)) self.add_row(HWidgets(None, self.compute_btn)) self.add_row(HWidgets(None, self.view_btn)) self.compute_btn.clicked.connect(self.compute_supervoxels) self.view_btn.clicked.connect(self.view_regions)
def setup_feature_widgets(self): feat_group_box = QGroupBox("Features:") feat_box_layout = QGridLayout() # Labels feat_box_layout.addWidget(QLabel("Feature"), 0, 0, 1, 2) feat_box_layout.addWidget(QLabel("File type"), 0, 2) # Features combo self.feat_source = FeatureComboBox() feat_box_layout.addWidget(self.feat_source, 1, 0, 1, 2) # File type combo self.feat_ftype_combo = ComboBox() self.add_filetypes_to_combo(self.feat_ftype_combo) feat_box_layout.addWidget(self.feat_ftype_combo, 1, 2) # Button self.feat_export_btn = IconButton("fa.save", "Export data", accent=True) self.feat_export_btn.clicked.connect(self.save_feature) feat_box_layout.addWidget(self.feat_export_btn, 1, 3) feat_group_box.setLayout(feat_box_layout) return feat_group_box
class ExportPlugin(Plugin): __icon__ = "fa.qrcode" __pname__ = "export" __views__ = ["slice_viewer"] __tab__ = "export" def __init__(self, parent=None): super().__init__(parent=parent) self.vbox = VBox(self, spacing=10) feature_widgets = self.setup_feature_widgets() anno_widgets = self.setup_annotation_widgets() pipe_widgets = self.setup_pipeline_widgets() self.existing_supervoxels = {} self.vbox.addWidget(feature_widgets) self.vbox.addWidget(anno_widgets) self.vbox.addWidget(pipe_widgets) def setup_feature_widgets(self): feat_group_box = QGroupBox("Features:") feat_box_layout = QGridLayout() # Labels feat_box_layout.addWidget(QLabel("Feature"), 0, 0, 1, 2) feat_box_layout.addWidget(QLabel("File type"), 0, 2) # Features combo self.feat_source = FeatureComboBox() feat_box_layout.addWidget(self.feat_source, 1, 0, 1, 2) # File type combo self.feat_ftype_combo = ComboBox() self.add_filetypes_to_combo(self.feat_ftype_combo) feat_box_layout.addWidget(self.feat_ftype_combo, 1, 2) # Button self.feat_export_btn = IconButton("fa.save", "Export data", accent=True) self.feat_export_btn.clicked.connect(self.save_feature) feat_box_layout.addWidget(self.feat_export_btn, 1, 3) feat_group_box.setLayout(feat_box_layout) return feat_group_box def setup_annotation_widgets(self): anno_group_box = QGroupBox("Annotations:") anno_box_layout = QGridLayout() # Labels anno_box_layout.addWidget(QLabel("Annotation"), 0, 0, 1, 2) anno_box_layout.addWidget(QLabel("File type"), 0, 2) # Annotations combo self.anno_source = AnnoComboBox() anno_box_layout.addWidget(self.anno_source, 1, 0, 1, 2) # File type combo self.anno_ftype_combo = ComboBox() self.add_filetypes_to_combo(self.anno_ftype_combo) anno_box_layout.addWidget(self.anno_ftype_combo, 1, 2) # Button self.anno_export_btn = IconButton("fa.save", "Export data", accent=True) self.anno_export_btn.clicked.connect(self.save_anno) anno_box_layout.addWidget(self.anno_export_btn, 1, 3) anno_group_box.setLayout(anno_box_layout) return anno_group_box def setup_pipeline_widgets(self): pipe_group_box = QGroupBox("Pipeline output:") pipe_box_layout = QGridLayout() # Labels pipe_box_layout.addWidget(QLabel("Pipeline"), 0, 0, 1, 2) pipe_box_layout.addWidget(QLabel("File type"), 0, 2) # Pipeline combo self.pipe_source = SuperRegionSegmentComboBox() pipe_box_layout.addWidget(self.pipe_source, 1, 0, 1, 2) # File type combo self.pipe_ftype_combo = ComboBox() self.add_filetypes_to_combo(self.pipe_ftype_combo) pipe_box_layout.addWidget(self.pipe_ftype_combo, 1, 2) # Button self.pipe_export_btn = IconButton("fa.save", "Export data", accent=True) self.pipe_export_btn.clicked.connect(self.save_pipe) pipe_box_layout.addWidget(self.pipe_export_btn, 1, 3) pipe_group_box.setLayout(pipe_box_layout) return pipe_group_box def add_filetypes_to_combo(self, combo): for file_type in FILE_TYPES: combo.addItem(file_type) def save_feature(self): result = re.search(r"(\d+) (.*)", self.feat_source.currentText()) if result: fid = result.group(1) + "_" + result.group(2).lower().replace( " ", "_") logger.info(f"Feature ID: {fid}") fname_filter, ext = self.get_data_filetype(self.feat_ftype_combo) filename = result.group(2).replace(" ", "") + ext path, _ = QFileDialog.getSaveFileName(self, "Save Feature", filename, fname_filter) if path is not None and len(path) > 0: feat_data = self.get_arr_data(fid, "features") self.save_data(feat_data, path, ext) else: logger.info("No feature selected") def save_anno(self): result = re.search(r"(\d+) (.*)", self.anno_source.currentText()) if result: lid = result.group(1) + "_" + result.group(2).lower().replace( " ", "_") logger.info(f"Label ID: {lid}") fname_filter, ext = self.get_data_filetype(self.anno_ftype_combo) filename = lid + "Annotations" + ext path, _ = QFileDialog.getSaveFileName(self, "Save Annotation", filename, fname_filter) if path is not None and len(path) > 0: anno_data = self.get_arr_data(lid, "annotations") anno_data = anno_data & 15 self.save_data(anno_data.astype(np.uint8), path, ext) else: logger.info("No annotation selected") def save_pipe(self): result = re.search(r"(\d+) (\S+) (\S+)", self.pipe_source.currentText()) if result: pid = (result.group(1) + "_" + result.group(2).lower() + "_" + result.group(3).lower()) logger.info(f"Pipeline ID: {pid}") fname_filter, ext = self.get_data_filetype(self.pipe_ftype_combo) filename = pid + "Output" + ext path, _ = QFileDialog.getSaveFileName(self, "Save Pipeline Output", filename, fname_filter) if path is not None and len(path) > 0: pipe_data = self.get_arr_data(pid, "pipelines") self.save_data(pipe_data.astype(np.uint8), path, ext) else: logger.info("No pipeline selected") def get_data_filetype(self, combo_box): ftype_map = { "HDF5": ("HDF5 (*.h5 *.hdf5)", HDF_EXT), "MRC": ("MRC (*.mrc *.rec *.st)", MRC_EXT), "TIFF": ("TIFF (*.tif *.tiff)", TIFF_EXT), } return ftype_map.get(combo_box.currentText()) def get_arr_data(self, item_id, item_type): src = DataModel.g.dataset_uri(item_id, group=item_type) with DatasetManager(src, out=None, dtype="uint32", fillvalue=0) as DM: src_arr = DM.sources[0][:] return src_arr def save_data(self, data, path, ext): if ext == HDF_EXT: logger.info(f"Saving data to {path} in HDF5 format") with h5.File(path, "w") as f: f["/data"] = data elif ext == MRC_EXT: logger.info(f"Saving data to {path} in MRC format") with mrcfile.new(path, overwrite=True) as mrc: mrc.set_data(data) elif ext == TIFF_EXT: logger.info(f"Saving data to {path} in TIFF format") io.imsave(path, data)
class PipelineCard(Card): def __init__(self, fid, ftype, fname, fparams, parent=None): super().__init__(fname, removable=True, editable=True, collapsible=True, parent=parent) self.pipeline_id = fid self.pipeline_type = ftype self.pipeline_name = fname #from qtpy.QtWidgets import QProgressBar #self.pbar = QProgressBar(self) #self.add_row(self.pbar) self.params = fparams print(fparams) self.widgets = dict() if self.pipeline_type == "superregion_segment": logger.debug("Adding a superregion_segment pipeline") self._add_features_source() self._add_annotations_source() self._add_constrain_source() self._add_regions_source() self.ensembles = EnsembleWidget() self.ensembles.train_predict.connect(self.compute_pipeline) self.svm = SVMWidget() self.svm.predict.connect(self.compute_pipeline) self._add_classifier_choice() self._add_projection_choice() self._add_param("lam", type="FloatSlider", default=0.15) self._add_confidence_choice() elif self.pipeline_type == "rasterize_points": self._add_annotations_source() self._add_feature_source() self._add_objects_source() elif self.pipeline_type == "watershed": self._add_annotations_source() self._add_feature_source() elif self.pipeline_type == "predict_segmentation_fcn": self._add_annotations_source() self._add_feature_source() self._add_workflow_file() self._add_model_type() # self._add_patch_params() elif self.pipeline_type == "label_postprocess": self._add_annotations_source(label="Layer Over: ") self._add_annotations_source2(label="Layer Base: ") self.label_index = LineEdit(default=-1, parse=int) #widget = HWidgets("Selected label:", self.label_index, Spacing(35), stretch=1) #self.add_row(widget) #self.offset = LineEdit(default=-1, parse=int) #widget2 = HWidgets("Offset:", self.offset, Spacing(35), stretch=1) #self.add_row(widget2) elif self.pipeline_type == "cleaning": # self._add_objects_source() self._add_feature_source() self._add_annotations_source() elif self.pipeline_type == "train_2d_unet": self._add_annotations_source() self._add_feature_source() self._add_unet_2d_training_params() elif self.pipeline_type == "predict_2d_unet": self._add_annotations_source() self._add_feature_source() self._add_unet_2d_prediction_params() else: logger.debug(f"Unsupported pipeline type {self.pipeline_type}.") for pname, params in fparams.items(): if pname not in ["src", "dst"]: self._add_param(pname, **params) self._add_compute_btn() self._add_view_btn() def _add_model_type(self): self.model_type = ComboBox() self.model_type.addItem(key="unet3d") self.model_type.addItem(key="fpn3d") widget = HWidgets("Model type:", self.model_type, Spacing(35), stretch=0) self.add_row(widget) def _add_patch_params(self): self.patch_size = LineEdit3D(default=64, parse=int) self.add_row( HWidgets("Patch Size:", self.patch_size, Spacing(35), stretch=1)) def _add_unet_2d_training_params(self): self.add_row(HWidgets("Training Parameters:", Spacing(35), stretch=1)) self.cycles_frozen = LineEdit(default=8, parse=int) self.cycles_unfrozen = LineEdit(default=5, parse=int) self.add_row( HWidgets("No. Cycles Frozen:", self.cycles_frozen, "No. Cycles Unfrozen", self.cycles_unfrozen, stretch=1)) def _add_unet_2d_prediction_params(self): self.model_file_line_edit = LineEdit(default="Filepath", parse=str) model_input_btn = PushButton("Select Model", accent=True) model_input_btn.clicked.connect(self.get_model_path) self.radio_group = QtWidgets.QButtonGroup() self.radio_group.setExclusive(True) single_pp_rb = QRadioButton("Single plane") single_pp_rb.setChecked(True) self.radio_group.addButton(single_pp_rb, 1) triple_pp_rb = QRadioButton("Three plane") self.radio_group.addButton(triple_pp_rb, 3) self.add_row( HWidgets(self.model_file_line_edit, model_input_btn, Spacing(35))) self.add_row(HWidgets("Prediction Parameters:", Spacing(35), stretch=1)) self.add_row(HWidgets(single_pp_rb, triple_pp_rb, stretch=1)) def _add_workflow_file(self): self.filewidget = FileWidget(extensions="*.pt", save=False) self.add_row(self.filewidget) self.filewidget.path_updated.connect(self.load_data) def load_data(self, path): self.model_fullname = path print(f"Setting model fullname: {self.model_fullname}") def _add_view_btn(self): view_btn = PushButton("View", accent=True) view_btn.clicked.connect(self.view_pipeline) load_as_annotation_btn = PushButton("Load as annotation", accent=True) load_as_annotation_btn.clicked.connect(self.load_as_annotation) load_as_float_btn = PushButton("Load as image", accent=True) load_as_float_btn.clicked.connect(self.load_as_float) self.add_row( HWidgets(None, load_as_float_btn, load_as_annotation_btn, view_btn, Spacing(35))) def _add_refine_choice(self): self.refine_checkbox = CheckBox(checked=True) self.add_row( HWidgets("MRF Refinement:", self.refine_checkbox, Spacing(35), stretch=0)) def _add_confidence_choice(self): self.confidence_checkbox = CheckBox(checked=False) self.add_row( HWidgets("Confidence Map as Feature:", self.confidence_checkbox, Spacing(35), stretch=0)) def _add_objects_source(self): self.objects_source = ObjectComboBox(full=True) self.objects_source.fill() self.objects_source.setMaximumWidth(250) widget = HWidgets("Objects:", self.objects_source, Spacing(35), stretch=1) self.add_row(widget) def _add_classifier_choice(self): self.classifier_type = ComboBox() self.classifier_type.addItem(key="Ensemble") self.classifier_type.addItem(key="SVM") widget = HWidgets("Classifier:", self.classifier_type, Spacing(35), stretch=0) self.classifier_type.currentIndexChanged.connect( self._on_classifier_changed) self.clf_container = QtWidgets.QWidget() clf_vbox = VBox(self, spacing=4) clf_vbox.setContentsMargins(0, 0, 0, 0) self.clf_container.setLayout(clf_vbox) self.add_row(widget) self.add_row(self.clf_container, max_height=500) self.clf_container.layout().addWidget(self.ensembles) def _on_classifier_changed(self, idx): if idx == 0: self.clf_container.layout().addWidget(self.ensembles) self.svm.setParent(None) elif idx == 1: self.clf_container.layout().addWidget(self.svm) self.ensembles.setParent(None) def _add_projection_choice(self): self.projection_type = ComboBox() self.projection_type.addItem(key="None") self.projection_type.addItem(key="pca") self.projection_type.addItem(key="rbp") self.projection_type.addItem(key="rproj") self.projection_type.addItem(key="std") widget = HWidgets("Projection:", self.projection_type, Spacing(35), stretch=0) self.add_row(widget) def _add_feature_source(self): self.feature_source = FeatureComboBox() self.feature_source.fill() self.feature_source.setMaximumWidth(250) widget = HWidgets("Feature:", self.feature_source, Spacing(35), stretch=1) self.add_row(widget) def _add_features_source(self): self.features_source = MultiSourceComboBox() self.features_source.fill() self.features_source.setMaximumWidth(250) cfg.pipelines_features_source = self.features_source widget = HWidgets("Features:", self.features_source, Spacing(35), stretch=1) self.add_row(widget) def _add_constrain_source(self): print(self.annotations_source.value()) self.constrain_mask_source = AnnotationComboBox(header=(None, "None"), full=True) self.constrain_mask_source.fill() self.constrain_mask_source.setMaximumWidth(250) widget = HWidgets("Constrain mask:", self.constrain_mask_source, Spacing(35), stretch=1) self.add_row(widget) def _add_annotations_source(self, label="Annotation"): self.annotations_source = LevelComboBox(full=True) self.annotations_source.fill() self.annotations_source.setMaximumWidth(250) widget = HWidgets(label, self.annotations_source, Spacing(35), stretch=1) self.add_row(widget) def _add_annotations_source2(self, label="Annotation 2"): self.annotations_source2 = LevelComboBox(full=True) self.annotations_source2.fill() self.annotations_source2.setMaximumWidth(250) widget = HWidgets(label, self.annotations_source2, Spacing(35), stretch=1) self.add_row(widget) def _add_pipelines_source(self): self.pipelines_source = PipelinesComboBox() self.pipelines_source.fill() self.pipelines_source.setMaximumWidth(250) widget = HWidgets("Segmentation:", self.pipelines_source, Spacing(35), stretch=1) self.add_row(widget) def _add_regions_source(self): self.regions_source = RegionComboBox(full=True) # SourceComboBox() self.regions_source.fill() self.regions_source.setMaximumWidth(250) widget = HWidgets("Superregions:", self.regions_source, Spacing(35), stretch=1) cfg.pipelines_regions_source = self.regions_source self.add_row(widget) def _add_param(self, name, title=None, type="String", default=None): if type == "Int": p = LineEdit(default=0, parse=int) elif type == "FloatSlider": p = RealSlider(value=0.0, vmax=1, vmin=0) title = "MRF Refinement Amount:" elif type == "Float": p = LineEdit(default=0.0, parse=float) title = title elif type == "FloatOrVector": p = LineEdit3D(default=0, parse=float) elif type == "IntOrVector": p = LineEdit3D(default=0, parse=int) elif type == "SmartBoolean": p = CheckBox(checked=True) else: p = None if title is None: title = name if p: self.widgets[name] = p self.add_row(HWidgets(None, title, p, Spacing(35))) def _add_compute_btn(self): compute_btn = PushButton("Compute", accent=True) compute_btn.clicked.connect(self.compute_pipeline) self.add_row(HWidgets(None, compute_btn, Spacing(35))) def update_params(self, params): logger.debug(f"Pipeline update params {params}") for k, v in params.items(): if k in self.widgets: self.widgets[k].setValue(v) if "anno_id" in params: if params["anno_id"] is not None: self.annotations_source.select( os.path.join("annotations/", params["anno_id"])) if "object_id" in params: if params["object_id"] is not None: self.objects_source.select( os.path.join("objects/", params["object_id"])) if "feature_id" in params: for source in params["feature_id"]: self.feature_source.select(os.path.join("features/", source)) if "feature_ids" in params: for source in params["feature_ids"]: self.features_source.select(os.path.join("features/", source)) if "region_id" in params: if params["region_id"] is not None: self.regions_source.select( os.path.join("regions/", params["region_id"])) if "constrain_mask" in params: if (params["constrain_mask"] is not None and params["constrain_mask"] != "None"): import ast constrain_mask_dict = ast.literal_eval( params["constrain_mask"]) print(constrain_mask_dict) constrain_mask_source = (constrain_mask_dict["level"] + ":" + str(constrain_mask_dict["idx"])) print(f"Constrain mask source {constrain_mask_source}") self.constrain_mask_source.select(constrain_mask_source) def card_deleted(self): params = dict(pipeline_id=self.pipeline_id, workspace=True) result = Launcher.g.run("pipelines", "remove", **params) if result["done"]: self.setParent(None) _PipelineNotifier.notify() cfg.ppw.clientEvent.emit({ "source": "pipelines", "data": "remove_layer", "layer_name": self.pipeline_id, }) def view_pipeline(self): logger.debug(f"View pipeline_id {self.pipeline_id}") with progress(total=2) as pbar: pbar.set_description("Viewing feature") pbar.update(1) if self.annotations_source: if self.annotations_source.value(): level_id = str(self.annotations_source.value().rsplit( "/", 1)[-1]) else: level_id = '001_level' logger.debug(f"Assigning annotation level {level_id}") cfg.ppw.clientEvent.emit({ "source": "pipelines", "data": "view_pipeline", "pipeline_id": self.pipeline_id, "level_id": level_id, }) pbar.update(1) def get_model_path(self): workspace_path = os.path.join(DataModel.g.CHROOT, DataModel.g.current_workspace) self.model_path, _ = QtWidgets.QFileDialog.getOpenFileName( self, ("Select model"), workspace_path, ("Model files (*.zip)")) self.model_file_line_edit.setValue(self.model_path) def load_as_float(self): logger.debug(f"Loading prediction {self.pipeline_id} as float image.") # get pipeline output src = DataModel.g.dataset_uri(self.pipeline_id, group="pipelines") with DatasetManager(src, out=None, dtype="uint32", fillvalue=0) as DM: src_arr = DM.sources[0][:] # create new float image params = dict(feature_type="raw", workspace=True) result = Launcher.g.run("features", "create", **params) if result: fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug( f"Created new object in workspace {fid}, {ftype}, {fname}") dst = DataModel.g.dataset_uri(fid, group="features") with DatasetManager(dst, out=dst, dtype="float32", fillvalue=0) as DM: DM.out[:] = src_arr cfg.ppw.clientEvent.emit({ "source": "workspace_gui", "data": "refresh", "value": None }) def load_as_annotation(self): logger.debug(f"Loading prediction {self.pipeline_id} as annotation.") # get pipeline output src = DataModel.g.dataset_uri(self.pipeline_id, group="pipelines") with DatasetManager(src, out=None, dtype="uint32", fillvalue=0) as DM: src_arr = DM.sources[0][:] label_values = np.unique(src_arr) # create new level params = dict(level=self.pipeline_id, workspace=True) result = Launcher.g.run("annotations", "add_level", workspace=True) # create a blank label for each unique value in the pipeline output array if result: level_id = result["id"] for v in label_values: params = dict( level=level_id, idx=int(v), name=str(v), color="#11FF11", workspace=True, ) label_result = Launcher.g.run("annotations", "add_label", **params) params = dict( level=str(self.annotations_source.value().rsplit("/", 1)[-1]), workspace=True, ) anno_result = Launcher.g.run("annotations", "get_levels", **params)[0] params = dict(level=str(level_id), workspace=True) level_result = Launcher.g.run("annotations", "get_levels", **params)[0] try: # set the new level color mapping to the mapping from the pipeline for v in level_result["labels"].keys(): if v in anno_result["labels"]: label_hex = anno_result["labels"][v]["color"] label = dict( idx=int(v), name=str(v), color=label_hex, ) params = dict(level=result["id"], workspace=True) label_result = Launcher.g.run("annotations", "update_label", **params, **label) except Exception as err: logger.debug(f"Exception {err}") fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug( f"Created new object in workspace {fid}, {ftype}, {fname}") # set levels array to pipeline output array dst = DataModel.g.dataset_uri(fid, group="annotations") with DatasetManager(dst, out=dst, dtype="uint32", fillvalue=0) as DM: DM.out[:] = src_arr cfg.ppw.clientEvent.emit({ "source": "workspace_gui", "data": "refresh", "value": None }) def setup_params_superregion_segment(self, dst): feature_names_list = [ n.rsplit("/", 1)[-1] for n in self.features_source.value() ] src_grp = None if self.annotations_source.currentIndex( ) == 0 else "pipelines" src = DataModel.g.dataset_uri( self.annotations_source.value().rsplit("/", 1)[-1], group="annotations", ) all_params = dict(src=src, modal=True) all_params["workspace"] = DataModel.g.current_workspace logger.info(f"Setting src to {self.annotations_source.value()} ") all_params["region_id"] = str(self.regions_source.value().rsplit( "/", 1)[-1]) all_params["feature_ids"] = feature_names_list all_params["anno_id"] = str(self.annotations_source.value().rsplit( "/", 1)[-1]) if self.constrain_mask_source.value() != None: all_params["constrain_mask"] = self.constrain_mask_source.value( ) # .rsplit("/", 1)[-1] else: all_params["constrain_mask"] = "None" all_params["dst"] = dst all_params["refine"] = self.widgets["refine"].value() all_params["lam"] = self.widgets["lam"].value() all_params["classifier_type"] = self.classifier_type.value() all_params["projection_type"] = self.projection_type.value() all_params["confidence"] = self.confidence_checkbox.value() if self.classifier_type.value() == "Ensemble": all_params["classifier_params"] = self.ensembles.get_params() else: all_params["classifier_params"] = self.svm.get_params() return all_params def setup_params_rasterize_points(self, dst): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") all_params = dict(src=src, modal=True) all_params["workspace"] = DataModel.g.current_workspace # all_params["anno_id"] = str( # self.annotations_source.value().rsplit("/", 1)[-1] # ) all_params["feature_id"] = self.feature_source.value() all_params["object_id"] = str(self.objects_source.value()) all_params["acwe"] = self.widgets["acwe"].value() # all_params["object_scale"] = self.widgets["object_scale"].value() # all_params["object_offset"] = self.widgets["object_offset"].value() all_params["dst"] = dst return all_params def setup_params_watershed(self, dst): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") all_params = dict(src=src, dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["dst"] = self.pipeline_id all_params["anno_id"] = str(self.annotations_source.value().rsplit( "/", 1)[-1]) return all_params def setup_params_predict_segmentation_fcn(self, dst): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") all_params = dict(src=src, dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["anno_id"] = str(self.annotations_source.value().rsplit( "/", 1)[-1]) all_params["feature_id"] = self.feature_source.value() all_params["model_fullname"] = self.model_fullname all_params["model_type"] = self.model_type.value() all_params["dst"] = self.pipeline_id return all_params def setup_params_label_postprocess(self, dst): all_params = dict(modal=True) all_params["workspace"] = DataModel.g.current_workspace print(self.annotations_source.value()) if (self.annotations_source.value()): all_params["level_over"] = str( self.annotations_source.value().rsplit("/", 1)[-1]) else: all_params["level_over"] = "None" all_params["level_base"] = str(self.annotations_source2.value().rsplit( "/", 1)[-1]) all_params["dst"] = dst #all_params["selected_label"] = int(self.label_index.value()) #all_params["offset"] = int(self.offset.value()) all_params["selected_label"] = int( self.widgets["selected_label"].value()) all_params["offset"] = int(self.widgets["offset"].value()) return all_params def setup_params_cleaning(self, dst): all_params = dict(dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) # all_params["object_id"] = str(self.objects_source.value()) return all_params def setup_params_train_2d_unet(self, dst): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") all_params = dict(src=src, dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) all_params["anno_id"] = str(self.annotations_source.value().rsplit( "/", 1)[-1]) all_params["unet_train_params"] = dict( cyc_frozen=self.cycles_frozen.value(), cyc_unfrozen=self.cycles_unfrozen.value()) return all_params def setup_params_predict_2d_unet(self, dst): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") all_params = dict(src=src, dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) all_params["anno_id"] = str(self.annotations_source.value().rsplit( "/", 1)[-1]) all_params["model_path"] = str(self.model_file_line_edit.value()) all_params["no_of_planes"] = self.radio_group.checkedId() return all_params def compute_pipeline(self): dst = DataModel.g.dataset_uri(self.pipeline_id, group="pipelines") with progress(total=3) as pbar: pbar.set_description("Calculating pipeline") pbar.update(1) try: if self.pipeline_type == "superregion_segment": all_params = self.setup_params_superregion_segment(dst) elif self.pipeline_type == "rasterize_points": all_params = self.setup_params_rasterize_points(dst) elif self.pipeline_type == "watershed": all_params = self.setup_params_watershed(dst) elif self.pipeline_type == "predict_segmentation_fcn": all_params = self.setup_params_predict_segmentation_fcn( dst) elif self.pipeline_type == "label_postprocess": all_params = self.setup_params_label_postprocess(dst) elif self.pipeline_type == "cleaning": all_params = self.setup_params_cleaning(dst) elif self.pipeline_type == "train_2d_unet": all_params = self.setup_params_train_2d_unet(dst) elif self.pipeline_type == "predict_2d_unet": all_params = self.setup_params_predict_2d_unet(dst) else: logger.warning( f"No action exists for pipeline: {self.pipeline_type}") all_params.update( {k: v.value() for k, v in self.widgets.items()}) logger.info( f"Computing pipelines {self.pipeline_type} {all_params}") try: pbar.update(1) result = Launcher.g.run("pipelines", self.pipeline_type, **all_params) print(result) except Exception as err: print(err) if result is not None: pbar.update(1) except Exception as e: print(e) def card_title_edited(self, newtitle): params = dict(pipeline_id=self.pipeline_id, new_name=newtitle, workspace=True) result = Launcher.g.run("pipelines", "rename", **params) if result["done"]: _PipelineNotifier.notify() return result["done"]
class AnalyzerCard(Card): def __init__(self, analyzer_id, analyzer_name, analyzer_type, parent=None): super().__init__( title=analyzer_name, collapsible=True, removable=True, editable=True, parent=parent, ) self.analyzer_id = analyzer_id self.analyzer_name = analyzer_name self.analyzer_type = analyzer_type self.annotations_source = ( "001_level" # default annotation level to use for labels ) additional_buttons = [] self.annotations_selected = False self.op_cards = [] if self.analyzer_type == "label_splitter": # radio buttons to select source type self.radio_group = QtWidgets.QButtonGroup() self.radio_group.setExclusive(True) pipelines_rb = QRadioButton("Pipelines") pipelines_rb.setChecked(True) pipelines_rb.toggled.connect(self._pipelines_rb_checked) self.radio_group.addButton(pipelines_rb, 1) analyzers_rb = QRadioButton("Analyzers") analyzers_rb.toggled.connect(self._analyzers_rb_checked) self.radio_group.addButton(analyzers_rb, 2) annotations_rb = QRadioButton("Annotation") self.radio_group.addButton(annotations_rb, 3) annotations_rb.toggled.connect(self._annotations_rb_checked) self.add_row(HWidgets(pipelines_rb, analyzers_rb, annotations_rb)) self.source_container = QtWidgets.QWidget() source_vbox = VBox(self, spacing=4) source_vbox.setContentsMargins(0, 0, 0, 0) self.source_container.setLayout(source_vbox) self.add_row(self.source_container) self.pipelines_source = PipelinesComboBox() self.pipelines_source.fill() self.pipelines_source.setMaximumWidth(250) self.pipelines_widget = HWidgets( "Segmentation:", self.pipelines_source, Spacing(35), stretch=1 ) self.pipelines_widget.setParent(None) self.annotations_source = LevelComboBox(full=True) self.annotations_source.fill() self.annotations_source.setMaximumWidth(250) self.annotations_widget = HWidgets("Annotation", self.annotations_source, Spacing(35), stretch=1) self.annotations_widget.setParent(None) self.analyzers_source = AnalyzersComboBox() self.analyzers_source.fill() self.analyzers_source.setMaximumWidth(250) self.analyzers_widget = HWidgets( "Analyzers:", self.analyzers_source, Spacing(35), stretch=1 ) self.analyzers_widget.setParent(None) self.source_container.layout().addWidget(self.pipelines_widget) self.current_widget = self.pipelines_widget self._add_feature_source() self.background_label = LineEdit(default=0, parse=float) widget = HWidgets("Background label:", self.background_label, Spacing(35), stretch=1) self.add_row(widget) self.add_rules_btn = PushButton("Add Rule") self.add_rules_btn.clicked.connect(self._add_rule) self.refresh_rules_btn = PushButton("Refresh plots") self.refresh_rules_btn.clicked.connect(self._setup_ops) widget = HWidgets(self.add_rules_btn, self.refresh_rules_btn,Spacing(35),stretch=0) self.add_row(widget) self.export_csv_btn = PushButton("Export CSV") self.load_as_objects_btn = PushButton("Load as Objects") self.add_row(HWidgets(None, self.load_as_objects_btn, self.export_csv_btn, Spacing(35))) self.load_as_objects_btn.clicked.connect(self.load_as_objects) self.export_csv_btn.clicked.connect(self.export_csv) self.feature_name_combo_box = SimpleComboBox( full=True, values=feature_names ) self.feature_name_combo_box.fill() self.add_row(HWidgets("Explore feature name: ", self.feature_name_combo_box, Spacing(35),stretch=0)) self._add_view_btn() elif self.analyzer_type == "image_stats": self._add_features_source() self.plot_btn = PushButton("Plot") additional_buttons.append(self.plot_btn) self.plot_btn.clicked.connect(self.clustering_plot) elif self.analyzer_type == "level_image_stats": self._add_annotations_source() self.statistic_name_combo_box = SimpleComboBox( full=True, values=["Mean", "Std", "Var"] ) widget = HWidgets( "Statistic:", self.statistic_name_combo_box, Spacing(35), stretch=1 ) self.add_row(widget) self.label_index = LineEdit(default=1, parse=float) widget = HWidgets("Level index:", self.label_index, Spacing(35), stretch=1) self.add_row(widget) elif self.analyzer_type == "binary_image_stats": self._add_feature_source() self.threshold = LineEdit(default=0.5, parse=float) widget = HWidgets("Threshold:", self.threshold, Spacing(35), stretch=1) self.add_row(widget) self.load_as_objects_btn = PushButton("Load as Objects") additional_buttons.append(self.load_as_objects_btn) self.load_as_objects_btn.clicked.connect(self.load_as_objects) elif self.analyzer_type == "object_stats": self._add_features_source() self._add_objects_source() self.stat_name_combo_box = SimpleComboBox( full=True, values=["Mean", "Std", "Var"] ) self.stat_name_combo_box.fill() widget = HWidgets( "Statistic name:", self.stat_name_combo_box, Spacing(35), stretch=1 ) self.add_row(widget) elif self.analyzer_type == "object_detection_stats": self._add_features_source() self._add_object_detection_stats_source() elif self.analyzer_type == "find_connected_components": additional_buttons.append(self._add_pipelines_source2()) self.label_index = LineEdit(default=0, parse=int) widget = HWidgets("Label Index:", self.label_index, Spacing(35), stretch=1) self.add_row(widget) self.load_as_objects_btn = additional_buttons[-1] self.load_as_objects_btn.clicked.connect(self.load_as_objects) self._add_view_btn() elif self.analyzer_type == "detector_predict": self._add_features_source() self._add_objects_source() self._add_model_file() elif self.analyzer_type == "remove_masked_objects": self._add_feature_source() self._add_objects_source() self.load_as_objects_btn = PushButton("Load as Objects") additional_buttons.append(self.load_as_objects_btn) self.load_as_objects_btn.clicked.connect(self.load_as_objects) elif self.analyzer_type == "spatial_clustering": self._add_feature_source() self._add_objects_source() self.eps = LineEdit(default=0.1, parse=float) widget = HWidgets("DBScan EPS:", self.eps, Spacing(35), stretch=1) self.add_row(widget) self.load_as_objects_btn = PushButton("Load as Objects") additional_buttons.append(self.load_as_objects_btn) self.load_as_objects_btn.clicked.connect(self.load_as_objects) self.calc_btn = PushButton("Compute") self.add_row(HWidgets(None, self.calc_btn, Spacing(35))) if len(additional_buttons) > 0: self.add_row(HWidgets(None, *additional_buttons, Spacing(35))) self.calc_btn.clicked.connect(self.calculate_analyzer) self.table_control = None self.plots = [] def _pipelines_rb_checked(self, enabled): if enabled: self.source_container.layout().addWidget(self.pipelines_widget) if self.current_widget: self.current_widget.setParent(None) self.current_widget = self.pipelines_widget self.annotations_selected = False def _analyzers_rb_checked(self, enabled): if enabled: self.source_container.layout().addWidget(self.analyzers_widget) if self.current_widget: self.current_widget.setParent(None) self.current_widget = self.analyzers_widget self.annotations_selected = False def _annotations_rb_checked(self, enabled): if enabled: self.source_container.layout().addWidget(self.annotations_widget) if self.current_widget: self.current_widget.setParent(None) self.current_widget = self.annotations_widget self.annotations_selected = True def _setup_ops(self): print(f"Current number of op cards {len(self.op_cards)}") if self.table_control: self.table_control.w.setParent(None) self.table_control = None if len(self.plots) > 0: for plot in self.plots: plot.setParent(None) plot = None self.plots = [] #self.clear_widgets() def _add_rule(self): op_card = RuleCard(title="Rule", editable=True, collapsible=False, removable=True, parent=self) self.op_cards.append(op_card) self.add_row(op_card) self.add_to_widget_list(op_card) def _add_model_file(self): self.filewidget = FileWidget(extensions="*.pt", save=False) self.add_row(self.filewidget) self.filewidget.path_updated.connect(self.load_data) def load_data(self, path): self.model_fullname = path print(f"Setting model fullname: {self.model_fullname}") def load_as_objects(self): logger.debug("Load analyzer result as objects") from survos2.entity.entities import load_entities_via_file load_entities_via_file(self.entities_arr, flipxy=False) cfg.ppw.clientEvent.emit( {"source": "analyzer_plugin", "data": "refresh", "value": None} ) def _add_objects_source(self): self.objects_source = ObjectComboBox(full=True) self.objects_source.fill() self.objects_source.setMaximumWidth(250) widget = HWidgets("Objects:", self.objects_source, Spacing(35), stretch=1) self.add_row(widget) def _add_object_detection_stats_source(self): self.gold_objects_source = ObjectComboBox(full=True) self.gold_objects_source.fill() self.gold_objects_source.setMaximumWidth(250) widget = HWidgets( "Gold Objects:", self.gold_objects_source, Spacing(35), stretch=1 ) self.add_row(widget) self.predicted_objects_source = ObjectComboBox(full=True) self.predicted_objects_source.fill() self.predicted_objects_source.setMaximumWidth(250) widget = HWidgets( "Predicted Objects:", self.predicted_objects_source, Spacing(35), stretch=1 ) self.add_row(widget) def _add_annotations_source(self, label="Annotation"): self.annotations_source = LevelComboBox(full=True) self.annotations_source.fill() self.annotations_source.setMaximumWidth(250) widget = HWidgets(label, self.annotations_source, Spacing(35), stretch=1) self.add_row(widget) def _add_pipelines_source(self): self.pipelines_source = PipelinesComboBox() self.pipelines_source.fill() self.pipelines_source.setMaximumWidth(250) widget = HWidgets( "Segmentation:", self.pipelines_source, Spacing(35), stretch=1 ) self.add_row(widget) def _add_pipelines_source2(self): self.pipelines_source = PipelinesComboBox() self.pipelines_source.fill() self.pipelines_source.setMaximumWidth(250) widget = HWidgets( "Segmentation:", self.pipelines_source, Spacing(35), stretch=1 ) self.add_row(widget) load_as_objects = PushButton("Load as Objects") return load_as_objects def _add_analyzers_source(self): self.analyzers_source = AnalyzersComboBox() self.analyzers_source.fill() self.analyzers_source.setMaximumWidth(250) widget = HWidgets( "Analyzers:", self.analyzers_source, Spacing(35), stretch=1 ) self.add_row(widget) def _add_feature_source(self): self.feature_source = FeatureComboBox() self.feature_source.fill() self.feature_source.setMaximumWidth(250) widget = HWidgets("Feature:", self.feature_source, Spacing(35), stretch=1) self.add_row(widget) def _add_features_source(self): self.features_source = MultiSourceComboBox() self.features_source.fill() self.features_source.setMaximumWidth(250) widget = HWidgets("Features:", self.features_source, Spacing(35), stretch=1) self.add_row(widget) def _add_view_btn(self): view_btn = PushButton("View", accent=True) view_btn.clicked.connect(self.view_analyzer) load_as_annotation_btn = PushButton("Load as annotation", accent=True) load_as_annotation_btn.clicked.connect(self.load_as_annotation) load_as_float_btn = PushButton("Load as feature", accent=True) load_as_float_btn.clicked.connect(self.load_as_float) self.add_row( HWidgets( None, load_as_float_btn, load_as_annotation_btn, view_btn, Spacing(35) ) ) def view_analyzer(self): logger.debug(f"View analyzer_id {self.analyzer_id}") with progress(total=2) as pbar: pbar.set_description("Viewing analyzer") pbar.update(1) if self.annotations_source: if self.annotations_selected: level_id = self.annotations_source.value().rsplit("/", 1)[-1] else: level_id = "001_level" logger.debug(f"Assigning annotation level {level_id}") cfg.ppw.clientEvent.emit( { "source": "analyzer", "data": "view_pipeline", "pipeline_id": self.analyzer_id, "level_id": level_id, } ) pbar.update(1) def load_as_float(self): logger.debug(f"Loading analyzer result {self.analyzer_id} as float image.") # get analyzer output src = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") with DatasetManager(src, out=None, dtype="uint32", fillvalue=0) as DM: src_arr = DM.sources[0][:] # create new float image params = dict(feature_type="raw", workspace=True) result = Launcher.g.run("features", "create", **params) if result: fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug(f"Created new object in workspace {fid}, {ftype}, {fname}") dst = DataModel.g.dataset_uri(fid, group="features") with DatasetManager(dst, out=dst, dtype="float32", fillvalue=0) as DM: DM.out[:] = src_arr cfg.ppw.clientEvent.emit( {"source": "workspace_gui", "data": "refresh", "value": None} ) def load_as_annotation(self): logger.debug(f"Loading analyzer result {self.analyzer_id} as annotation.") # get analyzer output src = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") with DatasetManager(src, out=None, dtype="uint32", fillvalue=0) as DM: src_arr = DM.sources[0][:] label_values = np.unique(src_arr) # create new level params = dict(level=self.analyzer_id, workspace=True) result = Launcher.g.run("annotations", "add_level", workspace=True) # create a blank label for each unique value in the analyzer output array if result: level_id = result["id"] for v in label_values: params = dict( level=level_id, idx=int(v), name=str(v), color="#11FF11", workspace=True, ) label_result = Launcher.g.run("annotations", "add_label", **params) # derive label colours from given annotation params = dict( level=str("001_level"), workspace=True, ) anno_result = Launcher.g.run("annotations", "get_levels", **params)[0] params = dict(level=str(level_id), workspace=True) level_result = Launcher.g.run("annotations", "get_levels", **params)[0] try: # set the new level color mapping to the mapping from the given annotation for v in level_result["labels"].keys(): if v in anno_result["labels"]: label_hex = anno_result["labels"][v]["color"] label = dict( idx=int(v), name=str(v), color=label_hex, ) params = dict(level=result["id"], workspace=True) label_result = Launcher.g.run( "annotations", "update_label", **params, **label ) except Exception as err: logger.debug(f"Exception {err}") fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug(f"Created new object in workspace {fid}, {ftype}, {fname}") dst = DataModel.g.dataset_uri(fid, group="annotations") with DatasetManager(dst, out=dst, dtype="uint32", fillvalue=0) as DM: DM.out[:] = src_arr cfg.ppw.clientEvent.emit( {"source": "workspace_gui", "data": "refresh", "value": None} ) def card_deleted(self): params = dict(analyzer_id=self.analyzer_id, workspace=True) result = Launcher.g.run("analyzer", "remove", **params) if result["done"]: self.setParent(None) def card_title_edited(self, newtitle): logger.debug(f"Edited analyzer title {newtitle}") params = dict(analyzer_id=self.analyzer_id, new_name=newtitle, workspace=True) result = Launcher.g.run("analyzer", "rename", **params) return result["done"] def update_params(self, params): logger.debug(f"Analyzer update params {params}") # for k, v in params.items(): # if k in self.widgets: # self.widgets[k].setValue(v) def display_splitter_results(self, result): entities = [] tabledata = [] for i in range(len(result)): entry = ( i, result[i][0], result[i][1], result[i][2], result[i][3], result[i][4], result[i][5], result[i][6], result[i][7], result[i][8], result[i][9], result[i][10], result[i][11], result[i][12], result[i][13], result[i][14], result[i][15], result[i][16], ) tabledata.append(entry) entity = (result[i][0], result[i][2], result[i][1], 0) entities.append(entity) tabledata = np.array( tabledata, dtype=[ ("index", int), ("z", int), ("x", int), ("y", int), ("Sum", float), ("Mean", float), ("Std", float), ("Var", float), ("BB Vol", float), ("BB Vol Log10", float), ("BB Depth", float), ("BB Height", float), ("BB Width", float), ("OrientBB Vol", float), ("OrientBB Vol Log10", float), ("OrientBB Depth", float), ("OrientBB Height", float), ("OrientBB Width", float), ], ) if self.table_control is None: self.table_control = TableWidget() max_height = 500 self.table_control.w.setProperty("header", False) self.table_control.w.setMaximumHeight(max_height) self.vbox.addWidget(self.table_control.w) self.total_height += 500 + self.spacing self.setMinimumHeight(self.total_height) self.table_control.set_data(tabledata) self.collapse() self.expand() self.tabledata = tabledata self.entities_arr = np.array(entities) def display_component_results(self, result): entities = [] tabledata = [] for i in range(len(result)): entry = ( i, result[i][0], result[i][1], result[i][2], result[i][3], ) tabledata.append(entry) entity = (result[i][1], result[i][2], result[i][3], 0) entities.append(entity) tabledata = np.array( tabledata, dtype=[ ("index", int), ("area", int), ("z", int), ("x", int), ("y", int), ], ) if self.table_control is None: self.table_control = TableWidget() self.add_row(self.table_control.w, max_height=500) self.table_control.set_data(tabledata) self.collapse() self.expand() self.entities_arr = np.array(entities) def display_component_results2(self, result): entities = [] tabledata = [] for i in range(len(result)): entry = ( i, result[i][0], result[i][1], result[i][2], result[i][3], ) tabledata.append(entry) entity = (result[i][1], result[i][2], result[i][3], 0) entities.append(entity) self.entities_arr = np.array(entities) def display_splitter_plot(self, feature_arrays, titles=[], vert_line_at=None): for i, feature_array in enumerate(feature_arrays): self.plots.append(MplCanvas(self, width=5, height=5, dpi=100)) max_height = 600 self.plots[i].setProperty("header", False) self.plots[i].setMaximumHeight(max_height) self.vbox.addWidget(self.plots[i]) self.total_height += 500 + self.spacing self.setMinimumHeight(self.total_height) colors = ['r','y','b','c','m','g'] y, x, _ = self.plots[i].axes.hist(feature_array, bins=16, color=colors[i]) self.plots[i].axes.set_title(titles[i]) if vert_line_at: print(f"Plotting vertical line at: {vert_line_at[i]} {y.max()}") self.plots[i].axes.axvline(x=vert_line_at[i], ymin=0, ymax=y.max(), color="k") def clustering_plot(self): src = DataModel.g.dataset_uri(self.features_source.value()) dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_ids"] = str(self.features_source.value()[-1]) all_params["object_id"] = str(self.objects_source.value()) logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "image_stats", **all_params) if result: src_arr = decode_numpy(result) sc = MplCanvas(self, width=5, height=4, dpi=100) sc.axes.imshow(src_arr) self.add_row(sc, max_height=300) def export_csv(self): full_path = QtWidgets.QFileDialog.getSaveFileName( self, "Select output filename", ".", filter="*.csv" ) if isinstance(full_path, tuple): full_path = full_path[0] out_df = pd.DataFrame(self.tabledata) out_df.to_csv(full_path) logger.debug(f"Exported to csv {full_path}") def calc_label_splitter(self): if len(self.plots) > 0: for plot in self.plots: plot.setParent(None) plot = None self.plots = [] dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.pipelines_source.value(), group="pipelines") all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["pipelines_id"] = str(self.pipelines_source.value()) all_params["feature_id"] = str(self.feature_source.value()) all_params["analyzers_id"] = str(self.analyzers_source.value()) all_params["annotations_id"] = str(self.annotations_source.value()) all_params["mode"] = self.radio_group.checkedId() all_params["background_label"] = self.background_label.value() split_ops = {} split_feature_indexes = [] split_feature_thresholds = [] if len(self.op_cards) > 0: for j, op_card in enumerate(self.op_cards): split_op = {} split_feature_index = int(op_card.feature_name_combo_box.value()) split_op["split_feature_index"] = str(split_feature_index) split_feature_indexes.append(split_feature_index) split_op["split_op"] = op_card.split_op_combo_box.value() split_op["split_threshold"] = op_card.split_threshold.value() split_feature_thresholds.append(float(op_card.split_threshold.value())) split_ops[j] = split_op else: split_op = {} split_feature_index = int(self.feature_name_combo_box.value()) split_op["split_feature_index"] = str(split_feature_index) split_feature_indexes.append(split_feature_index) split_op["split_op"] = 1 split_op["split_threshold"] = 0 split_feature_thresholds.append(0) split_ops[0] = split_op all_params["split_ops"] = split_ops logger.debug(f"Running analyzer with params {all_params}") result_features, features_array = Launcher.g.run( "analyzer", "label_splitter", **all_params ) features_ndarray = np.array(features_array) print(f"Shape of features_array {features_ndarray.shape}") if features_array: logger.debug(f"Segmentation stats result table {len(features_array)}") feature_arrays = [] feature_titles = [] for j,s in enumerate(split_feature_indexes): print(s) feature_title = feature_names[int(s)] print(feature_title) feature_plot_array = features_ndarray[:, int(s)] feature_arrays.append(feature_plot_array) feature_titles.append(feature_title) print(f"Titles of feature names{feature_titles}") print(f"Split feature thresholds: {split_feature_thresholds}") self.display_splitter_plot(feature_arrays, titles=feature_titles, vert_line_at=split_feature_thresholds) self.display_splitter_results(result_features) def calc_level_image_stats(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") anno_id = DataModel.g.dataset_uri(self.annotations_source.value()) all_params = dict(dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["anno_id"] = anno_id all_params["label_index"] = self.label_index.value() logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "level_image_stats", **all_params) if result: logger.debug(f"Level Image stats result table {len(result)}") self.display_component_results(result) def calc_find_connected_components(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.pipelines_source.value(), group="pipelines") all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["pipelines_id"] = str(self.pipelines_source.value()) all_params["label_index"] = self.label_index.value() logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run( "analyzer", "find_connected_components", **all_params ) print(result) if result: logger.debug(f"Segmentation stats result table {len(result)}") self.display_component_results(result) def calc_binary_image_stats(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.feature_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) all_params["threshold"] = self.threshold.value() logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "binary_image_stats", **all_params) if result: logger.debug(f"Segmentation stats result table {len(result)}") self.display_component_results(result) def calc_image_stats(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.features_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_ids"] = str(self.features_source.value()[-1]) logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "image_stats", **all_params) if result: src_arr = decode_numpy(result) sc = MplCanvas(self, width=5, height=4, dpi=100) sc.axes.imshow(src_arr) self.add_row(sc, max_height=300) def calc_object_stats2(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.features_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_ids"] = str(self.features_source.value()[-1]) all_params["object_id"] = str(self.objects_source.value()) logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "object_stats", **all_params) if result: src_arr = decode_numpy(result) sc = MplCanvas(self, width=5, height=4, dpi=100) sc.axes.imshow(src_arr) self.add_row(sc, max_height=300) def calc_object_stats(self): dst = DataModel.g.dataset_uri(self.analyzer_id, group="analyzer") src = DataModel.g.dataset_uri(self.features_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_ids"] = str(self.features_source.value()[-1]) all_params["object_id"] = str(self.objects_source.value()) all_params["stat_name"] = self.stat_name_combo_box.value() logger.debug(f"Running analyzer with params {all_params}") result = Launcher.g.run("analyzer", "object_stats", **all_params) (point_features, img) = result if result: logger.debug(f"Object stats result table {len(point_features)}") tabledata = [] for i in range(len(point_features)): entry = (i, point_features[i]) tabledata.append(entry) tabledata = np.array( tabledata, dtype=[ ("index", int), ("z", float), ], ) src_arr = decode_numpy(img) sc = MplCanvas(self, width=6, height=5, dpi=80) sc.axes.imshow(src_arr) sc.axes.axis("off") self.add_row(sc, max_height=500) if self.table_control is None: self.table_control = TableWidget() self.add_row(self.table_control.w, max_height=500) self.table_control.set_data(tabledata) self.collapse() self.expand() def calc_object_detection_stats(self): src = DataModel.g.dataset_uri(self.features_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["predicted_objects_id"] = str( self.predicted_objects_source.value() ) all_params["gold_objects_id"] = str(self.gold_objects_source.value()) logger.debug(f"Running object detection analyzer with params {all_params}") result = Launcher.g.run("analyzer", "object_detection_stats", **all_params) def calc_detector_predict(self): src = DataModel.g.dataset_uri( self.features_source.value()[0], group="pipelines" ) feature_names_list = [ n.rsplit("/", 1)[-1] for n in self.features_source.value() ] all_params = dict(src=src, dst=dst, modal=True) all_params["workspace"] = DataModel.g.current_workspace all_params["object_id"] = str(self.objects_source.value()) all_params["feature_ids"] = feature_names_list all_params["model_fullname"] = self.model_fullname all_params["dst"] = self.pipeline_id result = Launcher.g.run("pipelines", self.analyzer_type, **all_params) def calc_spatial_clustering(self): src = DataModel.g.dataset_uri(self.feature_source.value()) all_params = dict(src=src, dst=None, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) all_params["object_id"] = str(self.objects_source.value()) all_params["params"] = {"algorithm": "DBSCAN", "eps": self.eps.value(), "min_samples": 1} result = Launcher.g.run("analyzer", "spatial_clustering", **all_params) print(result) logger.debug(f"spatial clustering result table {len(result)}") self.display_component_results2(result) def calc_removed_masked_objects(self): src = DataModel.g.dataset_uri(self.feature_source.value()) all_params = dict(src=src, dst=dst, modal=False) all_params["workspace"] = DataModel.g.current_workspace all_params["feature_id"] = str(self.feature_source.value()) all_params["object_id"] = str(self.objects_source.value()) result = Launcher.g.run("analyzer", "remove_masked_objects", **all_params) logger.debug(f"remove_masked_objects result table {len(result)}") self.display_component_results2(result) # calculate def calculate_analyzer(self): with progress(total=2) as pbar: pbar.set_description("Calculating pipeline") pbar.update(1) if self.analyzer_type == "label_splitter": self.calc_label_splitter() elif self.analyzer_type == "find_connected_components": self.calc_find_connected_components() elif self.analyzer_type == "level_image_stats": self.calc_level_image_stats() elif self.analyzer_type == "binary_image_stats": self.calc_binary_image_stats() elif self.analyzer_type == "image_stats": self.calc_image_stats() elif self.analyzer_type == "object_stats2": self.calc_object_stats2() elif self.analyzer_type == "object_stats": self.calc_object_stats2() elif self.analyzer_type == "object_detection_stats": self.calc_object_detection_stats() elif self.analyzer_type == "detector_predict": self.calc_detector_predict() elif self.analyzer_type == "spatial_clustering": self.calc_spatial_clustering() elif self.analyzer_type == "remove_masked_objects": self.calc_removed_masked_objects() pbar.update(2)
class SupervoxelCard(Card): def __init__(self, svid, svname, parent=None): super().__init__( title=svname, collapsible=True, removable=True, editable=True, parent=parent ) self.svid = svid self.svname = svname from survos2.frontend.plugins.features import FeatureComboBox self.svsource = FeatureComboBox() self.svsource.setMaximumWidth(250) self.svshape = LineEdit(parse=int, default=10) self.svshape.setMaximumWidth(250) self.svspacing = LineEdit3D(parse=float, default=1) self.svspacing.setMaximumWidth(250) self.svcompactness = LineEdit(parse=float, default=20) self.svcompactness.setMaximumWidth(250) self.int64_checkbox = CheckBox(checked=False) self.compute_btn = PushButton("Compute") self.view_btn = PushButton("View", accent=True) self.add_row(HWidgets("Source:", self.svsource, stretch=1)) self.add_row(HWidgets("Shape:", self.svshape, stretch=1)) self.add_row(HWidgets("Spacing:", self.svspacing, stretch=1)) self.add_row(HWidgets("Compactness:", self.svcompactness, stretch=1)) self.add_row(HWidgets("Int64:", self.int64_checkbox, stretch=1)) self.add_row(HWidgets(None, self.compute_btn)) self.add_row(HWidgets(None, self.view_btn)) self.compute_btn.clicked.connect(self.compute_supervoxels) self.view_btn.clicked.connect(self.view_regions) def card_deleted(self): params = dict(region_id=self.svid, workspace=True) result = Launcher.g.run("superregions", "remove", **params) if result["done"]: self.setParent(None) cfg.ppw.clientEvent.emit( { "source": "superregions", "data": "remove_layer", "layer_name": self.svid, } ) def card_title_edited(self, newtitle): logger.debug(f"Edited region title {newtitle}") params = dict(region_id=self.svid, new_name=newtitle, workspace=True) result = Launcher.g.run("superregions", "rename", **params) return result["done"] def view_regions(self): logger.debug(f"Transferring supervoxels {self.svid} to viewer") with progress(total=2) as pbar: pbar.set_description("Viewing feature") pbar.update(1) print(f"Current Supervoxels: {cfg.current_supervoxels}") cfg.ppw.clientEvent.emit( {"source": "superregions", "data": "view_regions", "region_id": self.svid} ) pbar.update(1) def compute_supervoxels(self): with progress(total=4) as pbar: pbar.set_description("Refreshing") pbar.update(1) # src = [ # DataModel.g.dataset_uri("features/" + s) for s in [self.svsource.value()] # ] src = DataModel.g.dataset_uri(self.svsource.value(), group="features") dst = DataModel.g.dataset_uri(self.svid, group="superregions") logger.debug(f"Compute sv: Src {src} Dst {dst}") from survos2.model import Workspace ws = Workspace(DataModel.g.current_workspace) num_chunks = np.prod(np.array(ws.metadata()["chunk_grid"])) chunk_size = ws.metadata()["chunk_size"] logger.debug( f"Using chunk_size {chunk_size} to compute number of supervoxel segments for num_chunks: {num_chunks}." ) with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM: src_dataset_shape = DM.sources[0][:].shape # n_segments = int(np.prod(chunk_size) // (self.svshape.value() ** 3)) pbar.update(1) n_segments = int(np.prod(src_dataset_shape) / self.svshape.value() ** 3) if self.int64_checkbox.value(): out_dtype = "uint64" else: out_dtype = "uint32" params = dict( src=src, dst=dst, compactness=round(self.svcompactness.value() / 100, 3), # shape=self.svshape.value(), n_segments=n_segments, spacing=self.svspacing.value(), modal=True, out_dtype=out_dtype, ) logger.debug(f"Compute supervoxels with params {params}") pbar.update(1) result = Launcher.g.run("superregions", "supervoxels", **params) if result is not None: pbar.update(1) def update_params(self, params): if "shape" in params: self.svshape.setValue(params["shape"]) if "compactness" in params: self.svcompactness.setValue(params["compactness"] * 100) if "spacing" in params: self.svspacing.setValue(params["spacing"]) if "source" in params: for source in params["source"]: self.svsource.select(source)
def __init__(self, name): super().__init__(name, FeatureComboBox(full=True))
class ObjectsCard(Card): def __init__(self, objectsid, objectsname, objectsfullname, objectstype, parent=None): super().__init__( title=objectsname, collapsible=True, removable=True, editable=True, parent=parent, ) self.objectsid = objectsid self.objectsname = objectsname self.object_scale = 1.0 self.objectsfullname = objectsfullname self.objectstype = objectstype self.widgets = {} self.filewidget = FileWidget(extensions="*.csv", save=False) self.filewidget.path.setText(self.objectsfullname) self.add_row(self.filewidget) self.filewidget.path_updated.connect(self.load_data) self.compute_btn = PushButton("Compute") self.view_btn = PushButton("View", accent=True) self.get_btn = PushButton("Get", accent=True) # self._add_param("scale", title="Scale: ", type="Float", default=1) # self._add_param("offset", title="Offset: ", type="FloatOrVector", default=0) # self._add_param( # "crop_start", title="Crop Start: ", type="FloatOrVector", default=0 # ) # self._add_param( # "crop_end", title="Crop End: ", type="FloatOrVector", default=9000 # ) self.flipxy_checkbox = CheckBox(checked=True) self.add_row(HWidgets(None, self.flipxy_checkbox, Spacing(35))) self.add_row(HWidgets(None, self.view_btn, self.get_btn, Spacing(35))) self.view_btn.clicked.connect(self.view_objects) self.get_btn.clicked.connect(self.get_objects) #cfg.object_scale = self.widgets["scale"].value() #cfg.object_offset = self.widgets["offset"].value() #cfg.object_crop_start = self.widgets["crop_start"].value() #cfg.object_crop_end = self.widgets["crop_end"].value() cfg.object_scale = 1.0 cfg.object_offset = (0, 0, 0) cfg.object_crop_start = (0, 0, 0) cfg.object_crop_end = (1e9, 1e9, 1e9) if self.objectstype == "patches": self._add_annotations_source() self.entity_mask_bvol_size = LineEdit3D(default=64, parse=int) self._add_feature_source() self.make_entity_mask_btn = PushButton("Make entity mask", accent=True) self.make_entity_mask_btn.clicked.connect(self.make_entity_mask) self.make_patches_btn = PushButton("Make patches", accent=True) self.make_patches_btn.clicked.connect(self.make_patches) self.train_fpn_btn = PushButton("Train FPN", accent=True) self.train_fpn_btn.clicked.connect(self.train_fpn) self.add_row( HWidgets(None, self.entity_mask_bvol_size, self.make_entity_mask_btn, Spacing(35))) self.add_row(HWidgets(None, self.make_patches_btn, Spacing(35))) self.add_row(HWidgets(None, self.train_fpn_btn, Spacing(35))) self.table_control = TableWidget() self.add_row(self.table_control.w, max_height=500) cfg.entity_table = self.table_control def _add_param(self, name, title=None, type="String", default=None): if type == "Int": p = LineEdit(default=default, parse=int) elif type == "Float": p = LineEdit(default=default, parse=float) elif type == "FloatOrVector": p = LineEdit3D(default=default, parse=float) elif type == "IntOrVector": p = LineEdit3D(default=default, parse=int) else: p = None if title is None: title = name if p: self.widgets[name] = p self.add_row(HWidgets(None, title, p, Spacing(35))) def load_data(self, path): self.objectsfullname = path print(f"Setting objectsfullname: {self.objectsfullname}") def card_deleted(self): params = dict(objects_id=self.objectsid, workspace=True) result = Launcher.g.run("objects", "remove", **params) if result["done"]: self.setParent(None) self.table_control = None def _add_annotations_source(self): self.annotations_source = LevelComboBox(full=True) self.annotations_source.fill() self.annotations_source.setMaximumWidth(250) widget = HWidgets("Annotation:", self.annotations_source, Spacing(35), stretch=1) self.add_row(widget) def card_title_edited(self, newtitle): logger.debug(f"Edited entity title {newtitle}") params = dict(objects_id=self.objectsid, new_name=newtitle, workspace=True) result = Launcher.g.run("objects", "rename", **params) return result["done"] def view_objects(self): logger.debug(f"Transferring objects {self.objectsid} to viewer") cfg.ppw.clientEvent.emit({ "source": "objects", "data": "view_objects", "objects_id": self.objectsid, "flipxy": self.flipxy_checkbox.value(), }) def update_params(self, params): if "fullname" in params: self.objectsfullname = params["fullname"] def _add_feature_source(self): self.feature_source = FeatureComboBox() self.feature_source.fill() self.feature_source.setMaximumWidth(250) widget = HWidgets("Feature:", self.feature_source, Spacing(35), stretch=1) self.add_row(widget) def get_objects(self): #cfg.object_scale = self.widgets["scale"].value() #cfg.object_offset = self.widgets["offset"].value() #cfg.object_crop_start = self.widgets["crop_start"].value() #cfg.object_crop_end = self.widgets["crop_end"].value() dst = DataModel.g.dataset_uri(self.objectsid, group="objects") print(f"objectsfullname: {self.objectsfullname}") params = dict( dst=dst, fullname=self.objectsfullname, scale=cfg.object_scale, offset=cfg.object_offset, crop_start=cfg.object_crop_start, crop_end=cfg.object_crop_end, ) logger.debug(f"Getting objects with params {params}") result = Launcher.g.run("objects", "update_metadata", workspace=True, **params) if self.objectstype == "points": tabledata, self.entities_df = setup_entity_table( self.objectsfullname, scale=cfg.object_scale, offset=cfg.object_offset, crop_start=cfg.object_crop_start, crop_end=cfg.object_crop_end, flipxy=self.flipxy_checkbox.value()) elif self.objectstype == "boxes": tabledata, self.entities_df = setup_bb_table( self.objectsfullname, scale=cfg.object_scale, offset=cfg.object_offset, crop_start=cfg.object_crop_start, crop_end=cfg.object_crop_end, flipxy=self.flipxy_checkbox.value()) elif self.objectstype == "patches": tabledata, self.entities_df = setup_entity_table( self.objectsfullname, scale=cfg.object_scale, offset=cfg.object_offset, crop_start=cfg.object_crop_start, crop_end=cfg.object_crop_end, flipxy=self.flipxy_checkbox.value()) cfg.tabledata = tabledata self.table_control.set_data(tabledata) print(f"Loaded tabledata {tabledata}") self.table_control.set_data(tabledata) self.collapse() self.expand() def make_entity_mask(self): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM: src_array = DM.sources[0][:] entity_arr = np.array(self.entities_df) bvol_dim = self.entity_mask_bvol_size.value() entity_arr[:, 0] -= bvol_dim[0] entity_arr[:, 1] -= bvol_dim[1] entity_arr[:, 2] -= bvol_dim[2] from survos2.entity.entities import make_entity_mask gold_mask = make_entity_mask(src_array, entity_arr, flipxy=True, bvol_dim=bvol_dim)[0] # create new raw feature params = dict(feature_type="raw", workspace=True) result = Launcher.g.run("features", "create", **params) if result: fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug( f"Created new object in workspace {fid}, {ftype}, {fname}") dst = DataModel.g.dataset_uri(fid, group="features") with DatasetManager(dst, out=dst, dtype="float32", fillvalue=0) as DM: DM.out[:] = gold_mask cfg.ppw.clientEvent.emit({ "source": "objects_plugin", "data": "refresh", "value": None }) def make_patches(self): src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM: src_array = DM.sources[0][:] objects_scale = 1.0 entity_meta = { "0": { "name": "class1", "size": np.array((15, 15, 15)) * objects_scale, "core_radius": np.array((7, 7, 7)) * objects_scale, }, } entity_arr = np.array(self.entities_df) combined_clustered_pts, classwise_entities = organize_entities( src_array, entity_arr, entity_meta, plot_all=False) wparams = {} wparams["entities_offset"] = (0, 0, 0) wparams["entity_meta"] = entity_meta wparams["workflow_name"] = "Make_Patches" wparams["proj"] = DataModel.g.current_workspace wf = PatchWorkflow([src_array], combined_clustered_pts, classwise_entities, src_array, wparams, combined_clustered_pts) src = DataModel.g.dataset_uri(self.annotations_source.value().rsplit( "/", 1)[-1], group="annotations") with DatasetManager(src, out=None, dtype="uint16", fillvalue=0) as DM: src_dataset = DM.sources[0] anno_level = src_dataset[:] & 15 logger.debug( f"Obtained annotation level with labels {np.unique(anno_level)}") logger.debug(f"Making patches in path {src_dataset._path}") train_v_density = make_patches(wf, entity_arr, src_dataset._path, proposal_vol=(anno_level > 0) * 1.0, padding=(32, 32, 32), num_augs=0, max_vols=-1) self.patches = train_v_density cfg.ppw.clientEvent.emit({ "source": "panel_gui", "data": "view_patches", "patches_fullname": train_v_density }) def train_fpn(self): from survos2.entity.train import train_seg from survos2.entity.pipeline_ops import make_proposal wf_params = {} wf_params["torch_models_fullpath"] = "/experiments" model_file = train_seg(self.patches, wf_params, num_epochs=1) patch_size = (64, 64, 64) patch_overlap = (16, 16, 16) overlap_mode = "crop" model_type = "fpn3d" threshold_devs = 1.5, invert = True, src = DataModel.g.dataset_uri(self.feature_source.value(), group="features") with DatasetManager(src, out=None, dtype="float32", fillvalue=0) as DM: src_array = DM.sources[0][:] proposal = make_proposal( src_array, os.path.join(wf_params["torch_models_fullpath"], model_file), model_type=model_type, patch_size=patch_size, patch_overlap=patch_overlap, overlap_mode=overlap_mode, ) # create new float image params = dict(feature_type="raw", workspace=True) result = Launcher.g.run("features", "create", **params) if result: fid = result["id"] ftype = result["kind"] fname = result["name"] logger.debug( f"Created new object in workspace {fid}, {ftype}, {fname}") dst = DataModel.g.dataset_uri(fid, group="features") with DatasetManager(dst, out=dst, dtype="float32", fillvalue=0) as DM: DM.out[:] = proposal cfg.ppw.clientEvent.emit({ "source": "workspace_gui", "data": "refresh", "value": None })