diff --git a/src/napari_segmentation_correction/_widget.py b/src/napari_segmentation_correction/_widget.py index 60aeab9..eb978cc 100644 --- a/src/napari_segmentation_correction/_widget.py +++ b/src/napari_segmentation_correction/_widget.py @@ -204,42 +204,33 @@ def _save_labels(self) -> None: if isinstance(self.label_manager.selected_layer.data, da.core.Array): if self.outputdir is None: - msg = QMessageBox() - msg.setWindowTitle("No output directory selected") - msg.setText("Please specify an output directory first!") - msg.setIcon(QMessageBox.Information) - msg.setStandardButtons(QMessageBox.Ok) - msg.exec_() - return False - - else: - outputdir = os.path.join( - self.outputdir, - (self.label_manager.selected_layer.name + "_finalresult"), - ) - if os.path.exists(outputdir): - shutil.rmtree(outputdir) - os.mkdir(outputdir) - - for i in range( - self.label_manager.selected_layer.data.shape[0] - ): # Loop over the first dimension - current_stack = self.label_manager.selected_layer.data[ - i - ].compute() # Compute the current stack - tifffile.imwrite( - os.path.join( - outputdir, - ( - self.label_manager.selected_layer.name - + "_TP" - + str(i).zfill(4) - + ".tif" - ), + self.outputdir = QFileDialog.getExistingDirectory(self, "Select Output Folder") + outputdir = os.path.join( + self.outputdir, + (self.label_manager.selected_layer.name + "_finalresult"), + ) + if os.path.exists(outputdir): + shutil.rmtree(outputdir) + os.mkdir(outputdir) + + for i in range( + self.label_manager.selected_layer.data.shape[0] + ): # Loop over the first dimension + current_stack = self.label_manager.selected_layer.data[ + i + ].compute() # Compute the current stack + tifffile.imwrite( + os.path.join( + outputdir, + ( + self.label_manager.selected_layer.name + + "_TP" + + str(i).zfill(4) + + ".tif" ), - np.array(current_stack, dtype="uint16"), - ) - return True + ), + np.array(current_stack, dtype="uint16"), + ) elif len(self.label_manager.selected_layer.data.shape) == 4: filename, _ = QFileDialog.getSaveFileName( diff --git a/src/napari_segmentation_correction/erosion_dilation_widget.py b/src/napari_segmentation_correction/erosion_dilation_widget.py index 89cf3ba..3181612 100644 --- a/src/napari_segmentation_correction/erosion_dilation_widget.py +++ b/src/napari_segmentation_correction/erosion_dilation_widget.py @@ -14,6 +14,7 @@ QSpinBox, QVBoxLayout, QWidget, + QFileDialog ) from scipy import ndimage from scipy.ndimage import binary_erosion @@ -33,6 +34,7 @@ def __init__( self.viewer = viewer self.label_manager = label_manager + self.outputdir = None dil_erode_box = QGroupBox("Erode/dilate labels") dil_erode_box_layout = QVBoxLayout() @@ -88,63 +90,56 @@ def _erode_labels(self): if isinstance(self.label_manager.selected_layer.data, da.core.Array): if self.outputdir is None: - msg = QMessageBox() - msg.setWindowTitle("No output directory selected") - msg.setText("Please specify an output directory first!") - msg.setIcon(QMessageBox.Information) - msg.setStandardButtons(QMessageBox.Ok) - msg.exec_() - return False + self.outputdir = QFileDialog.getExistingDirectory(self, "Select Output Folder") - else: - outputdir = os.path.join( - self.outputdir, - (self.label_manager.selected_layer.name + "_eroded"), - ) - if os.path.exists(outputdir): - shutil.rmtree(outputdir) - os.mkdir(outputdir) + outputdir = os.path.join( + self.outputdir, + (self.label_manager.selected_layer.name + "_eroded"), + ) + if os.path.exists(outputdir): + shutil.rmtree(outputdir) + os.mkdir(outputdir) - for i in range( - self.label_manager.selected_layer.data.shape[0] - ): # Loop over the first dimension - current_stack = self.label_manager.selected_layer.data[ - i - ].compute() # Compute the current stack - mask = current_stack > 0 - filled_mask = ndimage.binary_fill_holes(mask) - eroded_mask = binary_erosion( - filled_mask, - structure=structuring_element, - iterations=iterations, - ) - eroded = np.where(eroded_mask, current_stack, 0) - tifffile.imwrite( - os.path.join( - outputdir, - ( - self.label_manager.selected_layer.name - + "_eroded_TP" - + str(i).zfill(4) - + ".tif" - ), - ), - np.array(eroded, dtype="uint16"), - ) - - file_list = [ - os.path.join(outputdir, fname) - for fname in os.listdir(outputdir) - if fname.endswith(".tif") - ] - self.label_manager.selected_layer = self.viewer.add_labels( - da.stack([imread(fname) for fname in sorted(file_list)]), - name=self.label_manager.selected_layer.name + "_eroded", + for i in range( + self.label_manager.selected_layer.data.shape[0] + ): # Loop over the first dimension + current_stack = self.label_manager.selected_layer.data[ + i + ].compute() # Compute the current stack + mask = current_stack > 0 + filled_mask = ndimage.binary_fill_holes(mask) + eroded_mask = binary_erosion( + filled_mask, + structure=structuring_element, + iterations=iterations, ) - self.label_manager._update_labels( - self.label_manager.selected_layer.name + eroded = np.where(eroded_mask, current_stack, 0) + tifffile.imwrite( + os.path.join( + outputdir, + ( + self.label_manager.selected_layer.name + + "_eroded_TP" + + str(i).zfill(4) + + ".tif" + ), + ), + np.array(eroded, dtype="uint16"), ) - return True + + file_list = [ + os.path.join(outputdir, fname) + for fname in os.listdir(outputdir) + if fname.endswith(".tif") + ] + self.label_manager.selected_layer = self.viewer.add_labels( + da.stack([imread(fname) for fname in sorted(file_list)]), + name=self.label_manager.selected_layer.name + "_eroded", + ) + self.label_manager._update_labels( + self.label_manager.selected_layer.name + ) + return True else: if len(self.label_manager.selected_layer.data.shape) == 4: @@ -201,59 +196,52 @@ def _dilate_labels(self): if isinstance(self.label_manager.selected_layer.data, da.core.Array): if self.outputdir is None: - msg = QMessageBox() - msg.setWindowTitle("No output directory selected") - msg.setText("Please specify an output directory first!") - msg.setIcon(QMessageBox.Information) - msg.setStandardButtons(QMessageBox.Ok) - msg.exec_() - return False + self.outputdir = QFileDialog.getExistingDirectory(self, "Select Output Folder") - else: - outputdir = os.path.join( - self.outputdir, - (self.label_manager.selected_layer.name + "_dilated"), - ) - if os.path.exists(outputdir): - shutil.rmtree(outputdir) - os.mkdir(outputdir) + outputdir = os.path.join( + self.outputdir, + (self.label_manager.selected_layer.name + "_dilated"), + ) + if os.path.exists(outputdir): + shutil.rmtree(outputdir) + os.mkdir(outputdir) - for i in range( - self.label_manager.selected_layer.data.shape[0] - ): # Loop over the first dimension - expanded_labels = self.label_manager.selected_layer.data[ - i - ].compute() # Compute the current stack - for _j in range(iterations): - expanded_labels = expand_labels( - expanded_labels, distance=diam - ) - tifffile.imwrite( - os.path.join( - outputdir, - ( - self.label_manager.selected_layer.name - + "_dilated_TP" - + str(i).zfill(4) - + ".tif" - ), - ), - np.array(expanded_labels, dtype="uint16"), + for i in range( + self.label_manager.selected_layer.data.shape[0] + ): # Loop over the first dimension + expanded_labels = self.label_manager.selected_layer.data[ + i + ].compute() # Compute the current stack + for _j in range(iterations): + expanded_labels = expand_labels( + expanded_labels, distance=diam ) - - file_list = [ - os.path.join(outputdir, fname) - for fname in os.listdir(outputdir) - if fname.endswith(".tif") - ] - self.label_manager.selected_layer = self.viewer.add_labels( - da.stack([imread(fname) for fname in sorted(file_list)]), - name=self.label_manager.selected_layer.name + "_dilated", - ) - self.label_manager._update_labels( - self.label_manager.selected_layer.name + tifffile.imwrite( + os.path.join( + outputdir, + ( + self.label_manager.selected_layer.name + + "_dilated_TP" + + str(i).zfill(4) + + ".tif" + ), + ), + np.array(expanded_labels, dtype="uint16"), ) - return True + + file_list = [ + os.path.join(outputdir, fname) + for fname in os.listdir(outputdir) + if fname.endswith(".tif") + ] + self.label_manager.selected_layer = self.viewer.add_labels( + da.stack([imread(fname) for fname in sorted(file_list)]), + name=self.label_manager.selected_layer.name + "_dilated", + ) + self.label_manager._update_labels( + self.label_manager.selected_layer.name + ) + return True else: if len(self.label_manager.selected_layer.data.shape) == 4: diff --git a/src/napari_segmentation_correction/size_filter_widget.py b/src/napari_segmentation_correction/size_filter_widget.py index 23c63a0..12b2f3a 100644 --- a/src/napari_segmentation_correction/size_filter_widget.py +++ b/src/napari_segmentation_correction/size_filter_widget.py @@ -15,6 +15,7 @@ QSpinBox, QVBoxLayout, QWidget, + QFileDialog ) from skimage import measure from skimage.io import imread @@ -32,6 +33,7 @@ def __init__( self.viewer = viewer self.label_manager = label_manager + self.outputdir = None filterbox = QGroupBox("Filter objects by size") filter_layout = QVBoxLayout() @@ -60,69 +62,62 @@ def _delete_small_objects(self) -> None: if isinstance(self.label_manager.selected_layer.data, da.core.Array): if self.outputdir is None: - msg = QMessageBox() - msg.setWindowTitle("No output directory selected") - msg.setText("Please specify an output directory first!") - msg.setIcon(QMessageBox.Information) - msg.setStandardButtons(QMessageBox.Ok) - msg.exec_() - return False - - else: - outputdir = os.path.join( - self.outputdir, - (self.label_manager.selected_layer.name + "_sizefiltered"), - ) - if os.path.exists(outputdir): - shutil.rmtree(outputdir) - os.mkdir(outputdir) - - for i in range( - self.label_manager.selected_layer.data.shape[0] - ): # Loop over the first dimension - current_stack = self.label_manager.selected_layer.data[ - i - ].compute() # Compute the current stack - - # measure the sizes in pixels of the labels in slice using skimage.regionprops - props = measure.regionprops(current_stack) - filtered_labels = [ - p.label - for p in props - if p.area > self.min_size_field.value() - ] - mask = functools.reduce( - np.logical_or, - (current_stack == val for val in filtered_labels), - ) - filtered = np.where(mask, current_stack, 0) - tifffile.imwrite( - os.path.join( - outputdir, - ( - self.label_manager.selected_layer.name - + "_sizefiltered_TP" - + str(i).zfill(4) - + ".tif" - ), - ), - np.array(filtered, dtype="uint16"), - ) - - file_list = [ - os.path.join(outputdir, fname) - for fname in os.listdir(outputdir) - if fname.endswith(".tif") + self.outputdir = QFileDialog.getExistingDirectory(self, "Select Output Folder") + + outputdir = os.path.join( + self.outputdir, + (self.label_manager.selected_layer.name + "_sizefiltered"), + ) + if os.path.exists(outputdir): + shutil.rmtree(outputdir) + os.mkdir(outputdir) + + for i in range( + self.label_manager.selected_layer.data.shape[0] + ): # Loop over the first dimension + current_stack = self.label_manager.selected_layer.data[ + i + ].compute() # Compute the current stack + + # measure the sizes in pixels of the labels in slice using skimage.regionprops + props = measure.regionprops(current_stack) + filtered_labels = [ + p.label + for p in props + if p.area > self.min_size_field.value() ] - self.label_manager.selected_layer = self.viewer.add_labels( - da.stack([imread(fname) for fname in sorted(file_list)]), - name=self.label_manager.selected_layer.name - + "_sizefiltered", + mask = functools.reduce( + np.logical_or, + (current_stack == val for val in filtered_labels), ) - self.label_manager._update_labels( - self.label_manager.selected_layer.name + filtered = np.where(mask, current_stack, 0) + tifffile.imwrite( + os.path.join( + outputdir, + ( + self.label_manager.selected_layer.name + + "_sizefiltered_TP" + + str(i).zfill(4) + + ".tif" + ), + ), + np.array(filtered, dtype="uint16"), ) + file_list = [ + os.path.join(outputdir, fname) + for fname in os.listdir(outputdir) + if fname.endswith(".tif") + ] + self.label_manager.selected_layer = self.viewer.add_labels( + da.stack([imread(fname) for fname in sorted(file_list)]), + name=self.label_manager.selected_layer.name + + "_sizefiltered", + ) + self.label_manager._update_labels( + self.label_manager.selected_layer.name + ) + else: # Image data is a normal array and can be directly edited. if len(self.label_manager.selected_layer.data.shape) == 4: diff --git a/src/napari_segmentation_correction/threshold_widget.py b/src/napari_segmentation_correction/threshold_widget.py index aca6af2..8660d57 100644 --- a/src/napari_segmentation_correction/threshold_widget.py +++ b/src/napari_segmentation_correction/threshold_widget.py @@ -1,4 +1,5 @@ import dask.array as da +import numpy as np import napari from napari.layers import Image, Labels from qtpy.QtWidgets import ( @@ -10,9 +11,14 @@ QSpinBox, QVBoxLayout, QWidget, + QFileDialog ) from .layer_dropdown import LayerDropdown +from skimage.io import imread +import os +import tifffile +import shutil class ThresholdWidget(QWidget): @@ -22,6 +28,8 @@ def __init__(self, viewer: "napari.viewer.Viewer") -> None: super().__init__() self.viewer = viewer + self.outputdir = None + self.threshold_layer = None threshold_box = QGroupBox("Threshold") threshold_box_layout = QVBoxLayout() @@ -72,19 +80,55 @@ def _threshold(self): """Threshold the selected label or intensity image""" if isinstance(self.threshold_layer.data, da.core.Array): - msg = QMessageBox() - msg.setWindowTitle( - "Thresholding not yet implemented for dask arrays" + if self.outputdir is None: + self.outputdir = QFileDialog.getExistingDirectory(self, "Select Output Folder") + + outputdir = os.path.join( + self.outputdir, + (self.threshold_layer.name + "_threshold"), + ) + if os.path.exists(outputdir): + shutil.rmtree(outputdir) + os.mkdir(outputdir) + + for i in range( + self.threshold_layer.data.shape[0] + ): # Loop over the first dimension + data = self.threshold_layer.data[ + i + ].compute() # Compute the current stack + + thresholded = ( + data >= int(self.min_threshold.value()) + ) & (data <= int(self.max_threshold.value())) + + tifffile.imwrite( + os.path.join( + outputdir, + ( + self.threshold_layer.name + + "_thresholded_TP" + + str(i).zfill(4) + + ".tif" + ), + ), + np.array(thresholded, dtype="uint8"), + ) + + file_list = [ + os.path.join(outputdir, fname) + for fname in os.listdir(outputdir) + if fname.endswith(".tif") + ] + self.viewer.add_labels( + da.stack([imread(fname) for fname in sorted(file_list)]), + name=self.threshold_layer.name + "_thresholded", + ) + + else: + thresholded = ( + self.threshold_layer.data >= int(self.min_threshold.value()) + ) & (self.threshold_layer.data <= int(self.max_threshold.value())) + self.viewer.add_labels( + thresholded, name=self.threshold_layer.name + "_thresholded" ) - msg.setText("Thresholding not yet implemented for dask arrays") - msg.setIcon(QMessageBox.Information) - msg.setStandardButtons(QMessageBox.Ok) - msg.exec_() - return False - - thresholded = ( - self.threshold_layer.data >= int(self.min_threshold.value()) - ) & (self.threshold_layer.data <= int(self.max_threshold.value())) - self.viewer.add_labels( - thresholded, name=self.threshold_layer.name + "_thresholded" - )