napari-tmidas 0.2.0__py3-none-any.whl → 0.2.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- napari_tmidas/_crop_anything.py +1895 -608
- napari_tmidas/_file_selector.py +87 -6
- napari_tmidas/_version.py +2 -2
- napari_tmidas/processing_functions/basic.py +494 -23
- napari_tmidas/processing_functions/careamics_denoising.py +324 -0
- napari_tmidas/processing_functions/careamics_env_manager.py +339 -0
- napari_tmidas/processing_functions/cellpose_env_manager.py +55 -20
- napari_tmidas/processing_functions/cellpose_segmentation.py +105 -218
- napari_tmidas/processing_functions/sam2_mp4.py +283 -0
- napari_tmidas/processing_functions/skimage_filters.py +31 -1
- napari_tmidas/processing_functions/timepoint_merger.py +490 -0
- napari_tmidas/processing_functions/trackastra_tracking.py +303 -0
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/METADATA +15 -8
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/RECORD +18 -13
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/WHEEL +1 -1
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/entry_points.txt +0 -0
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/licenses/LICENSE +0 -0
- {napari_tmidas-0.2.0.dist-info → napari_tmidas-0.2.1.dist-info}/top_level.txt +0 -0
napari_tmidas/_file_selector.py
CHANGED
|
@@ -585,7 +585,8 @@ class ProcessingWorker(QThread):
|
|
|
585
585
|
filepath = future_to_file[future]
|
|
586
586
|
try:
|
|
587
587
|
result = future.result()
|
|
588
|
-
if
|
|
588
|
+
# Only process result if it's not None (folder functions may return None)
|
|
589
|
+
if result is not None:
|
|
589
590
|
processed_files_info.append(result)
|
|
590
591
|
self.file_processed.emit(result)
|
|
591
592
|
except (
|
|
@@ -611,6 +612,16 @@ class ProcessingWorker(QThread):
|
|
|
611
612
|
|
|
612
613
|
print(f"Original image shape: {image.shape}, dtype: {image_dtype}")
|
|
613
614
|
|
|
615
|
+
# Check if this is a folder-processing function that shouldn't save individual files
|
|
616
|
+
function_name = getattr(
|
|
617
|
+
self.processing_func, "__name__", "unknown"
|
|
618
|
+
)
|
|
619
|
+
is_folder_function = (
|
|
620
|
+
"timepoint" in function_name.lower()
|
|
621
|
+
or "merge" in function_name.lower()
|
|
622
|
+
or "folder" in function_name.lower()
|
|
623
|
+
)
|
|
624
|
+
|
|
614
625
|
# Apply processing with parameters
|
|
615
626
|
processed_image = self.processing_func(image, **self.param_values)
|
|
616
627
|
|
|
@@ -618,6 +629,19 @@ class ProcessingWorker(QThread):
|
|
|
618
629
|
f"Processed image shape before removing singletons: {processed_image.shape}, dtype: {processed_image.dtype}"
|
|
619
630
|
)
|
|
620
631
|
|
|
632
|
+
# For folder functions, check if the output is the same as input (indicating no individual file should be saved)
|
|
633
|
+
if is_folder_function:
|
|
634
|
+
# If the function returns the original image unchanged, it means it handled saving internally
|
|
635
|
+
if np.array_equal(processed_image, image):
|
|
636
|
+
print(
|
|
637
|
+
"Folder function returned unchanged image - skipping individual file save"
|
|
638
|
+
)
|
|
639
|
+
return None # Return None to indicate no file should be created
|
|
640
|
+
else:
|
|
641
|
+
print(
|
|
642
|
+
"Folder function returned different data - will save individual file"
|
|
643
|
+
)
|
|
644
|
+
|
|
621
645
|
# Remove ALL singleton dimensions from the processed image
|
|
622
646
|
# This will keep only dimensions with size > 1
|
|
623
647
|
processed_image = np.squeeze(processed_image)
|
|
@@ -939,9 +963,49 @@ class FileResultsWidget(QWidget):
|
|
|
939
963
|
|
|
940
964
|
# Update description
|
|
941
965
|
description = function_info.get("description", "")
|
|
942
|
-
self.function_description.setText(description)
|
|
943
966
|
|
|
944
|
-
#
|
|
967
|
+
# Check if this is a folder-processing function that needs single threading
|
|
968
|
+
is_folder_function = (
|
|
969
|
+
"folder" in function_name.lower()
|
|
970
|
+
or "timepoint" in function_name.lower()
|
|
971
|
+
or "merge" in function_name.lower()
|
|
972
|
+
or "folder" in description.lower()
|
|
973
|
+
or "cellpose" in description.lower()
|
|
974
|
+
or "careamics" in description.lower()
|
|
975
|
+
or "trackastra" in description.lower()
|
|
976
|
+
)
|
|
977
|
+
|
|
978
|
+
# Disable threading controls for folder functions
|
|
979
|
+
if is_folder_function:
|
|
980
|
+
self.thread_count.setValue(1)
|
|
981
|
+
self.thread_count.setEnabled(False)
|
|
982
|
+
self.thread_count.setToolTip(
|
|
983
|
+
"This function processes entire folders and must run with 1 thread only."
|
|
984
|
+
)
|
|
985
|
+
|
|
986
|
+
# Add warning to description if not already present
|
|
987
|
+
if (
|
|
988
|
+
"IMPORTANT:" not in description
|
|
989
|
+
and "WARNING:" not in description
|
|
990
|
+
):
|
|
991
|
+
description += "\nThis function has to run single-threaded."
|
|
992
|
+
|
|
993
|
+
self.function_description.setText(description)
|
|
994
|
+
|
|
995
|
+
# Change the description color to make it more prominent
|
|
996
|
+
self.function_description.setStyleSheet(
|
|
997
|
+
"QLabel { color: #ff6b00; font-weight: bold; }"
|
|
998
|
+
)
|
|
999
|
+
else:
|
|
1000
|
+
# Re-enable threading controls for normal functions
|
|
1001
|
+
self.thread_count.setEnabled(True)
|
|
1002
|
+
self.thread_count.setToolTip(
|
|
1003
|
+
"Number of threads to use for parallel processing"
|
|
1004
|
+
)
|
|
1005
|
+
self.function_description.setStyleSheet("") # Reset styling
|
|
1006
|
+
self.function_description.setText(description)
|
|
1007
|
+
|
|
1008
|
+
# Get parameters
|
|
945
1009
|
parameters = function_info.get("parameters", {})
|
|
946
1010
|
|
|
947
1011
|
# Remove old parameters widget if it exists
|
|
@@ -1014,6 +1078,23 @@ class FileResultsWidget(QWidget):
|
|
|
1014
1078
|
self.batch_button.setEnabled(False)
|
|
1015
1079
|
self.cancel_button.setEnabled(True)
|
|
1016
1080
|
|
|
1081
|
+
# Set thread count based on function properties
|
|
1082
|
+
worker_thread_count = self.thread_count.value()
|
|
1083
|
+
|
|
1084
|
+
# Check if function should run single-threaded
|
|
1085
|
+
if (
|
|
1086
|
+
hasattr(processing_func, "thread_safe")
|
|
1087
|
+
and not processing_func.thread_safe
|
|
1088
|
+
):
|
|
1089
|
+
worker_thread_count = 1
|
|
1090
|
+
self.viewer.status = (
|
|
1091
|
+
"Processing with a single thread (function is not thread-safe)"
|
|
1092
|
+
)
|
|
1093
|
+
else:
|
|
1094
|
+
self.viewer.status = (
|
|
1095
|
+
f"Processing with {worker_thread_count} threads"
|
|
1096
|
+
)
|
|
1097
|
+
|
|
1017
1098
|
# Create and start the worker thread
|
|
1018
1099
|
self.worker = ProcessingWorker(
|
|
1019
1100
|
self.file_list,
|
|
@@ -1024,8 +1105,8 @@ class FileResultsWidget(QWidget):
|
|
|
1024
1105
|
output_suffix,
|
|
1025
1106
|
)
|
|
1026
1107
|
|
|
1027
|
-
# Set the thread count from the UI
|
|
1028
|
-
self.worker.thread_count =
|
|
1108
|
+
# Set the thread count from the UI or function attribute
|
|
1109
|
+
self.worker.thread_count = worker_thread_count
|
|
1029
1110
|
|
|
1030
1111
|
# Connect signals
|
|
1031
1112
|
self.worker.progress_updated.connect(self.update_progress)
|
|
@@ -1037,7 +1118,7 @@ class FileResultsWidget(QWidget):
|
|
|
1037
1118
|
self.worker.start()
|
|
1038
1119
|
|
|
1039
1120
|
# Update status
|
|
1040
|
-
self.viewer.status = f"Processing {len(self.file_list)} files with {selected_function_name} using {
|
|
1121
|
+
self.viewer.status = f"Processing {len(self.file_list)} files with {selected_function_name} using {worker_thread_count} threads"
|
|
1041
1122
|
|
|
1042
1123
|
def update_progress(self, value):
|
|
1043
1124
|
"""Update the progress bar"""
|
napari_tmidas/_version.py
CHANGED