napari-tmidas 0.1.8__tar.gz → 0.1.9__tar.gz

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.
Files changed (45) hide show
  1. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/PKG-INFO +39 -42
  2. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/README.md +29 -40
  3. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/pyproject.toml +9 -1
  4. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_crop_anything.py +137 -5
  5. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_file_conversion.py +40 -18
  6. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_file_selector.py +120 -13
  7. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_version.py +2 -2
  8. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/processing_functions/basic.py +104 -0
  9. napari_tmidas-0.1.9/src/napari_tmidas/processing_functions/cellpose_env_manager.py +172 -0
  10. napari_tmidas-0.1.9/src/napari_tmidas/processing_functions/cellpose_segmentation.py +511 -0
  11. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/processing_functions/colocalization.py +17 -19
  12. napari_tmidas-0.1.9/src/napari_tmidas/processing_functions/file_compression.py +205 -0
  13. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/processing_functions/skimage_filters.py +25 -6
  14. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/PKG-INFO +39 -42
  15. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/SOURCES.txt +3 -0
  16. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/requires.txt +8 -0
  17. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.github/dependabot.yml +0 -0
  18. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.github/workflows/test_and_deploy.yml +0 -0
  19. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.gitignore +0 -0
  20. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.napari-hub/DESCRIPTION.md +0 -0
  21. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.napari-hub/config.yml +0 -0
  22. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/.pre-commit-config.yaml +0 -0
  23. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/LICENSE +0 -0
  24. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/MANIFEST.in +0 -0
  25. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/setup.cfg +0 -0
  26. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/__init__.py +0 -0
  27. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_label_inspection.py +0 -0
  28. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_reader.py +0 -0
  29. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_registry.py +0 -0
  30. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_roi_colocalization.py +0 -0
  31. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_sample_data.py +0 -0
  32. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_tests/__init__.py +0 -0
  33. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_tests/test_reader.py +0 -0
  34. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_tests/test_sample_data.py +0 -0
  35. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_tests/test_widget.py +0 -0
  36. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_tests/test_writer.py +0 -0
  37. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_widget.py +0 -0
  38. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/_writer.py +0 -0
  39. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/napari.yaml +0 -0
  40. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/processing_functions/__init__.py +0 -0
  41. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas/processing_functions/scipy_filters.py +0 -0
  42. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/dependency_links.txt +0 -0
  43. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/entry_points.txt +0 -0
  44. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/src/napari_tmidas.egg-info/top_level.txt +0 -0
  45. {napari_tmidas-0.1.8 → napari_tmidas-0.1.9}/tox.ini +0 -0
@@ -1,7 +1,7 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: napari-tmidas
3
- Version: 0.1.8
4
- Summary: Tissue Microscopy Image Data Analysis Suite
3
+ Version: 0.1.9
4
+ Summary: A plugin for batch processing of confocal and whole-slide microscopy images of biological tissues
5
5
  Author: Marco Meer
6
6
  Author-email: marco.meer@pm.me
7
7
  License:
@@ -58,6 +58,14 @@ Requires-Dist: magicgui
58
58
  Requires-Dist: qtpy
59
59
  Requires-Dist: scikit-image
60
60
  Requires-Dist: pyqt5
61
+ Requires-Dist: tqdm
62
+ Requires-Dist: scikit-image
63
+ Requires-Dist: ome-zarr
64
+ Requires-Dist: napari-ome-zarr
65
+ Requires-Dist: torch
66
+ Requires-Dist: torchvision
67
+ Requires-Dist: timm
68
+ Requires-Dist: opencv-python
61
69
  Provides-Extra: testing
62
70
  Requires-Dist: tox; extra == "testing"
63
71
  Requires-Dist: pytest; extra == "testing"
