napari-dpr 0.1.0__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.
- napari_dpr-0.1.0/LICENSE +21 -0
- napari_dpr-0.1.0/PKG-INFO +149 -0
- napari_dpr-0.1.0/README.md +105 -0
- napari_dpr-0.1.0/pyproject.toml +84 -0
- napari_dpr-0.1.0/setup.cfg +4 -0
- napari_dpr-0.1.0/setup.py +43 -0
- napari_dpr-0.1.0/src/napari_dpr/__init__.py +9 -0
- napari_dpr-0.1.0/src/napari_dpr/_widget.py +88 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr.py +131 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cp310-win_amd64.pyd +0 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cp311-win_amd64.pyd +0 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cp312-win_amd64.pyd +0 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cp313-win_amd64.pyd +0 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cp39-win_amd64.pyd +0 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.cpp +15410 -0
- napari_dpr-0.1.0/src/napari_dpr/dpr_core.pyx +103 -0
- napari_dpr-0.1.0/src/napari_dpr/example.py +46 -0
- napari_dpr-0.1.0/src/napari_dpr/napari.yaml +10 -0
- napari_dpr-0.1.0/src/napari_dpr/run.dpr.py +68 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/PKG-INFO +149 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/SOURCES.txt +24 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/dependency_links.txt +1 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/entry_points.txt +2 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/requires.txt +20 -0
- napari_dpr-0.1.0/src/napari_dpr.egg-info/top_level.txt +1 -0
napari_dpr-0.1.0/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
MIT License
|
2
|
+
|
3
|
+
Copyright (c) 2025 JenuC
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
13
|
+
copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
21
|
+
SOFTWARE.
|
@@ -0,0 +1,149 @@
|
|
1
|
+
Metadata-Version: 2.4
|
2
|
+
Name: napari-dpr
|
3
|
+
Version: 0.1.0
|
4
|
+
Summary: Napari plugin for DPR Resolution Enhancement
|
5
|
+
Author-email: JenuC <jenu.chacko@wisc.edu>
|
6
|
+
License-Expression: MIT
|
7
|
+
Project-URL: Homepage, https://github.com/jenuc/napari-dpr
|
8
|
+
Project-URL: Bug Tracker, https://github.com/jenuc/napari-dpr/issues
|
9
|
+
Project-URL: Documentation, https://github.com/jenuc/napari-dpr#README.md
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
12
|
+
Classifier: Programming Language :: Python :: 3.9
|
13
|
+
Classifier: Programming Language :: Python :: 3.10
|
14
|
+
Classifier: Programming Language :: Python :: 3.11
|
15
|
+
Classifier: Programming Language :: Python :: 3.12
|
16
|
+
Classifier: Programming Language :: Python :: 3.13
|
17
|
+
Classifier: Operating System :: OS Independent
|
18
|
+
Classifier: Framework :: napari
|
19
|
+
Classifier: Intended Audience :: Science/Research
|
20
|
+
Classifier: Topic :: Scientific/Engineering :: Bio-Informatics
|
21
|
+
Classifier: Topic :: Scientific/Engineering :: Image Processing
|
22
|
+
Requires-Python: >=3.9
|
23
|
+
Description-Content-Type: text/markdown
|
24
|
+
License-File: LICENSE
|
25
|
+
Requires-Dist: napari>=0.4.18
|
26
|
+
Requires-Dist: numpy>=1.24.3
|
27
|
+
Requires-Dist: scipy>=1.10.1
|
28
|
+
Requires-Dist: matplotlib>=3.7.2
|
29
|
+
Requires-Dist: cython>=0.29.0
|
30
|
+
Requires-Dist: setuptools>=42.0.0
|
31
|
+
Requires-Dist: tifffile
|
32
|
+
Requires-Dist: pillow
|
33
|
+
Requires-Dist: magicgui>=0.5.0
|
34
|
+
Requires-Dist: qtpy
|
35
|
+
Provides-Extra: dev
|
36
|
+
Requires-Dist: pytest; extra == "dev"
|
37
|
+
Requires-Dist: build; extra == "dev"
|
38
|
+
Requires-Dist: twine; extra == "dev"
|
39
|
+
Requires-Dist: cibuildwheel; extra == "dev"
|
40
|
+
Provides-Extra: testing
|
41
|
+
Requires-Dist: pytest; extra == "testing"
|
42
|
+
Requires-Dist: pytest-qt; extra == "testing"
|
43
|
+
Dynamic: license-file
|
44
|
+
|
45
|
+
# napari-dpr
|
46
|
+
|
47
|
+
[](https://opensource.org/licenses/MIT)
|
48
|
+
[](https://pypi.org/project/napari-dpr)
|
49
|
+
[](https://python.org)
|
50
|
+
[](https://napari-hub.org/plugins/napari-dpr)
|
51
|
+
|
52
|
+
> ## ⚠️ IMPORTANT: Original Work Acknowledgment
|
53
|
+
> This napari plugin is based on and extends the work from the original [DPR-Resolution_enhancement_with_deblurring_by_pixel_reassignment](https://github.com/biomicroscopy/DPR-Resolution_enhancement_with_deblurring_by_pixel_reassignment) repository.
|
54
|
+
>
|
55
|
+
> The algorithm was originally developed by Zhao, B. and Mertz, J., as described in their paper ["Resolution enhancement with deblurring by pixel reassignment (DPR)"](https://www.spiedigitallibrary.org/journals/advanced-photonics/volume-5/issue-06/066004/Resolution-enhancement-with-deblurring-by-pixel-reassignment/10.1117/1.AP.5.6.066004.full) (DOI: 10.1117/1.AP.5.6.066004).
|
56
|
+
>
|
57
|
+
> <img src="docs/images/schematic.png" alt="DPR Algorithm Schematic" width="50%">
|
58
|
+
>
|
59
|
+
> **If you use this plugin for your research, please cite the original paper:**
|
60
|
+
> ```
|
61
|
+
> Zhao, B., and Mertz, J. "Resolution enhancement with deblurring by pixel reassignment (DPR)."
|
62
|
+
> Advanced Photonics, 5(6), 066004 (2023). DOI: 10.1117/1.AP.5.6.066004
|
63
|
+
> ```
|
64
|
+
|
65
|
+
A napari plugin for image resolution enhancement using Deconvolution by Pixel Reassignment (DPR).
|
66
|
+
|
67
|
+
## Description
|
68
|
+
|
69
|
+
DPR is a technique for enhancing the resolution of images, particularly useful in microscopy. This plugin provides easy access to DPR functionality within napari, allowing for quick and intuitive image enhancement without leaving your viewer.
|
70
|
+
|
71
|
+
The algorithm works by:
|
72
|
+
1. Applying a specialized deconvolution approach
|
73
|
+
2. Reassigning pixels based on local information
|
74
|
+
3. Enhancing fine details while preserving image structure
|
75
|
+
|
76
|
+
## Installation
|
77
|
+
|
78
|
+
You can install `napari-dpr` via [pip]:
|
79
|
+
|
80
|
+
```bash
|
81
|
+
pip install napari-dpr
|
82
|
+
```
|
83
|
+
|
84
|
+
## Usage
|
85
|
+
|
86
|
+
1. Open napari and load an image
|
87
|
+
2. In the menu, go to `Plugins > DPR Enhancement`
|
88
|
+
3. Select your image from the dropdown
|
89
|
+
4. Adjust parameters as needed:
|
90
|
+
- **PSF**: Point spread function size (typical values: 2-6)
|
91
|
+
- **Gain**: Enhancement gain (typical values: 1-3)
|
92
|
+
- **Background**: Background subtraction (typical values: 5-20)
|
93
|
+
5. Click "Enhance Resolution"
|
94
|
+
6. Two new layers will be added to your viewer:
|
95
|
+
- `[original_name]_DPR_enhanced`: The DPR-enhanced image
|
96
|
+
- `[original_name]_magnified`: The magnified original for comparison
|
97
|
+
|
98
|
+
## Parameters
|
99
|
+
|
100
|
+
- **PSF** (Point Spread Function): Controls the width of the point spread function used in the algorithm. Larger values capture wider spatial correlations but may reduce detail resolution.
|
101
|
+
- **Gain**: Controls the enhancement strength. Higher values increase contrast but may introduce artifacts.
|
102
|
+
- **Background**: Controls background subtraction. Higher values remove more background but may affect relevant image features.
|
103
|
+
|
104
|
+
## Standalone Usage
|
105
|
+
|
106
|
+
You can also use the DPR algorithm programmatically:
|
107
|
+
|
108
|
+
```python
|
109
|
+
from napari_dpr.dpr_core import apply_dpr
|
110
|
+
import numpy as np
|
111
|
+
import matplotlib.pyplot as plt
|
112
|
+
|
113
|
+
# Load your image data (should be 3D: HEIGHT, WIDTH, TIME)
|
114
|
+
image_data = your_image_loading_function()
|
115
|
+
if image_data.ndim == 2:
|
116
|
+
image_data = image_data[:, :, np.newaxis] # Add time dimension if 2D
|
117
|
+
|
118
|
+
# Apply DPR
|
119
|
+
dpr_enhanced, magnified = apply_dpr(image_data, psf=4.0, gain=2.0, background=10.0)
|
120
|
+
|
121
|
+
# Visualize results
|
122
|
+
plt.figure(figsize=(12, 6))
|
123
|
+
plt.subplot(121)
|
124
|
+
plt.title("Original (Magnified)")
|
125
|
+
plt.imshow(magnified.sum(axis=2))
|
126
|
+
plt.subplot(122)
|
127
|
+
plt.title("DPR Enhanced")
|
128
|
+
plt.imshow(dpr_enhanced)
|
129
|
+
plt.tight_layout()
|
130
|
+
plt.show()
|
131
|
+
```
|
132
|
+
|
133
|
+
## Contributing
|
134
|
+
|
135
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
136
|
+
|
137
|
+
## License
|
138
|
+
|
139
|
+
Distributed under the terms of the [MIT] license,
|
140
|
+
"napari-dpr" is free and open source software.
|
141
|
+
|
142
|
+
## Issues
|
143
|
+
|
144
|
+
If you encounter any problems, please [file an issue] along with a detailed description.
|
145
|
+
|
146
|
+
[file an issue]: https://github.com/jenuc/napari-dpr/issues
|
147
|
+
[napari]: https://github.com/napari/napari
|
148
|
+
[pip]: https://pypi.org/project/pip/
|
149
|
+
[MIT]: https://opensource.org/licenses/MIT
|
@@ -0,0 +1,105 @@
|
|
1
|
+
# napari-dpr
|
2
|
+
|
3
|
+
[](https://opensource.org/licenses/MIT)
|
4
|
+
[](https://pypi.org/project/napari-dpr)
|
5
|
+
[](https://python.org)
|
6
|
+
[](https://napari-hub.org/plugins/napari-dpr)
|
7
|
+
|
8
|
+
> ## ⚠️ IMPORTANT: Original Work Acknowledgment
|
9
|
+
> This napari plugin is based on and extends the work from the original [DPR-Resolution_enhancement_with_deblurring_by_pixel_reassignment](https://github.com/biomicroscopy/DPR-Resolution_enhancement_with_deblurring_by_pixel_reassignment) repository.
|
10
|
+
>
|
11
|
+
> The algorithm was originally developed by Zhao, B. and Mertz, J., as described in their paper ["Resolution enhancement with deblurring by pixel reassignment (DPR)"](https://www.spiedigitallibrary.org/journals/advanced-photonics/volume-5/issue-06/066004/Resolution-enhancement-with-deblurring-by-pixel-reassignment/10.1117/1.AP.5.6.066004.full) (DOI: 10.1117/1.AP.5.6.066004).
|
12
|
+
>
|
13
|
+
> <img src="docs/images/schematic.png" alt="DPR Algorithm Schematic" width="50%">
|
14
|
+
>
|
15
|
+
> **If you use this plugin for your research, please cite the original paper:**
|
16
|
+
> ```
|
17
|
+
> Zhao, B., and Mertz, J. "Resolution enhancement with deblurring by pixel reassignment (DPR)."
|
18
|
+
> Advanced Photonics, 5(6), 066004 (2023). DOI: 10.1117/1.AP.5.6.066004
|
19
|
+
> ```
|
20
|
+
|
21
|
+
A napari plugin for image resolution enhancement using Deconvolution by Pixel Reassignment (DPR).
|
22
|
+
|
23
|
+
## Description
|
24
|
+
|
25
|
+
DPR is a technique for enhancing the resolution of images, particularly useful in microscopy. This plugin provides easy access to DPR functionality within napari, allowing for quick and intuitive image enhancement without leaving your viewer.
|
26
|
+
|
27
|
+
The algorithm works by:
|
28
|
+
1. Applying a specialized deconvolution approach
|
29
|
+
2. Reassigning pixels based on local information
|
30
|
+
3. Enhancing fine details while preserving image structure
|
31
|
+
|
32
|
+
## Installation
|
33
|
+
|
34
|
+
You can install `napari-dpr` via [pip]:
|
35
|
+
|
36
|
+
```bash
|
37
|
+
pip install napari-dpr
|
38
|
+
```
|
39
|
+
|
40
|
+
## Usage
|
41
|
+
|
42
|
+
1. Open napari and load an image
|
43
|
+
2. In the menu, go to `Plugins > DPR Enhancement`
|
44
|
+
3. Select your image from the dropdown
|
45
|
+
4. Adjust parameters as needed:
|
46
|
+
- **PSF**: Point spread function size (typical values: 2-6)
|
47
|
+
- **Gain**: Enhancement gain (typical values: 1-3)
|
48
|
+
- **Background**: Background subtraction (typical values: 5-20)
|
49
|
+
5. Click "Enhance Resolution"
|
50
|
+
6. Two new layers will be added to your viewer:
|
51
|
+
- `[original_name]_DPR_enhanced`: The DPR-enhanced image
|
52
|
+
- `[original_name]_magnified`: The magnified original for comparison
|
53
|
+
|
54
|
+
## Parameters
|
55
|
+
|
56
|
+
- **PSF** (Point Spread Function): Controls the width of the point spread function used in the algorithm. Larger values capture wider spatial correlations but may reduce detail resolution.
|
57
|
+
- **Gain**: Controls the enhancement strength. Higher values increase contrast but may introduce artifacts.
|
58
|
+
- **Background**: Controls background subtraction. Higher values remove more background but may affect relevant image features.
|
59
|
+
|
60
|
+
## Standalone Usage
|
61
|
+
|
62
|
+
You can also use the DPR algorithm programmatically:
|
63
|
+
|
64
|
+
```python
|
65
|
+
from napari_dpr.dpr_core import apply_dpr
|
66
|
+
import numpy as np
|
67
|
+
import matplotlib.pyplot as plt
|
68
|
+
|
69
|
+
# Load your image data (should be 3D: HEIGHT, WIDTH, TIME)
|
70
|
+
image_data = your_image_loading_function()
|
71
|
+
if image_data.ndim == 2:
|
72
|
+
image_data = image_data[:, :, np.newaxis] # Add time dimension if 2D
|
73
|
+
|
74
|
+
# Apply DPR
|
75
|
+
dpr_enhanced, magnified = apply_dpr(image_data, psf=4.0, gain=2.0, background=10.0)
|
76
|
+
|
77
|
+
# Visualize results
|
78
|
+
plt.figure(figsize=(12, 6))
|
79
|
+
plt.subplot(121)
|
80
|
+
plt.title("Original (Magnified)")
|
81
|
+
plt.imshow(magnified.sum(axis=2))
|
82
|
+
plt.subplot(122)
|
83
|
+
plt.title("DPR Enhanced")
|
84
|
+
plt.imshow(dpr_enhanced)
|
85
|
+
plt.tight_layout()
|
86
|
+
plt.show()
|
87
|
+
```
|
88
|
+
|
89
|
+
## Contributing
|
90
|
+
|
91
|
+
Contributions are welcome! Please feel free to submit a Pull Request.
|
92
|
+
|
93
|
+
## License
|
94
|
+
|
95
|
+
Distributed under the terms of the [MIT] license,
|
96
|
+
"napari-dpr" is free and open source software.
|
97
|
+
|
98
|
+
## Issues
|
99
|
+
|
100
|
+
If you encounter any problems, please [file an issue] along with a detailed description.
|
101
|
+
|
102
|
+
[file an issue]: https://github.com/jenuc/napari-dpr/issues
|
103
|
+
[napari]: https://github.com/napari/napari
|
104
|
+
[pip]: https://pypi.org/project/pip/
|
105
|
+
[MIT]: https://opensource.org/licenses/MIT
|
@@ -0,0 +1,84 @@
|
|
1
|
+
[build-system]
|
2
|
+
requires = ["setuptools>=61.0.0", "wheel", "cython>=0.29.0", "numpy>=1.24.3"]
|
3
|
+
build-backend = "setuptools.build_meta"
|
4
|
+
|
5
|
+
[project]
|
6
|
+
name = "napari-dpr"
|
7
|
+
version = "0.1.0"
|
8
|
+
description = "Napari plugin for DPR Resolution Enhancement"
|
9
|
+
readme = "README.md"
|
10
|
+
requires-python = ">=3.9"
|
11
|
+
license = "MIT"
|
12
|
+
authors = [
|
13
|
+
{name = "JenuC", email = "jenu.chacko@wisc.edu"}
|
14
|
+
]
|
15
|
+
classifiers = [
|
16
|
+
"Development Status :: 3 - Alpha",
|
17
|
+
"Programming Language :: Python :: 3",
|
18
|
+
"Programming Language :: Python :: 3.9",
|
19
|
+
"Programming Language :: Python :: 3.10",
|
20
|
+
"Programming Language :: Python :: 3.11",
|
21
|
+
"Programming Language :: Python :: 3.12",
|
22
|
+
"Programming Language :: Python :: 3.13",
|
23
|
+
"Operating System :: OS Independent",
|
24
|
+
"Framework :: napari",
|
25
|
+
"Intended Audience :: Science/Research",
|
26
|
+
"Topic :: Scientific/Engineering :: Bio-Informatics",
|
27
|
+
"Topic :: Scientific/Engineering :: Image Processing",
|
28
|
+
]
|
29
|
+
dependencies = [
|
30
|
+
"napari>=0.4.18",
|
31
|
+
"numpy>=1.24.3",
|
32
|
+
"scipy>=1.10.1",
|
33
|
+
"matplotlib>=3.7.2",
|
34
|
+
"cython>=0.29.0",
|
35
|
+
"setuptools>=42.0.0",
|
36
|
+
"tifffile",
|
37
|
+
"pillow",
|
38
|
+
"magicgui>=0.5.0",
|
39
|
+
"qtpy",
|
40
|
+
]
|
41
|
+
|
42
|
+
[project.optional-dependencies]
|
43
|
+
dev = ["pytest", "build", "twine", "cibuildwheel"]
|
44
|
+
testing = ["pytest", "pytest-qt"]
|
45
|
+
|
46
|
+
[project.urls]
|
47
|
+
"Homepage" = "https://github.com/jenuc/napari-dpr"
|
48
|
+
"Bug Tracker" = "https://github.com/jenuc/napari-dpr/issues"
|
49
|
+
"Documentation" = "https://github.com/jenuc/napari-dpr#README.md"
|
50
|
+
|
51
|
+
[tool.setuptools]
|
52
|
+
package-dir = {"" = "src"}
|
53
|
+
packages = ["napari_dpr"]
|
54
|
+
|
55
|
+
[tool.setuptools.package-data]
|
56
|
+
"napari_dpr" = ["*.yaml", "*.pyx", "*.pyd"]
|
57
|
+
|
58
|
+
[project.entry-points."napari.manifest"]
|
59
|
+
napari-dpr = "napari_dpr:napari.yaml"
|
60
|
+
|
61
|
+
# Configuration for building wheels
|
62
|
+
[tool.cibuildwheel]
|
63
|
+
# Python versions to build wheels for - use underscore to separate items
|
64
|
+
build = ["cp39-*", "cp310-*", "cp311-*", "cp312-*", "cp313-*"]
|
65
|
+
# Skip 32-bit builds and musllinux builds
|
66
|
+
skip = ["*-win32", "*-manylinux_i686", "*-musllinux_*"]
|
67
|
+
|
68
|
+
# Build only for 64-bit architectures
|
69
|
+
archs = ["auto64"]
|
70
|
+
|
71
|
+
# Configure environment variables for building
|
72
|
+
[tool.cibuildwheel.environment]
|
73
|
+
CFLAGS = "-O3"
|
74
|
+
CXXFLAGS = "-O3"
|
75
|
+
|
76
|
+
# Windows specific settings
|
77
|
+
[tool.cibuildwheel.windows]
|
78
|
+
# Explicitly target 64-bit Windows for specific Python versions
|
79
|
+
build = ["cp39-win_amd64", "cp310-win_amd64", "cp311-win_amd64", "cp312-win_amd64", "cp313-win_amd64"]
|
80
|
+
|
81
|
+
# macOS specific settings
|
82
|
+
[tool.cibuildwheel.macos]
|
83
|
+
# Target only 64-bit builds for macOS
|
84
|
+
archs = ["x86_64", "arm64"]
|
@@ -0,0 +1,43 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
from setuptools import setup, Extension, find_packages
|
3
|
+
from Cython.Build import cythonize
|
4
|
+
import numpy as np
|
5
|
+
import sys
|
6
|
+
import os
|
7
|
+
|
8
|
+
# Ensure we're building extensions inplace
|
9
|
+
if 'build_ext' not in sys.argv:
|
10
|
+
sys.argv.append('build_ext')
|
11
|
+
if '--inplace' not in sys.argv:
|
12
|
+
sys.argv.append('--inplace')
|
13
|
+
|
14
|
+
# Make sure the compiled .pyd file can be imported from the package
|
15
|
+
if not os.path.exists("src/napari_dpr"):
|
16
|
+
os.makedirs("src/napari_dpr", exist_ok=True)
|
17
|
+
|
18
|
+
# Define the extension module - using correct package path
|
19
|
+
ext_modules = [
|
20
|
+
Extension(
|
21
|
+
"napari_dpr.dpr_core", # This will create dpr_core.pyd in the napari_dpr package
|
22
|
+
["src/napari_dpr/dpr_core.pyx"], # Source file in the napari_dpr package
|
23
|
+
include_dirs=[np.get_include()],
|
24
|
+
language="c++",
|
25
|
+
define_macros=[("NPY_NO_DEPRECATED_API", "NPY_1_7_API_VERSION")],
|
26
|
+
extra_compile_args=["-O3"],
|
27
|
+
),
|
28
|
+
]
|
29
|
+
|
30
|
+
setup(
|
31
|
+
ext_modules=cythonize(
|
32
|
+
ext_modules,
|
33
|
+
compiler_directives={
|
34
|
+
'language_level': 3,
|
35
|
+
'boundscheck': False,
|
36
|
+
'wraparound': False,
|
37
|
+
'cdivision': True,
|
38
|
+
}
|
39
|
+
),
|
40
|
+
# Ensure the extension is properly placed in the package directory
|
41
|
+
package_dir={"": "src"},
|
42
|
+
packages=find_packages(where="src"),
|
43
|
+
)
|
@@ -0,0 +1,88 @@
|
|
1
|
+
"""
|
2
|
+
Napari plugin widget for DPR resolution enhancement.
|
3
|
+
"""
|
4
|
+
from typing import TYPE_CHECKING
|
5
|
+
import numpy as np
|
6
|
+
from magicgui import magic_factory
|
7
|
+
from napari_dpr.dpr_core import apply_dpr
|
8
|
+
|
9
|
+
if TYPE_CHECKING:
|
10
|
+
import napari
|
11
|
+
|
12
|
+
@magic_factory(
|
13
|
+
psf={"widget_type": "FloatSpinBox", "min": 1.0, "max": 10.0, "step": 0.1, "value": 4.0},
|
14
|
+
gain={"widget_type": "FloatSpinBox", "min": 0.1, "max": 10.0, "step": 0.1, "value": 2.0},
|
15
|
+
background={"widget_type": "FloatSpinBox", "min": 0.0, "max": 50.0, "step": 1.0, "value": 10.0},
|
16
|
+
call_button="Enhance Resolution"
|
17
|
+
)
|
18
|
+
def enhance_image(
|
19
|
+
viewer: "napari.viewer.Viewer",
|
20
|
+
image_layer: "napari.layers.Image",
|
21
|
+
psf: float = 4.0,
|
22
|
+
gain: float = 2.0,
|
23
|
+
background: float = 10.0,
|
24
|
+
) -> None:
|
25
|
+
"""
|
26
|
+
Enhance image resolution using DPR.
|
27
|
+
|
28
|
+
Parameters
|
29
|
+
----------
|
30
|
+
viewer : napari.viewer.Viewer
|
31
|
+
Napari viewer instance
|
32
|
+
image_layer : napari.layers.Image
|
33
|
+
Input image layer to enhance
|
34
|
+
psf : float
|
35
|
+
Point spread function size parameter
|
36
|
+
gain : float
|
37
|
+
Gain parameter for enhancement
|
38
|
+
background : float
|
39
|
+
Background subtraction value
|
40
|
+
"""
|
41
|
+
if image_layer is None:
|
42
|
+
raise ValueError("Please select an image layer")
|
43
|
+
|
44
|
+
# Get the image data
|
45
|
+
image_data = image_layer.data
|
46
|
+
|
47
|
+
# Make sure image has the right dimensions and type
|
48
|
+
# DPR expects a 3D array (HEIGHT, WIDTH, TIME/CHANNELS)
|
49
|
+
if image_data.ndim == 2:
|
50
|
+
# Convert 2D image to 3D with one time point
|
51
|
+
image_data = image_data[:, :, np.newaxis]
|
52
|
+
elif image_data.ndim == 3 and image_data.shape[0] < image_data.shape[1]:
|
53
|
+
# If first dimension is smallest, it's probably [TIME, HEIGHT, WIDTH]
|
54
|
+
# We need to transpose to [HEIGHT, WIDTH, TIME]
|
55
|
+
image_data = image_data.transpose([1, 2, 0])
|
56
|
+
elif image_data.ndim > 3:
|
57
|
+
# If 4D or more, take the first 3 dimensions
|
58
|
+
image_data = image_data[:, :, :, 0]
|
59
|
+
|
60
|
+
# Ensure data is float64
|
61
|
+
if image_data.dtype != np.float64:
|
62
|
+
image_data = image_data.astype(np.float64)
|
63
|
+
|
64
|
+
# Apply DPR
|
65
|
+
try:
|
66
|
+
dpr_out, magnified = apply_dpr(image_data, psf=psf, gain=gain, background=background)
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
# Add the magnified original for comparison
|
71
|
+
viewer.add_image(
|
72
|
+
magnified.sum(axis=2), # Sum over the time/channel dimension
|
73
|
+
name=f"{image_layer.name}_magnified",
|
74
|
+
colormap=image_layer.colormap.name,
|
75
|
+
)
|
76
|
+
|
77
|
+
# Add the enhanced image to the viewer
|
78
|
+
viewer.add_image(
|
79
|
+
dpr_out,
|
80
|
+
name=f"{image_layer.name}_DPR_enhanced",
|
81
|
+
colormap=image_layer.colormap.name,
|
82
|
+
)
|
83
|
+
|
84
|
+
except Exception as e:
|
85
|
+
import traceback
|
86
|
+
print(f"Error applying DPR: {e}")
|
87
|
+
print(traceback.format_exc())
|
88
|
+
raise
|
@@ -0,0 +1,131 @@
|
|
1
|
+
import os, sys, time, numpy as np, scipy.ndimage as ndi
|
2
|
+
from scipy.interpolate import RectBivariateSpline
|
3
|
+
import tifffile as tiff
|
4
|
+
from PIL import Image
|
5
|
+
import matplotlib.pyplot as plt
|
6
|
+
|
7
|
+
## original DPR as shown by https://github.com/biomicroscopy/DPR-Resolution_enhancement_with_deblurring_by_pixel_reassignment
|
8
|
+
|
9
|
+
def dpr_set_parameters(psf, **k): return {'gain': k.get('gain',1), 'background': k.get('background',int(np.ceil(17*psf))), 'temporal': k.get('temporal',None)}
|
10
|
+
|
11
|
+
def dpr_update_single(i, psf, opt):
|
12
|
+
g, r = opt['gain'], int(np.ceil(opt['background']))
|
13
|
+
psf /= 1.6651
|
14
|
+
h, w = i.shape
|
15
|
+
x0, y0 = np.linspace(-.5,.5,w), np.linspace(-.5,.5,h)
|
16
|
+
x, y = np.linspace(-.5,.5,round(5*w/psf)), np.linspace(-.5,.5,round(5*h/psf))
|
17
|
+
sx, sy = np.array([[1,0,-1],[2,0,-2],[1,0,-1]]), np.array([[1,2,1],[0,0,0],[-1,-2,-1]])
|
18
|
+
i = i - i.min()
|
19
|
+
localmin = np.zeros_like(i)
|
20
|
+
i_localmin = np.zeros_like(i)
|
21
|
+
for u in range(h):
|
22
|
+
for v in range(w):
|
23
|
+
sub = i[max(0,u-r):min(h,u+r+1), max(0,v-r):min(w,v+r+1)]
|
24
|
+
localmin[u,v] = sub.min()
|
25
|
+
i_localmin[u,v] = i[u,v] - localmin[u,v]
|
26
|
+
m = RectBivariateSpline(y0,x0,i_localmin)(y,x)
|
27
|
+
m[m<0] = 0
|
28
|
+
m = np.pad(m,10)
|
29
|
+
mag = RectBivariateSpline(y0,x0,i)(y,x)
|
30
|
+
mag[mag<0] = 0
|
31
|
+
mag = np.pad(mag,10)
|
32
|
+
hn, wn = mag.shape
|
33
|
+
norm = m / (ndi.gaussian_filter(m,10)+1e-5)
|
34
|
+
gx = ndi.convolve(norm, sy, mode='reflect') / (norm + 1e-5)
|
35
|
+
gy = ndi.convolve(norm, sx, mode='reflect') / (norm + 1e-5)
|
36
|
+
d = 0.5*g+1
|
37
|
+
dx, dy = d*gx, d*gy
|
38
|
+
dx[np.abs(dx)>10] = 0
|
39
|
+
dy[np.abs(dy)>10] = 0
|
40
|
+
out = np.zeros((hn, wn))
|
41
|
+
for nx in range(10, hn-10):
|
42
|
+
for ny in range(10, wn-10):
|
43
|
+
wx, wy = dx[nx,ny], dy[nx,ny]
|
44
|
+
fx, fy = int(wx), int(wy)
|
45
|
+
sx, sy = int(np.sign(wx)), int(np.sign(wy))
|
46
|
+
w1 = (1-abs(wx-fx))*(1-abs(wy-fy))
|
47
|
+
w2 = (1-abs(wx-fx))*abs(wy-fy)
|
48
|
+
w3 = abs(wx-fx)*(1-abs(wy-fy))
|
49
|
+
w4 = abs(wx-fx)*abs(wy-fy)
|
50
|
+
c1 = [fx, fy]
|
51
|
+
c2 = [fx, fy+sy]
|
52
|
+
c3 = [fx+sx, fy]
|
53
|
+
c4 = [fx+sx, fy+sy]
|
54
|
+
val = mag[nx,ny]
|
55
|
+
out[nx+c1[0], ny+c1[1]] += w1*val
|
56
|
+
out[nx+c2[0], ny+c2[1]] += w2*val
|
57
|
+
out[nx+c3[0], ny+c3[1]] += w3*val
|
58
|
+
out[nx+c4[0], ny+c4[1]] += w4*val
|
59
|
+
return out[10:-10,10:-10], mag[10:-10,10:-10], g, r
|
60
|
+
|
61
|
+
def dpr_stack(s, psf, o):
|
62
|
+
f = s.shape[2]
|
63
|
+
shp = dpr_update_single(s[:,:,0],psf,o)[1].shape
|
64
|
+
out = np.zeros((*shp,f)); mag = np.zeros((*shp,f))
|
65
|
+
for i in range(f):
|
66
|
+
sys.stdout.write(f"\rProcessing {i+1}/{f}"); sys.stdout.flush()
|
67
|
+
o1,o2,_,_ = dpr_update_single(s[:,:,i],psf,o)
|
68
|
+
out[:,:,i], mag[:,:,i] = o1, o2
|
69
|
+
t = o.get('temporal','')
|
70
|
+
if t == 'mean': out = np.mean(out,axis=2)
|
71
|
+
elif t == 'var': out = np.var(out,axis=2)
|
72
|
+
return out, mag
|
73
|
+
|
74
|
+
def load_image_stack(p,n,t):
|
75
|
+
path = os.path.join(p,f'{n}.{t}')
|
76
|
+
if t.lower() == 'tif':
|
77
|
+
d = tiff.imread(path)
|
78
|
+
return np.transpose(d,(1,2,0)) if d.ndim==3 else d
|
79
|
+
return np.array(Image.open(path))
|
80
|
+
|
81
|
+
def save_image(im, p, n, t):
|
82
|
+
os.makedirs(p, exist_ok=True)
|
83
|
+
f = os.path.join(p, f'{n}.{t}')
|
84
|
+
if t.lower()=='tif': tiff.imwrite(f, im)
|
85
|
+
else:
|
86
|
+
if im.dtype != np.uint8:
|
87
|
+
im = ((im-im.min())/(im.max()-im.min())*255).astype(np.uint8)
|
88
|
+
Image.fromarray(im).save(f)
|
89
|
+
|
90
|
+
def process_image(p,n,t,psf,o):
|
91
|
+
s = load_image_stack(p,n,t)
|
92
|
+
out, mag = dpr_stack(s, psf, o)
|
93
|
+
save_image(out, os.path.join(p,'DPR_results'), f'{n}_result', t)
|
94
|
+
return s, out, mag
|
95
|
+
|
96
|
+
def display_images(i,m,o):
|
97
|
+
plt.figure(figsize=(12,4))
|
98
|
+
plt.subplot(1,3,1); plt.imshow(i[...,0] if i.ndim==3 else i, cmap='gray'); plt.title('Initial')
|
99
|
+
plt.subplot(1,3,2); plt.imshow(np.mean(m,axis=2) if m.ndim==3 else m, cmap='gray'); plt.title('Magnified')
|
100
|
+
plt.subplot(1,3,3); plt.imshow(o, cmap='gray'); plt.title('DPR')
|
101
|
+
plt.tight_layout(); plt.show()
|
102
|
+
|
103
|
+
def main():
|
104
|
+
p = r'test_data'
|
105
|
+
f = input("File name [test_image.tif]: ") or "test_image.tif"
|
106
|
+
n,t = f.rsplit('.',1)
|
107
|
+
mode = input("Use default params? y/n/e [y]: ").lower() or 'y'
|
108
|
+
if mode == 'e':
|
109
|
+
print("PSF: blur radius\nGain: enhancement\nBackground: subtraction\nTemporal: mean or var")
|
110
|
+
mode = input("Use default now? y/n [y]: ").lower() or 'y'
|
111
|
+
if mode == 'y': psf,g,bg,tmp = 4,2,10,'mean'
|
112
|
+
else:
|
113
|
+
psf = float(input("PSF [4]: ") or 4)
|
114
|
+
g = float(input("Gain [2]: ") or 2)
|
115
|
+
bg = float(input("Background [10]: ") or 10)
|
116
|
+
tmp = input("Temporal [mean]: ") or 'mean'
|
117
|
+
o = dpr_set_parameters(psf, gain=g, background=bg, temporal=tmp)
|
118
|
+
start = time.time()
|
119
|
+
res = process_image(p,n,t,psf,o)
|
120
|
+
if res:
|
121
|
+
img,dpr,mag = res
|
122
|
+
print(f"\nTime: {time.time()-start:.2f}s")
|
123
|
+
display_images(img,mag,dpr)
|
124
|
+
else: print("Failed.")
|
125
|
+
|
126
|
+
def apply_dpr(im, psf=4, gain=2, background=10, temporal='mean'):
|
127
|
+
if im.ndim == 2: im = im[:,:,np.newaxis]
|
128
|
+
o = dpr_set_parameters(psf, gain=gain, background=background, temporal=temporal)
|
129
|
+
return dpr_stack(im, psf, o)
|
130
|
+
|
131
|
+
if __name__ == '__main__': main()
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|