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.
@@ -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
+ [![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
48
+ [![PyPI version](https://img.shields.io/pypi/v/napari-dpr.svg)](https://pypi.org/project/napari-dpr)
49
+ [![Python Version](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://python.org)
50
+ [![napari hub](https://img.shields.io/badge/napari-hub-purple.svg)](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
+ [![License MIT](https://img.shields.io/badge/license-MIT-green.svg)](https://opensource.org/licenses/MIT)
4
+ [![PyPI version](https://img.shields.io/pypi/v/napari-dpr.svg)](https://pypi.org/project/napari-dpr)
5
+ [![Python Version](https://img.shields.io/badge/python-3.9%20%7C%203.10%20%7C%203.11%20%7C%203.12%20%7C%203.13-blue.svg)](https://python.org)
6
+ [![napari hub](https://img.shields.io/badge/napari-hub-purple.svg)](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,4 @@
1
+ [egg_info]
2
+ tag_build =
3
+ tag_date = 0
4
+
@@ -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,9 @@
1
+ """
2
+ napari-dpr plugin package.
3
+ """
4
+
5
+ __version__ = "0.1.0"
6
+
7
+ # Import modules for easier access
8
+ from napari_dpr.dpr_core import *
9
+ from napari_dpr.dpr import *
@@ -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()