@@ -75,34 +83,14 @@ Dynamic: license-file
75
83
  [![tests](https://github.com/macromeer/napari-tmidas/workflows/tests/badge.svg)](https://github.com/macromeer/napari-tmidas/actions)
76
84
  [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-tmidas)](https://napari-hub.org/plugins/napari-tmidas)
77
85
  <!-- [![codecov](https://codecov.io/gh/macromeer/napari-tmidas/branch/main/graph/badge.svg)](https://codecov.io/gh/macromeer/napari-tmidas) -->
78
- The `napari-tmidas` plugin consists of a growing collection of pipelines for fast batch processing of microscopy images. This is a WIP and based on the CLI version of [T-MIDAS](https://github.com/MercaderLabAnatomy/T-MIDAS).
79
-
80
- ## Feature Overview
81
-
82
- 1. **Image Processing**
83
- - Process image folders with: Gamma correction, Z-projection, channel splitting, Gaussian/median filters, thresholding (Otsu/manual), and label cleaning
84
-
85
- 2. **Label Inspection**
86
- - Review and edit label images with auto-save
87
-
88
- 3. **Microscopy Image Conversion**
89
- - Convert .nd2/.lif/.ndpi/.czi/acquifer → .tif/.zarr with metadata preservation
90
-
91
- 4. **Crop Anything**
92
- - Interactive ROI selection via click interface
93
-
94
- 5. **ROI Colocalization**
95
- - Count colocalized labels across multiple channels
96
-
97
-
98
-
99
- ### Coming Soon
100
- New features arriving April 2025
86
+ The `napari-tmidas` plugin consists of a growing collection of pipelines for fast batch processing of confocal and whole slide microscopy images of biological tissues. This is a WIP and based on the CLI version of [T-MIDAS](https://github.com/MercaderLabAnatomy/T-MIDAS).
101
87
 
88
+ ## Features
89
+ Currently, napari-tmidas provides pipelines as widgets for batch image conversion / cropping / processing, ROI colocalization and label inspection (cf. [Usage](#usage) below).
102
90
 
103
91
  ## Installation
104
92
 
105
- First install Napari in a virtual environment:
93
+ First, install Napari in a virtual environment:
106
94
 
107
95
  mamba create -y -n napari-tmidas -c conda-forge python=3.11 tqdm
108
96
  mamba activate napari-tmidas
@@ -112,19 +100,27 @@ Now you can install `napari-tmidas` via [pip]:
112
100
 
113
101
  pip install napari-tmidas
114
102
 
115
- To install the latest development version:
103
+ It is recommended to install the latest development version:
116
104
 
117
105
  pip install git+https://github.com/macromeer/napari-tmidas.git
118
106
 
119
107
  ### Dependencies
120
- To use the Batch Microscopy Image Conversion pipeline, we need some libraries to read microscopy formats and to write ome-zarr:
121
108
 
122
- pip install nd2 readlif tiffslide pylibCZIrw acquifer-napari ome-zarr napari-ome-zarr
109
+ To use the Batch Microscopy Image Conversion pipeline, we need some libraries to read microscopy formats:
110
+
111
+ pip install nd2 readlif tiffslide pylibCZIrw acquifer-napari
123
112
 
124
113
  For the Batch Crop Anything pipeline, we need to install MobileSAM and its dependencies:
125
114
 
126
115
  pip install git+https://github.com/ChaoningZhang/MobileSAM.git
127
- pip install torch torchvision timm opencv-python
116
+
117
+
118
+ If you want to batch compress images using [Zstandard](https://github.com/facebook/zstd), use the package manager of your operating system to install it:
119
+
120
+ sudo apt-get install zstd # for Linux
121
+ brew install zstd # for macOS
122
+ choco install zstandard # for Windows
123
+
128
124
 
129
125
  ## Usage
130
126
 
@@ -132,16 +128,15 @@ To use the plugin, start napari in the activated virtual environment with this t
132
128
 
133
129
  mamba run -n napari-tmidas napari
134
130
 
135
- You can find the installed plugin here:
136
-
137
- ![image](https://github.com/user-attachments/assets/504db09a-d66e-49eb-90cd-3237024d9d7a)
138
-
131
+ You can then find the installed plugin in the Plugins tab.
139
132
 
140
133
  ### Microscopy Image Conversion
141
134
 
142
135
  You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conversion`. Currently, this pipeline supports the conversion of `.nd2, .lif, .ndpi, .czi` and acquifer data. After scanning a folder of your choice for microscopy image data, select a file in the first column of the table and preview and export any image data it contains.
143
136
 
144
- ![image](https://github.com/user-attachments/assets/e377ca71-2f30-447d-825e-d2feebf7061b)
137
+
138
+ <img src="https://github.com/user-attachments/assets/e377ca71-2f30-447d-825e-d2feebf7061b" alt="Microscopy Image Conversion Widget" style="width:75%; height:auto;">
139
+
145
140
 
146
141
  ### Image Processing
147
142
 
@@ -149,7 +144,7 @@ You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conv
149
144
 
150
145
  ![image](https://github.com/user-attachments/assets/41ecb689-9abe-4371-83b5-9c5eb37069f9)
151
146
 
152
- 2. As a result, a table appears with the found images.
147
+ 2. As a result, a table appears with the found images. You can click on them to inspect them in the viewer.
153
148
 
154
149
  ![image](https://github.com/user-attachments/assets/8360942a-be8f-49ec-bc25-385ee43bd601)
155
150
 
@@ -158,26 +153,28 @@ You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conv
158
153
  ![image](https://github.com/user-attachments/assets/05929660-6672-4f76-89da-4f17749ccfad)
159
154
 
160
155
  4. You can click on the images in the table to show them in the viewer. For example first click on one of the `Original Files`, and then the corresponding `Processed File` to see an overlay.
156
+
157
+ <img src="https://github.com/user-attachments/assets/cfe84828-c1cc-4196-9a53-5dfb82d5bfce" alt="Image Processing Widget" style="width:75%; height:auto;">
161
158
 
162
- ![image](https://github.com/user-attachments/assets/cfe84828-c1cc-4196-9a53-5dfb82d5bfce)
163
159
 
164
160
  Note that whenever you click on an `Original File` or `Processed File` in the table, it will replace the one that is currently shown in the viewer. So naturally, you'd first select the original image, and then the processed image to correctly see the image pair that you want to inspect.
165
161
 
166
162
  ### Batch Label Inspection
167
163
  If you have already segmented a folder full of images and now you want to maybe inspect and edit each label image, you can use the `Plugins > T-MIDAS > Batch Label Inspection`, which automatically saves your changes to the existing label image once you click the `Save Changes and Continue` button (bottom right).
168
164
 
169
- ![image](https://github.com/user-attachments/assets/0bf8c6ae-4212-449d-8183-e91b23ba740e)
165
+ <img src="https://github.com/user-attachments/assets/0bf8c6ae-4212-449d-8183-e91b23ba740e" alt="Batch Label Inspection Widget" style="width:75%; height:auto;">
166
+
170
167
 
171
168
  ### Crop Anything
172
- This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`
169
+ This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`. Click the image below to see a video demo.
170
+
171
+ <img src="https://github.com/user-attachments/assets/6d72c2a2-1064-4a27-b398-a9b86fcbc443" alt="Crop Anything Widget" style="width:75%; height:auto;">
173
172
 
174
- ![image](https://github.com/user-attachments/assets/6d72c2a2-1064-4a27-b398-a9b86fcbc443)
175
173
 
176
174
  ### ROI Colocalization
177
175
  This pipeline quantifies colocalization between labeled regions of interest (ROIs) across multiple image channels. It determines the extent of overlap between ROIs in a reference channel and those in one or two other channels. The output is a table of colocalization counts. Optionally, the size of reference channel ROIs, as well as the total or median size of colocalizing ROIs in the other channels, can be included. Colocalization is determined using Boolean masking. The number of colocalizing instances is determined by counting unique label IDs within the overlapping regions. Typically, the reference channel contains larger structures, while other channels contain smaller, potentially nested, structures. For example, the reference channel might contain cell bodies, with the second and third channels containing nuclei and sub-nuclear objects, respectively.
178
176
 
179
- ![napari-tmidas_coloc_pipeline](https://github.com/user-attachments/assets/2f9022a0-7b88-4588-a448-250f07a634d7)
180
-
177
+ <img src="https://github.com/user-attachments/assets/2f9022a0-7b88-4588-a448-250f07a634d7" alt="ROI Colocalization Widget" style="width:75%; height:auto;">
181
178
 
182
179
  ## Contributing
183
180
 
@@ -6,34 +6,14 @@
6
6
  [![tests](https://github.com/macromeer/napari-tmidas/workflows/tests/badge.svg)](https://github.com/macromeer/napari-tmidas/actions)
7
7
  [![napari hub](https://img.shields.io/endpoint?url=https://api.napari-hub.org/shields/napari-tmidas)](https://napari-hub.org/plugins/napari-tmidas)
8
8
  <!-- [![codecov](https://codecov.io/gh/macromeer/napari-tmidas/branch/main/graph/badge.svg)](https://codecov.io/gh/macromeer/napari-tmidas) -->
9
- The `napari-tmidas` plugin consists of a growing collection of pipelines for fast batch processing of microscopy images. This is a WIP and based on the CLI version of [T-MIDAS](https://github.com/MercaderLabAnatomy/T-MIDAS).
10
-
11
- ## Feature Overview
12
-
13
- 1. **Image Processing**
14
- - Process image folders with: Gamma correction, Z-projection, channel splitting, Gaussian/median filters, thresholding (Otsu/manual), and label cleaning
15
-
16
- 2. **Label Inspection**
17
- - Review and edit label images with auto-save
18
-
19
- 3. **Microscopy Image Conversion**
20
- - Convert .nd2/.lif/.ndpi/.czi/acquifer → .tif/.zarr with metadata preservation
21
-
22
- 4. **Crop Anything**
23
- - Interactive ROI selection via click interface
24
-
25
- 5. **ROI Colocalization**
26
- - Count colocalized labels across multiple channels
27
-
28
-
29
-
30
- ### Coming Soon
31
- New features arriving April 2025
9
+ The `napari-tmidas` plugin consists of a growing collection of pipelines for fast batch processing of confocal and whole slide microscopy images of biological tissues. This is a WIP and based on the CLI version of [T-MIDAS](https://github.com/MercaderLabAnatomy/T-MIDAS).
32
10
 
11
+ ## Features
12
+ Currently, napari-tmidas provides pipelines as widgets for batch image conversion / cropping / processing, ROI colocalization and label inspection (cf. [Usage](#usage) below).
33
13
 
34
14
  ## Installation
35
15
 
36
- First install Napari in a virtual environment:
16
+ First, install Napari in a virtual environment:
37
17
 
38
18
  mamba create -y -n napari-tmidas -c conda-forge python=3.11 tqdm
39
19
  mamba activate napari-tmidas
@@ -43,19 +23,27 @@ Now you can install `napari-tmidas` via [pip]:
43
23
 
44
24
  pip install napari-tmidas
45
25
 
46
- To install the latest development version:
26
+ It is recommended to install the latest development version:
47
27
 
48
28
  pip install git+https://github.com/macromeer/napari-tmidas.git
49
29
 
50
30
  ### Dependencies
51
- To use the Batch Microscopy Image Conversion pipeline, we need some libraries to read microscopy formats and to write ome-zarr:
52
31
 
53
- pip install nd2 readlif tiffslide pylibCZIrw acquifer-napari ome-zarr napari-ome-zarr
32
+ To use the Batch Microscopy Image Conversion pipeline, we need some libraries to read microscopy formats:
33
+
34
+ pip install nd2 readlif tiffslide pylibCZIrw acquifer-napari
54
35
 
55
36
  For the Batch Crop Anything pipeline, we need to install MobileSAM and its dependencies:
56
37
 
57
38
  pip install git+https://github.com/ChaoningZhang/MobileSAM.git
58
- pip install torch torchvision timm opencv-python
39
+
40
+
41
+ If you want to batch compress images using [Zstandard](https://github.com/facebook/zstd), use the package manager of your operating system to install it:
42
+
43
+ sudo apt-get install zstd # for Linux
44
+ brew install zstd # for macOS
45
+ choco install zstandard # for Windows
46
+
59
47
 
60
48
  ## Usage
61
49
 
@@ -63,16 +51,15 @@ To use the plugin, start napari in the activated virtual environment with this t
63
51
 
64
52
  mamba run -n napari-tmidas napari
65
53
 
66
- You can find the installed plugin here:
67
-
68
- ![image](https://github.com/user-attachments/assets/504db09a-d66e-49eb-90cd-3237024d9d7a)
69
-
54
+ You can then find the installed plugin in the Plugins tab.
70
55
 
71
56
  ### Microscopy Image Conversion
72
57
 
73
58
  You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conversion`. Currently, this pipeline supports the conversion of `.nd2, .lif, .ndpi, .czi` and acquifer data. After scanning a folder of your choice for microscopy image data, select a file in the first column of the table and preview and export any image data it contains.
74
59
 
75
- ![image](https://github.com/user-attachments/assets/e377ca71-2f30-447d-825e-d2feebf7061b)
60
+
61
+ <img src="https://github.com/user-attachments/assets/e377ca71-2f30-447d-825e-d2feebf7061b" alt="Microscopy Image Conversion Widget" style="width:75%; height:auto;">
62
+
76
63
 
77
64
  ### Image Processing
78
65
 
@@ -80,7 +67,7 @@ You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conv
80
67
 
81
68
  ![image](https://github.com/user-attachments/assets/41ecb689-9abe-4371-83b5-9c5eb37069f9)
82
69
 
83
- 2. As a result, a table appears with the found images.
70
+ 2. As a result, a table appears with the found images. You can click on them to inspect them in the viewer.
84
71
 
85
72
  ![image](https://github.com/user-attachments/assets/8360942a-be8f-49ec-bc25-385ee43bd601)
86
73
 
@@ -89,26 +76,28 @@ You can start this pipeline via `Plugins > T-MIDAS > Batch Microscopy Image Conv
89
76
  ![image](https://github.com/user-attachments/assets/05929660-6672-4f76-89da-4f17749ccfad)
90
77
 
91
78
  4. You can click on the images in the table to show them in the viewer. For example first click on one of the `Original Files`, and then the corresponding `Processed File` to see an overlay.
79
+
80
+ <img src="https://github.com/user-attachments/assets/cfe84828-c1cc-4196-9a53-5dfb82d5bfce" alt="Image Processing Widget" style="width:75%; height:auto;">
92
81
 
93
- ![image](https://github.com/user-attachments/assets/cfe84828-c1cc-4196-9a53-5dfb82d5bfce)
94
82
 
95
83
  Note that whenever you click on an `Original File` or `Processed File` in the table, it will replace the one that is currently shown in the viewer. So naturally, you'd first select the original image, and then the processed image to correctly see the image pair that you want to inspect.
96
84
 
97
85
  ### Batch Label Inspection
98
86
  If you have already segmented a folder full of images and now you want to maybe inspect and edit each label image, you can use the `Plugins > T-MIDAS > Batch Label Inspection`, which automatically saves your changes to the existing label image once you click the `Save Changes and Continue` button (bottom right).
99
87
 
100
- ![image](https://github.com/user-attachments/assets/0bf8c6ae-4212-449d-8183-e91b23ba740e)
88
+ <img src="https://github.com/user-attachments/assets/0bf8c6ae-4212-449d-8183-e91b23ba740e" alt="Batch Label Inspection Widget" style="width:75%; height:auto;">
89
+
101
90
 
102
91
  ### Crop Anything
103
- This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`
92
+ This pipeline combines the Segment Anything Model (SAM) for automatic object detection with an interactive interface for selecting and cropping multiple objects from images. To launch the widget, open `Plugins > T-MIDAS > Batch Crop Anything`. Click the image below to see a video demo.
93
+
94
+ <img src="https://github.com/user-attachments/assets/6d72c2a2-1064-4a27-b398-a9b86fcbc443" alt="Crop Anything Widget" style="width:75%; height:auto;">
104
95
 
105
- ![image](https://github.com/user-attachments/assets/6d72c2a2-1064-4a27-b398-a9b86fcbc443)
106
96
 
107
97
  ### ROI Colocalization
108
98
  This pipeline quantifies colocalization between labeled regions of interest (ROIs) across multiple image channels. It determines the extent of overlap between ROIs in a reference channel and those in one or two other channels. The output is a table of colocalization counts. Optionally, the size of reference channel ROIs, as well as the total or median size of colocalizing ROIs in the other channels, can be included. Colocalization is determined using Boolean masking. The number of colocalizing instances is determined by counting unique label IDs within the overlapping regions. Typically, the reference channel contains larger structures, while other channels contain smaller, potentially nested, structures. For example, the reference channel might contain cell bodies, with the second and third channels containing nuclei and sub-nuclear objects, respectively.
109
99
 
110
- ![napari-tmidas_coloc_pipeline](https://github.com/user-attachments/assets/2f9022a0-7b88-4588-a448-250f07a634d7)
111
-
100
+ <img src="https://github.com/user-attachments/assets/2f9022a0-7b88-4588-a448-250f07a634d7" alt="ROI Colocalization Widget" style="width:75%; height:auto;">
112
101
 
113
102
  ## Contributing
114
103
 
@@ -1,7 +1,7 @@
1
1
  [project]
2
2
  name = "napari-tmidas"
3
3
  dynamic = ["version"]
4
- description = "Tissue Microscopy Image Data Analysis Suite"
4
+ description = "A plugin for batch processing of confocal and whole-slide microscopy images of biological tissues"
5
5
  readme = "README.md"
6
6
  license = {file = "LICENSE"}
7
7
  authors = [
@@ -30,6 +30,14 @@ dependencies = [
30
30
  "qtpy",
31
31
  "scikit-image",
32
32
  "pyqt5",
33
+ "tqdm",
34
+ "scikit-image",
35
+ "ome-zarr",
36
+ "napari-ome-zarr",
37
+ "torch",
38
+ "torchvision",
39
+ "timm",
40
+ "opencv-python",
33
41
  ]
34
42
 
35
43
  [project.optional-dependencies]
@@ -29,6 +29,7 @@ from qtpy.QtWidgets import (
29
29
  QWidget,
30
30
  )
31
31
  from skimage.io import imread
32
+ from skimage.transform import resize # Added import for resize function
32
33
  from tifffile import imwrite
33
34
 
34
35
 
@@ -48,6 +49,7 @@ class BatchCropAnything:
48
49
  self.original_image = None
49
50
  self.segmentation_result = None
50
51
  self.current_image_for_segmentation = None
52
+ self.current_scale_factor = 1.0 # Added scale factor tracking
51
53
 
52
54
  # UI references
53
55
  self.image_layer = None
@@ -356,10 +358,41 @@ class BatchCropAnything:
356
358
  # Convert back to uint8
357
359
  image_gamma = (image_gamma * 255).astype(np.uint8)
358
360
 
361
+ # Check if the image is very large and needs downscaling
362
+ orig_shape = image_gamma.shape[:2] # (height, width)
363
+
364
+ # Calculate image size in megapixels
365
+ image_mp = (orig_shape[0] * orig_shape[1]) / 1e6
366
+
367
+ # If image is larger than 2 megapixels, downscale it
368
+ max_mp = 2.0 # Maximum image size in megapixels
369
+ scale_factor = 1.0
370
+
371
+ if image_mp > max_mp:
372
+ scale_factor = np.sqrt(max_mp / image_mp)
373
+ new_height = int(orig_shape[0] * scale_factor)
374
+ new_width = int(orig_shape[1] * scale_factor)
375
+
376
+ self.viewer.status = f"Downscaling image from {orig_shape} to {(new_height, new_width)} for processing (scale: {scale_factor:.2f})"
377
+
378
+ # Resize the image for processing
379
+ image_gamma_resized = resize(
380
+ image_gamma,
381
+ (new_height, new_width),
382
+ anti_aliasing=True,
383
+ preserve_range=True,
384
+ ).astype(np.uint8)
385
+
386
+ # Store scale factor for later use
387
+ self.current_scale_factor = scale_factor
388
+ else:
389
+ image_gamma_resized = image_gamma
390
+ self.current_scale_factor = 1.0
391
+
359
392
  self.viewer.status = f"Generating segmentation with sensitivity {self.sensitivity} (gamma={gamma:.2f})..."
360
393
 
361
- # Generate masks with gamma-corrected image
362
- masks = self.mask_generator.generate(image_gamma)
394
+ # Generate masks with gamma-corrected and potentially resized image
395
+ masks = self.mask_generator.generate(image_gamma_resized)
363
396
  self.viewer.status = f"Generated {len(masks)} masks"
364
397
 
365
398
  if not masks:
@@ -390,9 +423,16 @@ class BatchCropAnything:
390
423
  return
391
424
 
392
425
  # Process segmentation masks
393
- self._process_segmentation_masks(
394
- masks, self.current_image_for_segmentation.shape[:2]
395
- )
426
+ # If image was downscaled, we need to ensure masks are upscaled correctly
427
+ if self.current_scale_factor < 1.0:
428
+ # Upscale the segmentation masks to match the original image dimensions
429
+ self._process_segmentation_masks_with_scaling(
430
+ masks, self.current_image_for_segmentation.shape[:2]
431
+ )
432
+ else:
433
+ self._process_segmentation_masks(
434
+ masks, self.current_image_for_segmentation.shape[:2]
435
+ )
396
436
 
397
437
  # Clear selected labels since segmentation has changed
398
438
  self.selected_labels = set()
@@ -475,6 +515,98 @@ class BatchCropAnything:
475
515
  # image_name = os.path.basename(self.images[self.current_index])
476
516
  self.viewer.status = f"Loaded image {self.current_index + 1}/{len(self.images)} - Found {len(masks)} segments"
477
517
 
518
+ # New method for handling scaled segmentation masks
519
+ def _process_segmentation_masks_with_scaling(self, masks, original_shape):
520
+ """Process segmentation masks with scaling to match the original image size."""
521
+ # Create label image from masks
522
+ # First determine the size of the mask predictions (which are at the downscaled resolution)
523
+ if not masks:
524
+ return
525
+
526
+ mask_shape = masks[0]["segmentation"].shape
527
+
528
+ # Create an empty label image at the downscaled resolution
529
+ downscaled_labels = np.zeros(mask_shape, dtype=np.uint32)
530
+ self.label_info = {} # Reset label info
531
+
532
+ # Fill in the downscaled labels
533
+ for i, mask_data in enumerate(masks):
534
+ mask = mask_data["segmentation"]
535
+ label_id = i + 1 # Start label IDs from 1
536
+ downscaled_labels[mask] = label_id
537
+
538
+ # Store basic label info
539
+ area = np.sum(mask)
540
+ y_indices, x_indices = np.where(mask)
541
+ center_y = np.mean(y_indices) if len(y_indices) > 0 else 0
542
+ center_x = np.mean(x_indices) if len(x_indices) > 0 else 0
543
+
544
+ # Scale centers to original image coordinates
545
+ center_y_orig = center_y / self.current_scale_factor
546
+ center_x_orig = center_x / self.current_scale_factor
547
+
548
+ # Store label info at original scale
549
+ self.label_info[label_id] = {
550
+ "area": area
551
+ / (
552
+ self.current_scale_factor**2
553
+ ), # Approximate area in original scale
554
+ "center_y": center_y_orig,
555
+ "center_x": center_x_orig,
556
+ "score": mask_data.get("stability_score", 0),
557
+ }
558
+
559
+ # Upscale the labels to the original image size
560
+ upscaled_labels = resize(
561
+ downscaled_labels,
562
+ original_shape,
563
+ order=0, # Nearest neighbor interpolation
564
+ preserve_range=True,
565
+ anti_aliasing=False,
566
+ ).astype(np.uint32)
567
+
568
+ # Sort labels by area (largest first)
569
+ self.label_info = dict(
570
+ sorted(
571
+ self.label_info.items(),
572
+ key=lambda item: item[1]["area"],
573
+ reverse=True,
574
+ )
575
+ )
576
+
577
+ # Save segmentation result
578
+ self.segmentation_result = upscaled_labels
579
+
580
+ # Remove existing label layer if exists
581
+ for layer in list(self.viewer.layers):
582
+ if isinstance(layer, Labels) and "Segmentation" in layer.name:
583
+ self.viewer.layers.remove(layer)
584
+
585
+ # Add label layer to viewer
586
+ self.label_layer = self.viewer.add_labels(
587
+ upscaled_labels,
588
+ name=f"Segmentation ({os.path.basename(self.images[self.current_index])})",
589
+ opacity=0.7,
590
+ )
591
+
592
+ # Make the label layer active by default
593
+ self.viewer.layers.selection.active = self.label_layer
594
+
595
+ # Disconnect existing callbacks if any
596
+ if (
597
+ hasattr(self, "label_layer")
598
+ and self.label_layer is not None
599
+ and hasattr(self.label_layer, "mouse_drag_callbacks")
600
+ ):
601
+ # Remove old callbacks
602
+ for callback in list(self.label_layer.mouse_drag_callbacks):
603
+ self.label_layer.mouse_drag_callbacks.remove(callback)
604
+
605
+ # Connect mouse click event to label selection
606
+ self.label_layer.mouse_drag_callbacks.append(self._on_label_clicked)
607
+
608
+ self.viewer.status = f"Loaded image {self.current_index + 1}/{len(self.images)} - Found {len(masks)} segments"
609
+
478
610
  # --------------------------------------------------
479
611
  # Label Selection and UI Elements
480
612
  # --------------------------------------------------
@@ -1105,19 +1105,21 @@ class ConversionWorker(QThread):
1105
1105
  )
1106
1106
  file_size_GB = estimated_size_bytes / (1024**3)
1107
1107
 
1108
- # If file is very large (>4GB), force zarr format regardless of setting
1108
+ # Determine format
1109
1109
  use_zarr = self.use_zarr
1110
- if file_size_GB > 4:
1111
- use_zarr = True
1112
- if not self.use_zarr:
1113
- print(
1114
- f"File size ({file_size_GB:.2f}GB) exceeds 4GB limit for TIF, automatically using ZARR format"
1115
- )
1116
- self.file_done.emit(
1117
- filepath,
1118
- True,
1119
- f"File size ({file_size_GB:.2f}GB) exceeds 4GB, using ZARR format",
1120
- )
1110
+ # If file is very large (>4GB) and user didn't explicitly choose TIF,
1111
+ # auto-switch to ZARR format
1112
+ if file_size_GB > 4 and not self.use_zarr:
1113
+ # Recommend ZARR format but respect user's choice by still allowing TIF
1114
+ print(
1115
+ f"File size ({file_size_GB:.2f}GB) exceeds 4GB, ZARR format is recommended but using TIF with BigTIFF format"
1116
+ )
1117
+ self.file_done.emit(
1118
+ filepath,
1119
+ True,
1120
+ f"File size ({file_size_GB:.2f}GB) exceeds 4GB, using TIF with BigTIFF format",
1121
+ )
1122
+
1121
1123
  # Set up the output path
1122
1124
  if use_zarr:
1123
1125
  output_path = os.path.join(
@@ -1171,12 +1173,22 @@ class ConversionWorker(QThread):
1171
1173
  def _save_tif(
1172
1174
  self, image_data: np.ndarray, output_path: str, metadata: dict = None
1173
1175
  ):
1174
- """Enhanced TIF saving with proper dimension handling"""
1176
+ """Enhanced TIF saving with proper dimension handling and BigTIFF support"""
1175
1177
  import tifffile
1176
1178
 
1177
1179
  print(f"Saving TIF file: {output_path}")
1178
1180
  print(f"Image data shape: {image_data.shape}")
1179
1181
 
1182
+ # Check if this is a large file that needs BigTIFF
1183
+ estimated_size_bytes = np.prod(image_data.shape) * image_data.itemsize
1184
+ file_size_GB = estimated_size_bytes / (1024**3)
1185
+ use_bigtiff = file_size_GB > 4
1186
+
1187
+ if use_bigtiff:
1188
+ print(
1189
+ f"File size ({file_size_GB:.2f}GB) exceeds 4GB, using BigTIFF format"
1190
+ )
1191
+
1180
1192
  if metadata:
1181
1193
  print(f"Metadata keys: {list(metadata.keys())}")
1182
1194
  if "axes" in metadata:
@@ -1198,7 +1210,12 @@ class ConversionWorker(QThread):
1198
1210
  # Basic save if no metadata
1199
1211
  if metadata is None:
1200
1212
  print("No metadata provided, using basic save")
1201
- tifffile.imwrite(output_path, image_data, compression="zstd")
1213
+ tifffile.imwrite(
1214
+ output_path,
1215
+ image_data,
1216
+ compression="zlib",
1217
+ bigtiff=use_bigtiff,
1218
+ )
1202
1219
  return
1203
1220
 
1204
1221
  # Get image dimensions and axis order
@@ -1261,7 +1278,10 @@ class ConversionWorker(QThread):
1261
1278
  print(f"Error reordering dimensions: {e}")
1262
1279
  # Fall back to simple save without reordering
1263
1280
  tifffile.imwrite(
1264
- output_path, image_data, compression="zstd"
1281
+ output_path,
1282
+ image_data,
1283
+ compression="zlib",
1284
+ bigtiff=use_bigtiff,
1265
1285
  )
1266
1286
  return
1267
1287
 
@@ -1287,7 +1307,8 @@ class ConversionWorker(QThread):
1287
1307
  output_path,
1288
1308
  image_data,
1289
1309
  resolution=resolution,
1290
- compression="zstd",
1310
+ compression="zlib",
1311
+ bigtiff=use_bigtiff,
1291
1312
  )
1292
1313
  else:
1293
1314
  # Hyperstack case
@@ -1306,14 +1327,15 @@ class ConversionWorker(QThread):
1306
1327
  imagej=True,
1307
1328
  resolution=resolution,
1308
1329
  metadata=imagej_metadata,
1309
- compression="zstd",
1330
+ compression="zlib",
1331
+ bigtiff=use_bigtiff,
1310
1332
  )
1311
1333
 
1312
1334
  print(f"Successfully saved TIF file: {output_path}")
1313
1335
  except (ValueError, FileNotFoundError) as e:
1314
1336
  print(f"Error saving TIF file: {e}")
1315
1337
  # Try simple save as fallback
1316
- tifffile.imwrite(output_path, image_data)
1338
+ tifffile.imwrite(output_path, image_data, bigtiff=use_bigtiff)
1317
1339
 
1318
1340
  def _save_zarr(
1319
1341
  self, image_data: np.ndarray, output_path: str, metadata: dict = None