PyOPIA 2.4.7__tar.gz → 2.5.1__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.
- {pyopia-2.4.7 → pyopia-2.5.1}/PKG-INFO +1 -1
- pyopia-2.5.1/pyopia/__init__.py +1 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/instrument/holo.py +19 -18
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/instrument/silcam.py +115 -2
- pyopia-2.4.7/pyopia/__init__.py +0 -1
- {pyopia-2.4.7 → pyopia-2.5.1}/LICENSE +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/README.md +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/background.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/classify.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/cli.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/exampledata.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/instrument/__init__.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/instrument/common.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/instrument/uvp.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/io.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/pipeline.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/plotting.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/process.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/simulator/__init__.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/simulator/silcam.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/statistics.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/tests/__init__.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/tests/test_classify.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/tests/test_notebooks.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyopia/tests/test_pipeline.py +0 -0
- {pyopia-2.4.7 → pyopia-2.5.1}/pyproject.toml +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = '2.5.1'
|
|
@@ -1,5 +1,15 @@
|
|
|
1
1
|
'''
|
|
2
|
-
|
|
2
|
+
This is a module containing basic processing for reconstruction of in-line holographic images with :mod:`pyopia.pipeline`.
|
|
3
|
+
|
|
4
|
+
See (and references therein):
|
|
5
|
+
Davies EJ, Buscombe D, Graham GW & Nimmo-Smith WAM (2015)
|
|
6
|
+
'Evaluating Unsupervised Methods to Size and Classify Suspended Particles
|
|
7
|
+
Using Digital In-Line Holography'
|
|
8
|
+
Journal of Atmospheric and Oceanic Technology 32, (6) 1241-1256,
|
|
9
|
+
https://doi.org/10.1175/JTECH-D-14-00157.1
|
|
10
|
+
https://journals.ametsoc.org/view/journals/atot/32/6/jtech-d-14-00157_1.xml
|
|
11
|
+
|
|
12
|
+
2022-11-01 Alex Nimmo-Smith alex.nimmo.smith@plymouth.ac.uk
|
|
3
13
|
'''
|
|
4
14
|
|
|
5
15
|
import os
|
|
@@ -17,20 +27,6 @@ from glob import glob
|
|
|
17
27
|
import logging
|
|
18
28
|
logger = logging.getLogger()
|
|
19
29
|
|
|
20
|
-
'''
|
|
21
|
-
This is a module containing basic processing for reconstruction of in-line holographic images.
|
|
22
|
-
|
|
23
|
-
See (and references therein):
|
|
24
|
-
Davies EJ, Buscombe D, Graham GW & Nimmo-Smith WAM (2015)
|
|
25
|
-
'Evaluating Unsupervised Methods to Size and Classify Suspended Particles
|
|
26
|
-
Using Digital In-Line Holography'
|
|
27
|
-
Journal of Atmospheric and Oceanic Technology 32, (6) 1241-1256,
|
|
28
|
-
https://doi.org/10.1175/JTECH-D-14-00157.1
|
|
29
|
-
https://journals.ametsoc.org/view/journals/atot/32/6/jtech-d-14-00157_1.xml
|
|
30
|
-
|
|
31
|
-
2022-11-01 Alex Nimmo-Smith alex.nimmo.smith@plymouth.ac.uk
|
|
32
|
-
'''
|
|
33
|
-
|
|
34
30
|
|
|
35
31
|
class Initial():
|
|
36
32
|
'''PyOpia pipline-compatible class for one-time setup of holograhic reconstruction
|
|
@@ -472,7 +468,7 @@ class Focus():
|
|
|
472
468
|
|
|
473
469
|
Returns
|
|
474
470
|
-------
|
|
475
|
-
:class:`pyopia.pipeline.Data`
|
|
471
|
+
data : :class:`pyopia.pipeline.Data`
|
|
476
472
|
|
|
477
473
|
containing the following keys:
|
|
478
474
|
|
|
@@ -547,11 +543,12 @@ class MergeStats():
|
|
|
547
543
|
|
|
548
544
|
Parameters
|
|
549
545
|
----------
|
|
546
|
+
None
|
|
550
547
|
|
|
551
548
|
Returns
|
|
552
549
|
-------
|
|
553
|
-
|
|
554
|
-
|
|
550
|
+
data : :class:`pyopia.pipeline.Data`
|
|
551
|
+
Updated pipeline data, where data['stats'] includes the new columns: 'holo_filename', 'z', and 'ifocus'
|
|
555
552
|
'''
|
|
556
553
|
|
|
557
554
|
def __init__(self):
|
|
@@ -573,6 +570,10 @@ class MergeStats():
|
|
|
573
570
|
ifocus.append(stack_ifocus[np.argmin(total_diff)])
|
|
574
571
|
|
|
575
572
|
stats['ifocus'] = np.array(ifocus, dtype=np.int64)
|
|
573
|
+
z = (np.arange(data['settings']['steps']['initial']['minZ'],
|
|
574
|
+
(data['settings']['steps']['initial']['maxZ'] + data['settings']['steps']['initial']['stepZ']),
|
|
575
|
+
data['settings']['steps']['initial']['stepZ']))
|
|
576
|
+
stats['z'] = z[stats['ifocus']-1]
|
|
576
577
|
stats['holo_filename'] = data['filename']
|
|
577
578
|
data['stats'] = stats
|
|
578
579
|
return data
|
|
@@ -51,6 +51,117 @@ def load_mono8(filename):
|
|
|
51
51
|
return img
|
|
52
52
|
|
|
53
53
|
|
|
54
|
+
def load_bayer_rgb8(filename):
|
|
55
|
+
'''load an RG8 .bsilc file from disc and convert it to RGB image
|
|
56
|
+
|
|
57
|
+
Assumes 8-bit Bayer-RG (Red-Green) image in range 0-255
|
|
58
|
+
|
|
59
|
+
Parameters
|
|
60
|
+
----------
|
|
61
|
+
filename : string
|
|
62
|
+
filename to load
|
|
63
|
+
|
|
64
|
+
Returns
|
|
65
|
+
-------
|
|
66
|
+
array
|
|
67
|
+
raw image float between 0-1
|
|
68
|
+
'''
|
|
69
|
+
img_bayer = np.load(filename, allow_pickle=False).astype(np.int16)
|
|
70
|
+
|
|
71
|
+
# Check the image dimension
|
|
72
|
+
image_shape = np.shape(img_bayer)
|
|
73
|
+
if len(image_shape) > 2:
|
|
74
|
+
if image_shape[2] == 1:
|
|
75
|
+
img_bayer = img_bayer[:, :, 0]
|
|
76
|
+
else:
|
|
77
|
+
raise RuntimeError('Invalid image dimension')
|
|
78
|
+
|
|
79
|
+
M, N = img_bayer.shape[:2] # Number of pixels in image height and width
|
|
80
|
+
img_bayer_min, img_bayer_max = np.min(img_bayer), np.max(img_bayer)
|
|
81
|
+
|
|
82
|
+
# img is a reconstructed RGB image
|
|
83
|
+
img = np.zeros((M, N, 3), dtype=np.uint8)
|
|
84
|
+
img[0:M:2, 0:N:2, 0] = img_bayer[0:M:2, 0:N:2] # Red pixels
|
|
85
|
+
img[0:M:2, 1:N:2, 1] = img_bayer[0:M:2, 1:N:2] # Green pixels on the first row
|
|
86
|
+
img[1:M:2, 0:N:2, 1] = img_bayer[1:M:2, 0:N:2] # Green pixels on the second row
|
|
87
|
+
img[1:M:2, 1:N:2, 2] = img_bayer[1:M:2, 1:N:2] # Blue pixels
|
|
88
|
+
|
|
89
|
+
# Boundary pixels interpolation in the first and last rows
|
|
90
|
+
# ***Red pixels
|
|
91
|
+
img[0, 2:N-1:2, 1] = (img_bayer[1, 2:N-1:2] + img_bayer[0, 1:N-2:2] + img_bayer[0, 3:N:2] + 1) // 3 # Interpolated G
|
|
92
|
+
img[0, 2:N-1:2, 2] = (img_bayer[1, 1:N-2:2] + img_bayer[1, 3:N:2] + 1) // 2 # Interpolated B
|
|
93
|
+
# ***Green pixels (odd columns)
|
|
94
|
+
img[0, 1:N-2:2, 0] = (img_bayer[0, 0:N-3:2] + img_bayer[0, 2:N-1:2] + 1) // 2 # Interpolated R
|
|
95
|
+
img[0, 1:N-2:2, 2] = img_bayer[1, 1:N-2:2] # Interpolated B
|
|
96
|
+
# ***Blue pixels
|
|
97
|
+
img[M-1, 1:N-2:2, 1] = (img_bayer[M-2, 1:N-2:2]
|
|
98
|
+
+ img_bayer[M-1, 0:N-3:2] + img_bayer[M-1, 2:N-1:2] + 1) // 3 # Interpolated G
|
|
99
|
+
img[M-1, 1:N-2:2, 0] = (img_bayer[M-2, 0:N-3:2] + img_bayer[M-2, 2:N-1:2] + 1) // 2 # Interpolated R
|
|
100
|
+
# ***Green pixels (even columns)
|
|
101
|
+
img[M-1, 2:N-1:2, 2] = (img_bayer[M-1, 1:N-2:2] + img_bayer[M-1, 3:N:2] + 1) // 2 # Interpolated B
|
|
102
|
+
img[M-1, 2:N-1:2, 0] = img_bayer[M-2, 2:N-1:2] # Interpolated R
|
|
103
|
+
|
|
104
|
+
# Boundary pixels interpolation in the first and last cols
|
|
105
|
+
# ***Red pixels
|
|
106
|
+
img[2:M-1:2, 0, 1] = (img_bayer[3:M:2, 0] + img_bayer[1:M-2:2, 0] + img_bayer[2:M-1:2, 1] + 1) // 3 # Interpolated G
|
|
107
|
+
img[2:M-1:2, 0, 2] = (img_bayer[3:M:2, 1] + img_bayer[1:M-2:2, 1] + 1) // 2 # Interpolated B
|
|
108
|
+
# ***Green pixels (odd columns)
|
|
109
|
+
img[1:M-2:2, 0, 0] = (img_bayer[0:M-3:2, 0] + img_bayer[2:M-1:2, 0] + 1) // 2 # Interpolated R
|
|
110
|
+
img[1:M-2:2, 0, 2] = img_bayer[1:M-2:2, 1] # Interpolated B
|
|
111
|
+
# ***Blue pixels
|
|
112
|
+
img[1:M-2:2, N-1, 1] = (img_bayer[0:M-3:2, N-1]
|
|
113
|
+
+ img_bayer[2:M-1:2, N-1] + img_bayer[1:M-2:2, N-2] + 1) // 3 # Interpolated G
|
|
114
|
+
img[1:M-2:2, N-1, 0] = (img_bayer[0:M-3:2, N-2] + img_bayer[2:M-1:2, N-2] + 1) // 2 # Interpolated R
|
|
115
|
+
# ***Green pixels (even columns)
|
|
116
|
+
img[2:M-1:2, N-1, 0] = img_bayer[2:M-1:2, N-2] # Interpolated R
|
|
117
|
+
img[2:M-1:2, N-1, 2] = (img_bayer[1:M-2:2, N-1]+img_bayer[3:M:2, N-1] + 1)//2 # Interpolated B
|
|
118
|
+
|
|
119
|
+
# Corner pixels interpolation
|
|
120
|
+
# *** top-left
|
|
121
|
+
img[0, 0, 1] = (img_bayer[1, 0] + img_bayer[0, 1] + 1) // 2 # Interpolated G
|
|
122
|
+
img[0, 0, 2] = img_bayer[1, 1] # Interpolated B
|
|
123
|
+
# *** top-right
|
|
124
|
+
img[0, N-1, 0] = img_bayer[0, N-2] # Interpolated R
|
|
125
|
+
img[0, N-1, 2] = img_bayer[1, N-1] # Interpolated B
|
|
126
|
+
# *** bottom-left
|
|
127
|
+
img[M-1, 0, 0] = img_bayer[M-2, 0] # Interpolated R
|
|
128
|
+
img[M-1, 0, 2] = img_bayer[M-1, 1] # Interpolated B
|
|
129
|
+
# *** bottom-right
|
|
130
|
+
img[M-1, N-1, 1] = (img_bayer[M-2, N-1] + img_bayer[M-1, N-2] + 1) // 2 # Interpolated G
|
|
131
|
+
img[M-1, N-1, 0] = img_bayer[M-2, N-2] # Interpolated R
|
|
132
|
+
|
|
133
|
+
# Internal pixels interpolation
|
|
134
|
+
# ***G pixel on odd row, even column
|
|
135
|
+
img[1:M-2:2, 2:N-1:2, 0] = (img_bayer[0:M-3:2, 2:N-1:2] + img_bayer[2:M-1:2, 2:N-1:2] + 1) // 2 # Interpolated R
|
|
136
|
+
img[1:M-2:2, 2:N-1:2, 2] = (img_bayer[1:M-2:2, 1:N-2:2] + img_bayer[1:M-2:2, 3:N:2] + 1) // 2 # Interpolated B
|
|
137
|
+
# ***G pixel on even row, odd column
|
|
138
|
+
img[2:M-1:2, 1:N-2:2, 0] = (img_bayer[2:M-1:2, 0:N-3:2] + img_bayer[2:M-1:2, 2:N-1:2] + 1) // 2 # Interpolated R
|
|
139
|
+
img[2:M-1:2, 1:N-2:2, 2] = (img_bayer[1:M-2:2, 1:N-2:2] + img_bayer[3:M:2, 1:N-2:2] + 1) // 2 # Interpolated B
|
|
140
|
+
# ***R pixel
|
|
141
|
+
img[2:M-1:2, 2:N-1:2, 1] = (img_bayer[1:M-2:2, 2:N-1:2]
|
|
142
|
+
+ img_bayer[3:M:2, 2:N-1:2] + img_bayer[2:M-1:2, 1:N-2:2]
|
|
143
|
+
+ img_bayer[2:M-1:2, 3:N:2] + 2) // 4 # Interpolated G
|
|
144
|
+
img[2:M-1:2, 2:N-1:2, 2] = (img_bayer[1:M-2:2, 1:N-2:2]
|
|
145
|
+
+ img_bayer[3:M:2, 1:N-2:2] + img_bayer[3:M:2, 3:N:2]
|
|
146
|
+
+ img_bayer[1:M-2:2, 3:N:2] + 2) // 4 # Interpolated B
|
|
147
|
+
# ***B pixel
|
|
148
|
+
img[1:M-2:2, 1:N-2:2, 0] = (img_bayer[0:M-3:2, 0:N-3:2]
|
|
149
|
+
+ img_bayer[2:M-1:2, 0:N-3:2] + img_bayer[2:M-1:2, 2:N-1:2]
|
|
150
|
+
+ img_bayer[0:M-3:2, 2:N-1:2] + 2) // 4 # Interpolated R
|
|
151
|
+
img[1:M-2:2, 1:N-2:2, 1] = (img_bayer[0:M-3:2, 1:N-2:2]
|
|
152
|
+
+ img_bayer[2:M-1:2, 1:N-2:2] + img_bayer[1:M-2:2, 0:N-3:2]
|
|
153
|
+
+ img_bayer[1:M-2:2, 2:N-1:2] + 2) // 4 # Interpolated G
|
|
154
|
+
img_min, img_max = np.min(img), np.max(img)
|
|
155
|
+
|
|
156
|
+
if img_min < 0 or img_max > 255 or (img_max - img_bayer_max) != 0 or (img_min - img_bayer_min) != 0:
|
|
157
|
+
raise ValueError(
|
|
158
|
+
"The converted RGB image is not suitable for further analysis. Check the pixel intensity ranges of the input image."
|
|
159
|
+
)
|
|
160
|
+
|
|
161
|
+
img = img.astype(np.float64) / 255
|
|
162
|
+
return img
|
|
163
|
+
|
|
164
|
+
|
|
54
165
|
def load_rgb8(filename):
|
|
55
166
|
'''load an RGB .silc file from disc
|
|
56
167
|
|
|
@@ -102,13 +213,14 @@ class SilCamLoad():
|
|
|
102
213
|
Parameters
|
|
103
214
|
----------
|
|
104
215
|
image_format : str, optional
|
|
105
|
-
Image file format. Can be either 'infer', 'rgb8' or 'mono8', by default 'infer'.
|
|
216
|
+
Image file format. Can be either 'infer', 'rgb8', 'bayer_rg8' or 'mono8', by default 'infer'.
|
|
106
217
|
|
|
107
218
|
Note
|
|
108
219
|
----
|
|
109
220
|
'infer' uses the file extension to determine the image format using the following convention:
|
|
110
221
|
- '.silc' for RGB8
|
|
111
222
|
- '.msilc' for MONO8
|
|
223
|
+
- '.bsilc' for BAYER_RG8
|
|
112
224
|
- '.bmp' for using skimage.io.imread
|
|
113
225
|
|
|
114
226
|
Returns
|
|
@@ -125,9 +237,10 @@ class SilCamLoad():
|
|
|
125
237
|
self.image_format = image_format
|
|
126
238
|
self.extension_load = {'.silc': load_rgb8,
|
|
127
239
|
'.msilc': load_mono8,
|
|
240
|
+
'.bsilc': load_bayer_rgb8,
|
|
128
241
|
'.bmp': skimage.io.imread}
|
|
129
242
|
self.format_load = {'RGB8': load_rgb8,
|
|
130
|
-
'MONO8': load_mono8}
|
|
243
|
+
'MONO8': load_mono8, 'BAYER_RG8': load_bayer_rgb8}
|
|
131
244
|
|
|
132
245
|
def __call__(self, data):
|
|
133
246
|
data['timestamp'] = timestamp_from_filename(data['filename'])
|
pyopia-2.4.7/pyopia/__init__.py
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = '2.4.7'
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|