Skip to content

Commit 8a39610

Browse files
committed
Fix single file backprojection output
- TiffWriter cannot be pickled (and arguments were wrong anyway). - Attempting to write single file as it comes in is very slow due to order requirements, so switched (back) to wait to finish and rewrite.
1 parent 923f9a0 commit 8a39610

File tree

3 files changed

+21
-18
lines changed

3 files changed

+21
-18
lines changed

python/ouroboros/helpers/files.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import numpy as np
88
from numpy.typing import ArrayLike
99
from pathlib import Path
10-
from tifffile import imread, TiffWriter, memmap, TiffFile
10+
from tifffile import imread, TiffWriter, TiffFile
1111
import time
1212

1313
from .shapes import DataShape
@@ -139,7 +139,8 @@ def np_convert(dtype: np.dtype, source: ArrayLike, normalize=True):
139139
return source.astype(dtype)
140140

141141

142-
def generate_tiff_write(write_func, compression, micron_resolution, backprojection_offset):
142+
def generate_tiff_write(write_func: callable, compression: str | None, micron_resolution: np.ndarray[float],
143+
backprojection_offset: np.ndarray, **kwargs):
143144
# Volume cache resolution is in voxel size, but .tiff XY resolution is in voxels per unit, so we invert.
144145
resolution = [1.0 / voxel_size for voxel_size in micron_resolution[:2] * 0.0001]
145146
resolutionunit = "CENTIMETER"
@@ -158,7 +159,8 @@ def generate_tiff_write(write_func, compression, micron_resolution, backprojecti
158159
metadata=metadata,
159160
resolution=resolution,
160161
resolutionunit=resolutionunit,
161-
software="ouroboros")
162+
software="ouroboros",
163+
**kwargs)
162164

163165

164166
def write_small_intermediate(file_path: os.PathLike, *series):

python/ouroboros/helpers/memory_usage.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ def calculate_gigabytes_from_dimensions(shape: tuple[int], dtype: np.dtype) -> f
4040
num_elements = np.prod(shape)
4141

4242
# Calculate the total number of bytes
43-
num_bytes = np.multiply(num_elements, dtype_size, dtype=np.uint64)
43+
num_bytes = np.multiply(num_elements, dtype_size, dtype=np.uint64, casting='unsafe')
4444

4545
return num_bytes / GIGABYTE
4646

python/ouroboros/pipeline/backproject_pipeline.py

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -135,13 +135,14 @@ def _process(self, input_data: any) -> tuple[any, None] | tuple[None, any]:
135135

136136
if config.make_single_file:
137137
is_big_tiff = calculate_gigabytes_from_dimensions(np.prod(write_shape), np.uint16) > 4 # Check Dtype
138-
single_tiff = tifffile.TiffWriter(folder_path.with_suffix(".tiff"), abigtiff=is_big_tiff)
138+
else:
139+
is_big_tiff = calculate_gigabytes_from_dimensions(np.prod(write_shape[1:]), np.uint16) > 4 # Check Dtype
139140

140141
bp_offset = pipeline_input.backprojection_offset if config.backproject_min_bounding_box else None
141-
tif_write = generate_tiff_write(single_tiff.write if config.make_single_file else tifffile.imwrite,
142-
config.backprojection_compression,
143-
volume_cache.get_resolution_um(),
144-
bp_offset)
142+
tif_write = partial(generate_tiff_write,
143+
compression=config.backprojection_compression,
144+
micron_resolution=volume_cache.get_resolution_um(),
145+
backprojection_offset=bp_offset)
145146

146147
# Process each bounding box in parallel, writing the results to the backprojected volume
147148
try:
@@ -198,17 +199,12 @@ def note_written(write_future):
198199

199200
if np.any(writeable == 1):
200201
write = np.flatnonzero(writeable == 1)
201-
if config.make_single_file:
202-
write = write[write == (np.indices(write.shape) + len(writeable > 1))]
203-
204-
# Will need to multiprocess
202+
# Single File needs to be in order
205203
for index in write:
206-
path_args = [] if config.make_single_file else [folder_path.joinpath(f"{index:05}.tiff")]
207-
208204
write_futures.append(write_executor.submit(
209205
write_conv_vol,
210-
tif_write, i_path.joinpath(f"i_{index:05}"),
211-
ImgSlice(*write_shape[1:]), np.uint16, *path_args
206+
tif_write(tifffile.imwrite), i_path.joinpath(f"i_{index:05}"),
207+
ImgSlice(*write_shape[1:]), np.uint16, folder_path.joinpath(f"{index:05}.tif")
212208
))
213209
write_futures[-1].add_done_callback(note_written)
214210

@@ -227,7 +223,9 @@ def note_written(write_future):
227223
start = time.perf_counter()
228224

229225
if config.make_single_file:
230-
shutil.rmtree(folder_path)
226+
writer = tif_write(tifffile.TiffWriter(folder_path.with_suffix(".tiff"), bigtiff=is_big_tiff).write)
227+
for fname in get_sorted_tif_files(folder_path):
228+
writer(tifffile.imread(folder_path.joinpath(fname)))
231229

232230
# Rescale the backprojected volume to the output mip level
233231
if pipeline_input.slice_options.output_mip_level != config.output_mip_level:
@@ -265,6 +263,9 @@ def note_written(write_future):
265263
pipeline_input.backprojected_folder_path = folder_path
266264

267265
self.add_timing("export", time.perf_counter() - start)
266+
267+
if config.make_single_file:
268+
shutil.rmtree(folder_path)
268269

269270
return None
270271

0 commit comments

Comments
 (0)