napari-dpr 0.1.0__cp313-cp313-win_amd64.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_dpr/__init__.py ADDED
@@ -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 *
napari_dpr/_widget.py ADDED
@@ -0,0 +1,86 @@
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
+ # Add the enhanced image to the viewer
69
+ viewer.add_image(
70
+ dpr_out,
71
+ name=f"{image_layer.name}_DPR_enhanced",
72
+ colormap=image_layer.colormap.name,
73
+ )
74
+
75
+ # Also add the magnified original for comparison
76
+ viewer.add_image(
77
+ magnified.sum(axis=2), # Sum over the time/channel dimension
78
+ name=f"{image_layer.name}_magnified",
79
+ colormap=image_layer.colormap.name,
80
+ )
81
+
82
+ except Exception as e:
83
+ import traceback
84
+ print(f"Error applying DPR: {e}")
85
+ print(traceback.format_exc())
86
+ raise
napari_dpr/dpr.py ADDED
@@ -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