66from tifffile import imread , imwrite
77from skimage import transform , img_as_uint , img_as_ubyte
88import sys
9- from os .path import dirname as up
10- from os .path import isfile
119
1210
1311"""
1412Scales the input channel up or down (isotropic factor). Option for interpolation is in the code.
15- Works only for 2D/3D (not timelapses) and for single channels.
13+ Works only for 2D/3D rescaling (not timelapses) but can be applied on a per timepoint basis.
14+ Works for single channels.
1615
1716Documentation
1817-------------
3938 Opens Aivia to display the new scaled image.
4039
4140"""
42- interpolation_mode = 1 # 0: Nearest-neighbor, 1: Bi-linear , 2: Bi-quadratic, 3: Bi-cubic, 4: Bi-quartic, 5: Bi-quintic
43-
44-
45- # automatic parameters
4641
42+ interpolation_mode = 1 # 0: Nearest-neighbor, 1: Bi-linear , 2: Bi-quadratic, 3: Bi-cubic, 4: Bi-quartic, 5: Bi-quintic
4743
4844# [INPUT Name:inputImagePath Type:string DisplayName:'Input Channel']
4945# [INPUT Name:scaleDirection Type:int DisplayName:'Down or Upscale (0 or 1)' Default:0 Min:0 Max:1]
5046# [INPUT Name:scaleFactorZ Type:double DisplayName:'Z scale factor' Default:1.0 Min:0.01 Max:20.0]
5147# [INPUT Name:scaleFactorXY Type:double DisplayName:'XY scale factor' Default:1.0 Min:0.01 Max:20.0]
5248# [OUTPUT Name:resultPath Type:string DisplayName:'Duplicate of input']
5349def run (params ):
54- image_org = params ['EntryPoint' ]
50+ image_org = params ['EntryPoint' ]
5551 image_location = params ['inputImagePath' ]
5652 result_location = params ['resultPath' ]
5753 scale_factor_xy = float (params ['scaleFactorXY' ])
@@ -66,6 +62,7 @@ def run(params):
6662 # Getting XY and Z values # Expecting only 'Micrometers' in this code
6763 XY_cal = float (pixel_cal [0 ].split (' ' )[0 ])
6864 Z_cal = float (pixel_cal [2 ].split (' ' )[0 ])
65+ T_cal = float (pixel_cal [3 ].split (' ' )[0 ])
6966
7067 if not os .path .exists (image_location ):
7168 print (f"Error: { image_location } does not exist" )
@@ -77,17 +74,12 @@ def run(params):
7774
7875 image_data = imread (image_location )
7976 dims = image_data .shape
80- print ('-- Input dimensions (expected (Z), Y, X): ' , np .asarray (dims ), ' --' )
81-
82- # Checking image is not 2D+t or 3D+t
83- if len (dims ) > 3 or (len (dims ) == 3 and tCount > 1 ):
84- print ('Error: Cannot handle timelapses yet.' )
85- return
77+ print ('-- Input dimensions (expected (T) (Z), Y, X): ' , np .asarray (dims ), ' --' )
8678
8779 if scale_factor_xy == 0.0 :
88- scale_factor_xy = 1.0 #TODO: manual input for batch
80+ scale_factor_xy = 1.0
8981 if scale_factor_z == 0.0 :
90- scale_factor_z = 1.0 #TODO
82+ scale_factor_z = 1.0
9183
9284 if scale_direction == 0 :
9385 scale_factor_xy = 1 / scale_factor_xy
@@ -102,8 +94,17 @@ def run(params):
10294
10395 # Defining axes for output metadata and scale factor variable
10496 final_scale = None
105- if tCount == 1 and zCount > 1 : # 3D
106- axes = 'ZYX' # Data is 'YXZ'
97+ axes = ''
98+ if tCount > 1 and zCount > 1 : # 3D + T
99+ axes = 'TZYX'
100+ final_scale = (1 , scale_factor_z , scale_factor_xy , scale_factor_xy )
101+
102+ elif tCount > 1 and zCount == 1 : # 2D + T
103+ axes = 'TYX'
104+ final_scale = (1 , scale_factor_xy , scale_factor_xy )
105+
106+ elif tCount == 1 and zCount > 1 : # 3D
107+ axes = 'ZYX' # should be 'YXZ'
107108 final_scale = (scale_factor_z , scale_factor_xy , scale_factor_xy )
108109
109110 elif tCount == 1 and zCount == 1 : # 2D
@@ -120,38 +121,41 @@ def run(params):
120121 else :
121122 out_data = img_as_ubyte (scaled_img )
122123 print ('img_as_ubyte' )
123-
124- # Formatting voxel calibration values
125- formatted_XY_cal = '{0:.4g}' .format (final_XY_cal )
126124
127125 tmp_path = result_location .replace ('.tif' , '-scaled.tif' )
128- meta_info = {'axes' : axes ,
129- 'PhysicalSizeX' : formatted_XY_cal ,
130- 'PhysicalSizeY' : formatted_XY_cal ,
131- 'PhysicalSizeZ' : str (final_Z_cal ),
132- 'PhysicalSizeXUnit' : '\xb5 m' ,
133- 'PhysicalSizeYUnit' : '\xb5 m' ,
134- 'PhysicalSizeZUnit' : '\xb5 m' } # '\xb5m' for microns?
126+ meta_info = {'axes' : axes , 'spacing' : str (final_Z_cal ), 'unit' : 'um' ,
127+ 'TimeIncrement' : T_cal , 'TimeIncrementUnit' : 's' }
128+
129+ # Formatting voxel calibration values
130+ inverted_XY_cal = 1 / final_XY_cal
131+ print (final_XY_cal )
135132
136133 print ('Saving image in temp location:\n ' , tmp_path )
137- imwrite (tmp_path , out_data , ome = True , photometric = 'minisblack' , metadata = meta_info )
134+ imwrite (tmp_path , out_data , imagej = True , photometric = 'minisblack' , metadata = meta_info ,
135+ resolution = (inverted_XY_cal , inverted_XY_cal ))
138136
139137 # Dummy save
140- imwrite (result_location , image_data )
138+ dummy_data = np .zeros (image_data .shape , dtype = image_data .dtype )
139+ imwrite (result_location , dummy_data )
141140
142141 # Run external program
143142 cmdLine = 'start \" \" \" ' + aivia_path + '\" \" ' + tmp_path + '\" '
144- # cmdLine = 'start \"\" \"' + IJ_path + '\" \"' + tmp_path + '\"'
145143
146144 args = shlex .split (cmdLine )
147145 subprocess .run (args , shell = True )
148146
149147
150148if __name__ == '__main__' :
151- params = {'inputImagePath' : 'D:\\ python-tests\\ 3D-image.aivia.tif' ,
152- 'resultPath' : 'D:\\ python-tests\\ scaled.tif' ,
153- 'TCount' : 1 ,
154- 'ZCount' : 51 }
149+ params = {'inputImagePath' : 'D:\\ PythonCode\\ _tests\\ 3D-TL-toalign.aivia.tif' ,
150+ 'resultPath' : 'D:\\ PythonCode\\ _tests\\ Output.tif' ,
151+ 'TCount' : 16 ,
152+ 'ZCount' : 41 ,
153+ 'Calibration' : 'XYZT: 0.4 Micrometers, 0.4 Micrometers, 1.2 Micrometers, 599.9996 Seconds' ,
154+ 'scaleFactorXY' : 2 ,
155+ 'scaleFactorZ' : 1 ,
156+ 'scaleDirection' : 0 ,
157+ 'EntryPoint' : '' ,
158+ 'CallingExecutable' : '' }
155159 run (params )
156160
157161# CHANGELOG
@@ -160,5 +164,5 @@ def run(params):
160164# v1_11: - tkinter not installed by default so removing all code and adding parameters in Aivia UI
161165# v1_13: - Fallback values if factors equal 0 / automated detection of latest Aivia version on PC
162166# v1_14: - Adding pixel/voxel calibration
163- # v1_15 : - Update Aivia path for Aivia community
164- # v1_16 : - Update aivia_path using new API
167+ # v1_20 : - Adding time handling (but not rescale with time dimension)
168+ # v1_30 : - Fusing with parallel version updating aivia_path using new API params value
0 commit comments