Skip to content

Commit 99dac57

Browse files
authored
New recipe
1 parent 366d3da commit 99dac57

8 files changed

+874
-0
lines changed
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
import os.path
2+
import sys
3+
import numpy as np
4+
from tifffile import imread, imsave
5+
import ctypes
6+
7+
"""
8+
Various arithmetics to be applied to one channel.
9+
10+
Requirements
11+
------------
12+
numpy (comes with Aivia installer)
13+
scikit-image (comes with Aivia installer)
14+
tifffile (installed with scikit-image)
15+
16+
Parameters
17+
----------
18+
Input Image : Aivia channel
19+
Input channel to use for the processing.
20+
21+
Operation : int
22+
Number-coded arithmetics action (0=multiply, 1=divide, 2=add, 3=subtract).
23+
24+
Threshold : int
25+
Grayvalue for the arithmetics.
26+
27+
28+
Returns
29+
-------
30+
Aivia objects
31+
Result of the process.
32+
"""
33+
34+
# [INPUT Name:inputImagePath Type:string DisplayName:'Input Image']
35+
# [INPUT Name:value Type:int DisplayName:'Value' Default:0 Min:0 Max:65535]
36+
# [INPUT Name:actionType Type:int DisplayName:'Operation (0=multiply, 1=divide, 2=add, 3=subtract)' Default:0 Min:0 Max:65535]
37+
# [OUTPUT Name:resultImagePath Type:string DisplayName:'Processed Image']
38+
def run(params):
39+
image_location = params['inputImagePath']
40+
result_location = params['resultImagePath']
41+
operation_type = int(params['actionType'])
42+
value = float(params['value'])
43+
tCount = int(params['TCount'])
44+
zCount = int(params['ZCount'])
45+
46+
if not os.path.exists(image_location):
47+
print(f'Error: {image_location} does not exist')
48+
return
49+
50+
image_data = imread(image_location)
51+
d_type = image_data.dtype
52+
dims = image_data.shape
53+
54+
output_data = np.empty(image_data.shape, dtype=d_type)
55+
axes = ''
56+
57+
# 3D+T
58+
if tCount > 1 and zCount > 1:
59+
print(f"Applying to 3D+T case with dims: {image_data.shape}")
60+
for t in range(0, dims[0]):
61+
output_data[t, :, :, :] = process_data(image_data[t, :, :, :], operation_type, value).astype(d_type)
62+
axes = 'TZYX'
63+
64+
# 2D +/- T and 3D
65+
else:
66+
print(f"Applying to 2D/3D case with dims: {image_data.shape}")
67+
output_data = process_data(image_data, operation_type, value).astype(d_type)
68+
if zCount > 1:
69+
axes = 'ZYX'
70+
else:
71+
axes = 'TYX' if tCount > 1 else 'YX'
72+
73+
imsave(result_location, output_data, metadata={'axes': axes}, ome=True)
74+
75+
76+
def process_data(data, op_type: int, value: int):
77+
out_data = None
78+
if op_type == 0: # MULTIPLY
79+
out_data = np.float32(data) * value
80+
elif op_type == 1: # DIVIDE
81+
if value == 0:
82+
sys.exit('Division by zero is not possible.')
83+
out_data = np.float32(data) / value
84+
elif op_type == 2: # ADD
85+
out_data = np.float32(data) + value
86+
elif op_type == 3: # SUBTRACT
87+
out_data = np.float32(data) - value
88+
elif op_type > 3:
89+
sys.exit('Wrong selection of operation type')
90+
91+
# Clipping data only if 8 or 16 bit
92+
if any(data.dtype == dtp for dtp in [np.uint8, np.uint16]):
93+
if np.max(out_data) > np.iinfo(data.dtype).max or np.min(out_data) < 0:
94+
out_data = out_data.clip(0, np.iinfo(data.dtype).max)
95+
print(f'Clipping data to fit the {data.dtype} range.')
96+
97+
return out_data
98+
99+
100+
def Mbox(title, text):
101+
return ctypes.windll.user32.MessageBoxW(0, text, title, 0)
102+
103+
104+
if __name__ == '__main__':
105+
# Commandline arguments: image_path,
106+
params = {'inputImagePath': r'D:\PythonCode\_tests\3D Object Analysis From Seeds_test_seeds.aivia.tif',
107+
'resultImagePath': r'D:\PythonCode\_tests\test.tif',
108+
'Calibration': 'XYZT: 0.3225 Micrometers, 0.3225 Micrometers, 1 Micrometers, 1 Default',
109+
'ZCount': 8, 'TCount': 1, 'actionType': 2, 'value': 2}
110+
run(params)
111+
112+
# CHANGELOG
113+
# v1_00: - From Threshold_for_3DObjects.py. Compatible with 32 bit images
114+
# v1_10: - Adding ome=True tag with imwrite for Aivia 13.0.0 compatibility
Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
import ctypes
2+
import sys
3+
import os.path
4+
import numpy as np
5+
from skimage.io import imread, imsave
6+
from skimage import segmentation
7+
8+
"""
9+
Detects boundaries of 3D labeled objects and creates measurable objects in Aivia.
10+
Works only when there is no time dimension (yet).
11+
12+
Requirements
13+
------------
14+
numpy (comes with Aivia installer)
15+
scikit-image (comes with Aivia installer)
16+
ctypes
17+
18+
Parameters
19+
----------
20+
Input channel:
21+
Input channel with labeled mask and touching objects.
22+
23+
Returns
24+
-------
25+
Object Set in Aivia
26+
27+
Note: replace output with one of the line below to change output type (objects or mask)
28+
# [OUTPUT Name:resultPath Type:string DisplayName:'Labeled Boundaries Mask']
29+
# [OUTPUT Name:resultPath Type:string DisplayName:’Boundaries from labels’ Objects:3D MinSize:0.5 MaxSize:50000.0]
30+
"""
31+
32+
33+
# [INPUT Name:inputImagePath Type:string DisplayName:'Labeled Mask']
34+
# [OUTPUT Name:resultPath Type:string DisplayName:’Boundaries from labels’ Objects:3D MinSize:0.5 MaxSize:50000.0]
35+
def run(params):
36+
image_location = params['inputImagePath']
37+
result_location = params['resultPath']
38+
tCount = int(params['TCount'])
39+
if not os.path.exists(image_location):
40+
print(f"Error: {image_location} does not exist")
41+
return
42+
43+
image_data = imread(image_location)
44+
dims = image_data.shape
45+
print('-- Input dimensions (expected (Z), Y, X): ', np.asarray(dims), ' --')
46+
47+
# Checking image is not 2D/2D+t or 3D+t
48+
if len(dims) == 2 or (len(dims) == 3 and tCount > 1):
49+
message = 'Error: Cannot be applied to timelapses or 2D images.'
50+
Mbox('Error', message, 0)
51+
sys.exit(message)
52+
53+
output_data = np.empty_like(image_data)
54+
55+
# Detecting boundaries (mode = ‘thick’, ‘inner’, ‘outer’, ‘subpixel’)
56+
boundaries = segmentation.find_boundaries(image_data, mode='inner')
57+
output_data = np.where(boundaries, image_data, 0)
58+
59+
imsave(result_location, output_data)
60+
print('Successfully saved output channel')
61+
62+
63+
def Mbox(title, text, style):
64+
return ctypes.windll.user32.MessageBoxW(0, text, title, style)
65+
66+
67+
if __name__ == '__main__':
68+
params = {'inputImagePath': r'D:\PythonCode\_tests\3D-image.aivia.tif',
69+
'resultPath': r'D:\PythonCode\_tests\test.tif',
70+
'TCount': 1}
71+
72+
run(params)
73+
74+
# CHANGELOG
75+
# v1_00: - From Objects_From_3D_Labeled_Mask_1_00.py
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
import ctypes
2+
import os.path
3+
import numpy as np
4+
from skimage.io import imread, imsave
5+
from skimage.segmentation import expand_labels
6+
7+
"""
8+
Dilate 2D labeled masks.
9+
10+
Requirements
11+
------------
12+
numpy (comes with Aivia installer)
13+
scikit-image (comes with Aivia installer)
14+
ctypes
15+
16+
Parameters
17+
----------
18+
Input channel:
19+
Input channel to be dilated. Prefer a binary mask.
20+
21+
Returns
22+
-------
23+
Channel in Aivia
24+
"""
25+
26+
27+
# [INPUT Name:inputImagePath Type:string DisplayName:'Labeled Mask']
28+
# [INPUT Name:dilation Type:int DisplayName:'Dilate distance (pixels)' Default:1 Min:0 Max:65535]
29+
# [OUTPUT Name:resultPath Type:string DisplayName:'Dilated Labeled Mask']
30+
def run(params):
31+
image_location = params['inputImagePath']
32+
result_location = params['resultPath']
33+
zCount = int(params['ZCount'])
34+
tCount = int(params['TCount'])
35+
dilation = int(params['dilation'])
36+
37+
if not os.path.exists(image_location):
38+
print(f"Error: {image_location} does not exist")
39+
return
40+
41+
if zCount > 1:
42+
Mbox('Error', 'This recipes currently only supports 2D images.', 0)
43+
return
44+
45+
lbl_data = imread(image_location)
46+
dims = lbl_data.shape
47+
print('-- Input dimensions (expected (T,) (Z,) Y, X): ', np.asarray(dims), ' --')
48+
49+
output_data = expand_labels(lbl_data, dilation)
50+
51+
imsave(result_location, output_data)
52+
53+
54+
def Mbox(title, text, style):
55+
return ctypes.windll.user32.MessageBoxW(0, text, title, style)
56+
57+
58+
if __name__ == '__main__':
59+
params = {'inputImagePath': r'D:\PythonCode\_tests\3D-image.aivia.tif',
60+
'resultPath': r'D:\PythonCode\_tests\test.tif',
61+
'ZCount': 51, 'TCount': 1,
62+
'threshold': 1, 'dilation': 3}
63+
64+
run(params)
65+
66+
# CHANGELOG
67+
# v1_00: - Comes from Dilate_3D_v1_00.py
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import ctypes
2+
import sys
3+
import os.path
4+
import numpy as np
5+
from skimage.io import imread, imsave
6+
from skimage import segmentation
7+
8+
"""
9+
Separates labeled objects in a 3D mask and creates measurable objects in Aivia.
10+
For instance, CellPose and StarDist output masks where objects can touch each other.
11+
In Aivia, objects need to be separated to be measurable.
12+
13+
WARNING: the boundary detection leads to a large cut (~3 pixels wide) between objects.
14+
15+
Works only when there is no time dimension (yet).
16+
17+
Requirements
18+
------------
19+
numpy (comes with Aivia installer)
20+
scikit-image (comes with Aivia installer)
21+
ctypes
22+
23+
Parameters
24+
----------
25+
Input channel:
26+
Input channel with labeled mask and touching objects.
27+
28+
Returns
29+
-------
30+
Object Set in Aivia
31+
32+
Note: replace output with one of the line below to change output type (objects or mask)
33+
# [OUTPUT Name:resultPath Type:string DisplayName:'Split Labeled Mask']
34+
# [OUTPUT Name:resultPath Type:string DisplayName:’Objects from labels’ Objects:3D MinSize:0.5 MaxSize:50000.0]
35+
"""
36+
37+
38+
# [INPUT Name:inputImagePath Type:string DisplayName:'Labeled Mask']
39+
# [OUTPUT Name:resultPath Type:string DisplayName:’Objects from labels’ Objects:3D MinSize:0.5 MaxSize:50000.0]
40+
def run(params):
41+
image_location = params['inputImagePath']
42+
result_location = params['resultPath']
43+
tCount = int(params['TCount'])
44+
if not os.path.exists(image_location):
45+
print(f"Error: {image_location} does not exist")
46+
return
47+
48+
image_data = imread(image_location)
49+
dims = image_data.shape
50+
print('-- Input dimensions (expected (Z), Y, X): ', np.asarray(dims), ' --')
51+
52+
# Checking image is not 2D/2D+t or 3D+t
53+
if len(dims) == 2 or (len(dims) == 3 and tCount > 1):
54+
message = 'Error: Cannot be applied to timelapses or 2D images.'
55+
Mbox('Error', message, 0)
56+
sys.exit(message)
57+
58+
output_data = np.empty_like(image_data)
59+
60+
# Detecting boundaries to be subtracted to original image
61+
boundaries = segmentation.find_boundaries(image_data, mode='outer')
62+
output_data = np.where(boundaries, 0, image_data)
63+
64+
imsave(result_location, output_data)
65+
print('Successfully saved output channel')
66+
67+
68+
def Mbox(title, text, style):
69+
return ctypes.windll.user32.MessageBoxW(0, text, title, style)
70+
71+
72+
if __name__ == '__main__':
73+
params = {'inputImagePath': r'D:\PythonCode\_tests\3D-image.aivia.tif',
74+
'resultPath': r'D:\PythonCode\_tests\test.tif',
75+
'TCount': 1}
76+
77+
run(params)
78+
79+
# CHANGELOG
80+
# v1_00: - From Split_3D_Labeled_Mask_1_10.py

0 commit comments

Comments
 (0)