From 6940a5e1a9378b5f8c3d447ee09d686005f5ea8f Mon Sep 17 00:00:00 2001 From: David Northover Date: Wed, 12 Nov 2025 16:25:22 -0500 Subject: [PATCH] Normalization and Zero-Handling of Slice Data - Optional (default enabled) normalization over full data range. - Optional (default enabled) compensation for subzero float values due to conversion issues. - Extended normalization function. - Switched slicing pipeline to writing float32 intermediate then conversion. --- .coverage | Bin 118784 -> 122880 bytes python/ouroboros/helpers/files.py | 26 +-- python/ouroboros/helpers/options.py | 2 + .../pipeline/slice_parallel_pipeline.py | 162 +++++++++--------- src/renderer/src/interfaces/options.tsx | 6 + 5 files changed, 105 insertions(+), 91 deletions(-) diff --git a/.coverage b/.coverage index bd69e2a2e54647516e4aa9fc757f852ec3f912b4..e03130e213620656798b0db395ee203ee7adfa15 100644 GIT binary patch literal 122880 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 literal 118784 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�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
    t+ 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 Si0Q;V1`67;gPtUD?EeBNSTP#_ diff --git a/python/ouroboros/helpers/files.py b/python/ouroboros/helpers/files.py index 2ae0de5..de23456 100644 --- a/python/ouroboros/helpers/files.py +++ b/python/ouroboros/helpers/files.py @@ -122,27 +122,27 @@ def num_digits_for_n_files(n: int) -> int: return len(str(n - 1)) -def np_convert(target_dtype: np.dtype, source: ArrayLike, normalize=True, safe_bool=False): - """ TODO: Fix for Negative Values """ +def np_convert(target_dtype: np.dtype, source: ArrayLike, + preset_min: np.number = None, preset_max: np.number = None, + normalize: bool = True, zero_guard: bool = True, safe_bool: bool = False): if safe_bool and target_dtype == bool: return source.astype(target_dtype).astype(np.uint8) - elif np.issubdtype(target_dtype, np.integer) and normalize: - dtype_range = np.iinfo(target_dtype).max - np.iinfo(target_dtype).min - source_range = np.max(source) - np.min(source) - - # Avoid divide by 0, esp. as numpy segfaults when you do. - if source_range == 0.0: - source_range = 1.0 - return (source * max(int(dtype_range / source_range), 1)).astype(target_dtype) - elif np.issubdtype(target_dtype, np.floating) and normalize: - source_range = np.max(source) - np.min(source) + if normalize: + source_floor = (preset_min if preset_min is not None else np.min(source)) * -1 + source_range = (preset_max if preset_max is not None else np.max(source)) + source_floor # Avoid divide by 0, esp. as numpy segfaults when you do. if source_range == 0.0: source_range = 1.0 - return (source / source_range).astype(target_dtype) + if np.issubdtype(target_dtype, np.integer) and normalize: + dtype_range = np.iinfo(target_dtype).max - np.iinfo(target_dtype).min + return ((source + source_floor) * max(dtype_range / source_range, 1)).astype(target_dtype) + elif np.issubdtype(target_dtype, np.floating) and normalize: + return ((source + source_floor) / source_range).astype(target_dtype) + elif preset_min is not None and preset_min < 0 and zero_guard: + return (source - preset_min).astype(target_dtype) else: return source.astype(target_dtype) diff --git a/python/ouroboros/helpers/options.py b/python/ouroboros/helpers/options.py index 55a466c..fec2330 100644 --- a/python/ouroboros/helpers/options.py +++ b/python/ouroboros/helpers/options.py @@ -41,6 +41,8 @@ class SliceOptions(CommonOptions): False # Whether to connect the start and end of the given annotation points ) annotation_mip_level: int = 0 # MIP level for the annotation layer + normalize_output: bool = True + zeroguard_output: bool = True @field_serializer("bounding_box_params") def serialize_bounding_box_params(self, value: BoundingBoxParams): diff --git a/python/ouroboros/pipeline/slice_parallel_pipeline.py b/python/ouroboros/pipeline/slice_parallel_pipeline.py index b0427ec..be9ebb9 100644 --- a/python/ouroboros/pipeline/slice_parallel_pipeline.py +++ b/python/ouroboros/pipeline/slice_parallel_pipeline.py @@ -1,4 +1,5 @@ from functools import partial +from pathlib import Path import sys import threading import traceback @@ -14,6 +15,7 @@ format_tiff_name, join_path, num_digits_for_n_files, + np_convert ) from .pipeline import PipelineStep from ouroboros.helpers.mem import SharedNPArray @@ -62,6 +64,10 @@ def _process(self, input_data: tuple[any]) -> None | str: if not isinstance(slice_rects, np.ndarray): return "Input data must contain an array of slice rects." + # Make sure slice rects is not empty + if len(slice_rects) == 0: + return "No slice rects were provided." + # Create a folder with the same name as the output file folder_name = join_path( config.output_file_folder, @@ -74,52 +80,41 @@ def _process(self, input_data: tuple[any]) -> None | str: output_file_path = join_path( config.output_file_folder, format_slice_output_file(config.output_file_name) ) + temp_file_path = Path( + config.output_file_folder, format_slice_output_file(config.output_file_name) + ).with_suffix(".temptif") + + # Start setting up metadata + # Volume cache resolution is in voxel size, but .tiff XY resolution is in voxels per unit, so we invert. + resolution = [1.0 / voxel_size for voxel_size in volume_cache.get_resolution_um()[:2] * 0.0001] + resolutionunit = "CENTIMETER" + # However, Z Resolution doesn't have an inbuilt property or strong convention, so going with this. + metadata = { + "spacing": volume_cache.get_resolution_um()[2], + "unit": "um" + } + + # Determine the dimensions of the image + has_color_channels = volume_cache.has_color_channels() + num_color_channels = ( + volume_cache.get_num_channels() if has_color_channels else None + ) - # Create an empty tiff to store the slices - if config.make_single_file: - # Make sure slice rects is not empty - if len(slice_rects) == 0: - return "No slice rects were provided." - - try: - # Volume cache resolution is in voxel size, but .tiff XY resolution is in voxels per unit, so we invert. - resolution = [1.0 / voxel_size for voxel_size in volume_cache.get_resolution_um()[:2] * 0.0001] - resolutionunit = "CENTIMETER" - # However, Z Resolution doesn't have an inbuilt property or strong convention, so going with this. - metadata = { - "spacing": volume_cache.get_resolution_um()[2], - "unit": "um" - } - - # Determine the dimensions of the image - has_color_channels = volume_cache.has_color_channels() - num_color_channels = ( - volume_cache.get_num_channels() if has_color_channels else None - ) - - # Create a single tif file with the same dimensions as the slices - temp_shape = ( - slice_rects.shape[0], - config.slice_width, - config.slice_height, - ) + ((num_color_channels,) if has_color_channels else ()) - temp_data = np.zeros(temp_shape, dtype=np.float16) - - imwrite( - output_file_path, - temp_data, - software="ouroboros", - resolution=resolution[:2], # XY Resolution - resolutionunit=resolutionunit, - photometric=( - "rgb" - if has_color_channels and num_color_channels > 1 - else "minisblack" - ), - metadata=metadata - ) - except BaseException as e: - return f"Error creating single tif file: {e}" + tiff_metadata = { + "software": "ouroboros", + "resolution": resolution[:2] + [resolutionunit], # XY Resolution + "photometric": ("rgb" if has_color_channels and num_color_channels > 1 else "minisblack"), + "metadata": metadata + } + + # Create temporary memmap (single tif file with the same dimensions as the slices) + temp_shape = ( + slice_rects.shape[0], + config.slice_width, + config.slice_height, + ) + ((int(num_color_channels),) if has_color_channels else ()) + + temp_file = memmap(temp_file_path, shape=temp_shape, dtype=np.float32, **tiff_metadata) # Calculate the number of digits needed to store the number of slices num_digits = num_digits_for_n_files(len(slice_rects)) @@ -127,6 +122,11 @@ def _process(self, input_data: tuple[any]) -> None | str: # Processing completion marker. all_work_done = threading.Event() + # Minimum and maximum boundaries. +# bound_shm = SharedNPArray("boundaries", X(2), np.float64, allocate=True) +# with bound_shm[:] as boundaries: + boundaries = np.zeros(2, dtype=np.float32) + # Start the download volumes process and process downloaded volumes as they become available in the queue try: with concurrent.futures.ThreadPoolExecutor( @@ -145,11 +145,8 @@ def _process(self, input_data: tuple[any]) -> None | str: partial_slice_executor = partial( process_worker_save_parallel, config=config, - folder_name=folder_name, slice_rects=slice_rects, - num_threads=self.num_threads, - num_digits=num_digits, - single_output_path=output_file_path if config.make_single_file else None, + temporary_path=temp_file_path, shared=volume_cache.use_shared) partial_dl_executor = partial(dl_worker, @@ -162,7 +159,10 @@ def dl_completed(future): process_futures[-1].add_done_callback(processor_completed) def processor_completed(future): - volume_index, durations = future.result() + volume_index, durations, min_val, max_val = future.result() +# with bound_shm[:] as boundaries: + boundaries[0] = min(boundaries[0], min_val) + boundaries[1] = max(boundaries[1], max_val) if volume_cache.use_shared: volume_cache.remove_volume(volume_index, destroy_shared=True) for key, value in durations.items(): @@ -187,6 +187,27 @@ def processor_completed(future): all_work_done.wait() + with multiprocessing.pool.ThreadPool(self.num_processes) as pool: + # with bound_shm[:] as boundaries: + convert_func = partial(np_convert, + target_dtype=volume_cache.get_volume_dtype(), + normalize=config.normalize_output, + zero_guard=config.zeroguard_output, + preset_min=boundaries[0], + preset_max=boundaries[1]) + if config.make_single_file: + target_file = memmap(output_file_path, shape=temp_shape, dtype=volume_cache.get_volume_dtype(), + **tiff_metadata) + pool.starmap(memmap_normalized, [(temp_file, target_file, convert_func, i) + for i in range(len(temp_file))]) + else: + pool.starmap(write_normalized, + [(temp_file, + partial(imwrite, join_path(folder_name, format_tiff_name(i, num_digits)), **tiff_metadata), # noqa: E501 + convert_func, + i) for i in range(len(temp_file))]) + del temp_file + temp_file_path.unlink() except BaseException as e: traceback.print_tb(e.__traceback__, file=sys.stderr) return f"Error downloading data: {e}" @@ -208,12 +229,9 @@ def dl_worker(volume_cache: VolumeCache, volume: int, parallel_fetch: bool = Fal def process_worker_save_parallel( config: SliceOptions, - folder_name: str, processing_data: tuple[np.ndarray | SharedNPArray, np.ndarray, np.ndarray, int], slice_rects: np.ndarray, - num_threads: int, - num_digits: int, - single_output_path: str = None, + temporary_path: str = None, shared: bool = False ) -> tuple[int, dict[str, list[float]]]: volume, bounding_box, slice_indices, volume_index = processing_data @@ -245,32 +263,20 @@ def process_worker_save_parallel( ) durations["slice_volume"].append(time.perf_counter() - start) - if single_output_path is None: - # Using a ThreadPoolExecutor within the process for saving slices - with concurrent.futures.ThreadPoolExecutor( - max_workers=num_threads - ) as thread_executor: - futures = [] - - for i, slice_i in zip(slice_indices, slices): - start = time.perf_counter() - filename = join_path(folder_name, format_tiff_name(i, num_digits)) - futures.append(thread_executor.submit(save_thread, filename, slice_i)) - durations["save"].append(time.perf_counter() - start) - - for future in concurrent.futures.as_completed(futures): - future.result() - else: - # Save the slices to a previously created tiff file - mmap = memmap(single_output_path) - mmap[slice_indices] = slices - mmap.flush() - del mmap + # Save the slices to a previously created tiff file + mmap = memmap(temporary_path) + mmap[slice_indices] = slices + mmap.flush() + del mmap durations["total_process"].append(time.perf_counter() - start_total) - return volume_index, durations + return volume_index, durations, np.min(slices), np.max(slices) + + +def memmap_normalized(source: np.memmap, target: np.memmap, convert: callable, index: int): + target[index] = convert(source=source[index, :]) -def save_thread(filename: str, data: np.ndarray): - imwrite(filename, data, software="ouroboros") +def write_normalized(source: np.memmap, writer: callable, convert: callable, index: int): + writer(data=convert(source=source[index])) diff --git a/src/renderer/src/interfaces/options.tsx b/src/renderer/src/interfaces/options.tsx index 4d17958..2d44df6 100644 --- a/src/renderer/src/interfaces/options.tsx +++ b/src/renderer/src/interfaces/options.tsx @@ -241,6 +241,12 @@ export class SliceOptionsFile extends CompoundEntry { 'Whether to output one tiff stack file or a folder of files.' ), new Entry('connect_start_and_end', 'Connect Endpoints', false, 'boolean').withHidden(), + new Entry('normalize_output', 'Normalize Output', true, 'boolean').withDescription( + 'Whether to normalize the output data.' + ), + new Entry('zeroguard_output', 'Zero-Guard Output', true, 'boolean').withDescription( + 'Whether to fix sub-zero slice values that may cause overflow artifacts.' + ), new Entry('flush_cache', 'Flush CloudVolume Cache', false, 'boolean').withHidden(), new CompoundEntry('bounding_box_params', 'Bounding Box Parameters', [ new Entry('max_depth', 'Max Depth', 12, 'number').withDescription(