From aac2289ae5832f5818cdf9cffbc3aea9c9eec885 Mon Sep 17 00:00:00 2001 From: Luca Freckmann Date: Tue, 2 Apr 2024 16:57:04 +0200 Subject: [PATCH 1/4] added embedding save path to UI --- micro_sam/sam_annotator/_widgets.py | 38 ++++++++++++++++++++++++++--- micro_sam/util.py | 4 +-- 2 files changed, 37 insertions(+), 5 deletions(-) diff --git a/micro_sam/sam_annotator/_widgets.py b/micro_sam/sam_annotator/_widgets.py index 44b131d4..660e7bf7 100644 --- a/micro_sam/sam_annotator/_widgets.py +++ b/micro_sam/sam_annotator/_widgets.py @@ -16,7 +16,7 @@ import z5py from qtpy import QtWidgets -from qtpy.QtCore import QObject, Signal +from qtpy.QtCore import QObject, Signal, QFileInfo from superqt import QCollapsible from magicgui import magic_factory from magicgui.widgets import ComboBox, Container, create_widget @@ -123,6 +123,34 @@ def _add_shape_param(self, names, values, min_val, max_val, step=1): return x_param, y_param, layout + # New method for directory selection + def _add_directory_param(self, name, value, title=None): + layout = QtWidgets.QHBoxLayout() + layout.addWidget(QtWidgets.QLabel(name if title is None else title)) + + directory_textbox = QtWidgets.QLineEdit() + directory_textbox.setText(value) + layout.addWidget(directory_textbox) + + directory_button = QtWidgets.QPushButton("Browse") + directory_button.clicked.connect(lambda: self._get_directory(name, directory_textbox)) + layout.addWidget(directory_button) + + return layout + + def _get_directory(self, name, directory_textbox): + directory = QtWidgets.QFileDialog.getExistingDirectory( + self, "Select Directory", "", QtWidgets.QFileDialog.ShowDirsOnly) + if directory: + path = Path(directory) # Create a Path object from the string + + if path.is_dir(): # Check if it's a valid directory + directory_textbox.setText(directory) + setattr(self, name, path) + else: + # Handle the case where the selected path is not a directory + print("Invalid directory selected. Please try again.") + # Custom signals for managing progress updates. class PBarSignals(QObject): @@ -587,8 +615,12 @@ def _create_settings_widget(self): # TODO # save_path: Optional[Path] = None, # where embeddings for this image are cached (optional, zarr file = folder) # custom_weights: Optional[Path] = None, # A filepath or URL to custom model weights. + # Create UI for the save path. - self.save_path = None + self.embeddings_save_path = None + layout = self._add_directory_param( + "embeddings_save_path", self.embeddings_save_path, title="embeddings save path:") + setting_values.layout().addLayout(layout) # Create UI for the custom weights. self.custom_weights = None @@ -632,7 +664,7 @@ def __call__(self): # Process tile_shape and halo, set other data. tile_shape, halo = _process_tiling_inputs(self.tile_x, self.tile_y, self.halo_x, self.halo_y) - save_path = self.save_path + save_path = self.embeddings_save_path image_data = image.data # Set up progress bar and signals for using it within a threadworker. diff --git a/micro_sam/util.py b/micro_sam/util.py index c37cde00..89c8d770 100644 --- a/micro_sam/util.py +++ b/micro_sam/util.py @@ -463,7 +463,7 @@ def _compute_tiled_features_3d(predictor, input_, tile_shape, halo, f, pbar_init def _compute_2d(input_, predictor, f, save_path, pbar_init, pbar_update): # Check if the embeddings are already cached. - if save_path is not None and "input_size" in f.attrs: + if save_path is not None and "features" in f.attrs: # In this case we load the embeddings.. features = f["features"][:] original_size, input_size = f.attrs["original_size"], f.attrs["input_size"] @@ -499,7 +499,7 @@ def _compute_2d(input_, predictor, f, save_path, pbar_init, pbar_update): def _compute_tiled_2d(input_, predictor, tile_shape, halo, f, pbar_init, pbar_update): # Check if the features are already computed. - if "input_size" in f.attrs: + if "input_size" in f.attrs and "features" in f.attrs: features = f["features"] original_size, input_size = f.attrs["original_size"], f.attrs["input_size"] image_embeddings = { From fdd9dac31c8471da13126611e7529055d4597f54 Mon Sep 17 00:00:00 2001 From: Luca Freckmann Date: Wed, 3 Apr 2024 10:55:37 +0200 Subject: [PATCH 2/4] added custom weights to UI --- micro_sam/sam_annotator/_widgets.py | 38 +++++++++++++++++++++++++---- micro_sam/util.py | 2 +- 2 files changed, 34 insertions(+), 6 deletions(-) diff --git a/micro_sam/sam_annotator/_widgets.py b/micro_sam/sam_annotator/_widgets.py index 660e7bf7..4c0687f7 100644 --- a/micro_sam/sam_annotator/_widgets.py +++ b/micro_sam/sam_annotator/_widgets.py @@ -123,8 +123,21 @@ def _add_shape_param(self, names, values, min_val, max_val, step=1): return x_param, y_param, layout - # New method for directory selection - def _add_directory_param(self, name, value, title=None): + # # New method for directory selection + # def _add_directory_param(self, name, value, title=None): + # layout = QtWidgets.QHBoxLayout() + # layout.addWidget(QtWidgets.QLabel(name if title is None else title)) + + # directory_textbox = QtWidgets.QLineEdit() + # directory_textbox.setText(value) + # layout.addWidget(directory_textbox) + + # directory_button = QtWidgets.QPushButton("Browse") + # directory_button.clicked.connect(lambda: self._get_directory(name, directory_textbox)) + # layout.addWidget(directory_button) + + # return layout + def _add_directory_param(self, name, value, title=None, select_file=False): layout = QtWidgets.QHBoxLayout() layout.addWidget(QtWidgets.QLabel(name if title is None else title)) @@ -132,8 +145,11 @@ def _add_directory_param(self, name, value, title=None): directory_textbox.setText(value) layout.addWidget(directory_textbox) - directory_button = QtWidgets.QPushButton("Browse") - directory_button.clicked.connect(lambda: self._get_directory(name, directory_textbox)) + button_text = "Browse Directory" if not select_file else "Browse File" # Adjust button text + directory_button = QtWidgets.QPushButton(button_text) + # Call appropriate function based on select_file + directory_button.clicked.connect(lambda: getattr(self, "_get_{}_path".format( + "directory" if not select_file else "file"))(name, directory_textbox)) layout.addWidget(directory_button) return layout @@ -151,6 +167,14 @@ def _get_directory(self, name, directory_textbox): # Handle the case where the selected path is not a directory print("Invalid directory selected. Please try again.") + def _get_file_path(self, name, directory_textbox): + file_path, _ = QtWidgets.QFileDialog.getOpenFileName( + self, "Select File", "", "All Files (*)" + ) + if file_path: + directory_textbox.setText(file_path) + setattr(self, name, file_path) + # Custom signals for managing progress updates. class PBarSignals(QObject): @@ -621,8 +645,12 @@ def _create_settings_widget(self): layout = self._add_directory_param( "embeddings_save_path", self.embeddings_save_path, title="embeddings save path:") setting_values.layout().addLayout(layout) + # Create UI for the custom weights. - self.custom_weights = None + self.custom_weights = None # select_file + layout = self._add_directory_param( + "custom_weights", self.custom_weights, title="custom weights path:", select_file=True) + setting_values.layout().addLayout(layout) # Create UI for the tile shape. self.tile_x, self.tile_y = 0, 0 diff --git a/micro_sam/util.py b/micro_sam/util.py index 89c8d770..60be1840 100644 --- a/micro_sam/util.py +++ b/micro_sam/util.py @@ -499,7 +499,7 @@ def _compute_2d(input_, predictor, f, save_path, pbar_init, pbar_update): def _compute_tiled_2d(input_, predictor, tile_shape, halo, f, pbar_init, pbar_update): # Check if the features are already computed. - if "input_size" in f.attrs and "features" in f.attrs: + if "input_size" in f.attrs: features = f["features"] original_size, input_size = f.attrs["original_size"], f.attrs["input_size"] image_embeddings = { From 6be10b3559df6617f9441636967ab5c5205c010e Mon Sep 17 00:00:00 2001 From: Luca Freckmann Date: Wed, 3 Apr 2024 15:25:34 +0200 Subject: [PATCH 3/4] tidied up some code --- micro_sam/sam_annotator/_widgets.py | 24 +++++------------------- micro_sam/util.py | 2 +- 2 files changed, 6 insertions(+), 20 deletions(-) diff --git a/micro_sam/sam_annotator/_widgets.py b/micro_sam/sam_annotator/_widgets.py index 4c0687f7..89a41e7e 100644 --- a/micro_sam/sam_annotator/_widgets.py +++ b/micro_sam/sam_annotator/_widgets.py @@ -123,21 +123,7 @@ def _add_shape_param(self, names, values, min_val, max_val, step=1): return x_param, y_param, layout - # # New method for directory selection - # def _add_directory_param(self, name, value, title=None): - # layout = QtWidgets.QHBoxLayout() - # layout.addWidget(QtWidgets.QLabel(name if title is None else title)) - - # directory_textbox = QtWidgets.QLineEdit() - # directory_textbox.setText(value) - # layout.addWidget(directory_textbox) - - # directory_button = QtWidgets.QPushButton("Browse") - # directory_button.clicked.connect(lambda: self._get_directory(name, directory_textbox)) - # layout.addWidget(directory_button) - - # return layout - def _add_directory_param(self, name, value, title=None, select_file=False): + def _add_path_param(self, name, value, title=None, select_file=False): layout = QtWidgets.QHBoxLayout() layout.addWidget(QtWidgets.QLabel(name if title is None else title)) @@ -145,7 +131,7 @@ def _add_directory_param(self, name, value, title=None, select_file=False): directory_textbox.setText(value) layout.addWidget(directory_textbox) - button_text = "Browse Directory" if not select_file else "Browse File" # Adjust button text + button_text = "Browse File" if select_file else "Browse Directory" # Adjust button text directory_button = QtWidgets.QPushButton(button_text) # Call appropriate function based on select_file directory_button.clicked.connect(lambda: getattr(self, "_get_{}_path".format( @@ -154,7 +140,7 @@ def _add_directory_param(self, name, value, title=None, select_file=False): return layout - def _get_directory(self, name, directory_textbox): + def _get_directory_path(self, name, directory_textbox): directory = QtWidgets.QFileDialog.getExistingDirectory( self, "Select Directory", "", QtWidgets.QFileDialog.ShowDirsOnly) if directory: @@ -642,13 +628,13 @@ def _create_settings_widget(self): # Create UI for the save path. self.embeddings_save_path = None - layout = self._add_directory_param( + layout = self._add_path_param( "embeddings_save_path", self.embeddings_save_path, title="embeddings save path:") setting_values.layout().addLayout(layout) # Create UI for the custom weights. self.custom_weights = None # select_file - layout = self._add_directory_param( + layout = self._add_path_param( "custom_weights", self.custom_weights, title="custom weights path:", select_file=True) setting_values.layout().addLayout(layout) diff --git a/micro_sam/util.py b/micro_sam/util.py index 60be1840..c37cde00 100644 --- a/micro_sam/util.py +++ b/micro_sam/util.py @@ -463,7 +463,7 @@ def _compute_tiled_features_3d(predictor, input_, tile_shape, halo, f, pbar_init def _compute_2d(input_, predictor, f, save_path, pbar_init, pbar_update): # Check if the embeddings are already cached. - if save_path is not None and "features" in f.attrs: + if save_path is not None and "input_size" in f.attrs: # In this case we load the embeddings.. features = f["features"][:] original_size, input_size = f.attrs["original_size"], f.attrs["input_size"] From 3a183da410b51f03edd4759d8b92abb5ef9c5750 Mon Sep 17 00:00:00 2001 From: Constantin Pape Date: Wed, 3 Apr 2024 16:40:54 +0200 Subject: [PATCH 4/4] Fix test --- test/test_sam_annotator/test_widgets.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/test_sam_annotator/test_widgets.py b/test/test_sam_annotator/test_widgets.py index 03ecc15a..04bede16 100644 --- a/test/test_sam_annotator/test_widgets.py +++ b/test/test_sam_annotator/test_widgets.py @@ -30,7 +30,7 @@ def test_embedding_widget(make_napari_viewer, tmp_path): my_widget.image = layer my_widget.model_type = "vit_t" my_widget.device = "cpu" - my_widget.save_path = tmp_path + my_widget.embeddings_save_path = tmp_path # Run image embedding widget. worker = my_widget()