Source code for imagesplit.utils.utilities

# coding=utf-8
"""
Utility files for splitting large images into subimages

Author: Tom Doel
Copyright UCL 2017

"""
from math import ceil
import numpy as np


[docs]def file_linear_byte_offset(image_size, bytes_per_voxel, start_coords): """ Return the file byte offset corresponding to the given coordinates. Files generally assumed to have the first dimension most rapidly changing Assumes you have a stream of bytes representing a multi-dimensional image, """ offset = 0 offset_multiple = bytes_per_voxel for coord, image_length in zip(start_coords, image_size): offset += coord * offset_multiple offset_multiple *= image_length return offset
[docs]def get_number_of_blocks(image_size, max_block_size): """Returns a list containing the number of blocks in each dimension required to split the image into blocks that are subject to a maximum size limit """ return [1 if max_block_size_element <= 0 else int(ceil(float(image_size_element) / float(max_block_size_element))) for image_size_element, max_block_size_element in zip(image_size, max_block_size)]
[docs]def get_block_coordinate_range(block_number, block_size, overlap_size, image_size): """ Returns the minimum and maximum coordinate values in one dimension for an image block, where the dimension length image_size is to be split into the number of blocks specified by block_size with an overlap of overlap_size voxels at each boundary, and the current block_number is specified. There is no overlap at the outer border of the image, and the length of the final block is reduced if necessary so there is no padding """ # Compute the minimum coordinate of the block if block_number == 0: min_coord = 0 start_border = 0 else: min_coord = block_number * block_size - overlap_size start_border = overlap_size # Compute the maximum coordinate of the block end_border = overlap_size max_coord = int((block_number + 1) * block_size - 1 + overlap_size) if max_coord >= image_size: max_coord = image_size - 1 end_border = 0 return [min_coord, max_coord, start_border, end_border]
[docs]def get_suggested_block_size(image_size, number_of_blocks): """Returns a recommended block size (a list of the number of blocks in each dimension) to allow the specified image_size to be split into the specified number of blocks in each dimension, with each block being roughly equal in size """ return [int(ceil(float(image_size_element) / float(number_of_blocks_element))) for image_size_element, number_of_blocks_element in zip(image_size, number_of_blocks)]
[docs]def ranges_for_max_block_size(image_size, max_block_size, overlap_size): """Returns a list of ranges, where each recommended block size (a list of the number of blocks in each dimension) is set such that no block exceeds the specified maximum size, and the specified image_size is split so that each block is roughly equal in size """ number_of_blocks = get_number_of_blocks(image_size, max_block_size) return ranges_for_number_of_blocks(image_size, number_of_blocks, overlap_size)
[docs]def ranges_for_number_of_blocks(image_size, number_of_blocks, overlap_size): """Returns a list of ranges, where each recommended block size (a list of the number of blocks in each dimension) is set to allow the specified image_size to be split into the specified number of blocks in each dimension, with each block being roughly equal in size """ suggested_block_size = get_suggested_block_size(image_size, number_of_blocks) block_ranges = [] for i in range(number_of_blocks[0]): for j in range(number_of_blocks[1]): for k in range(number_of_blocks[2]): block_ranges.append( [get_block_coordinate_range(index, block, overlap, size) for index, block, overlap, size in zip([i, j, k], suggested_block_size, overlap_size, image_size)]) return block_ranges
[docs]def convert_to_array(scalar_or_list, parameter_name, num_dims): """Converts a list or scalar to an array""" if not isinstance(scalar_or_list, list): array = [scalar_or_list] * num_dims elif len(scalar_or_list) == 1: array = scalar_or_list * num_dims elif len(scalar_or_list) == num_dims: array = scalar_or_list else: raise ValueError( 'The ' + parameter_name + 'parameter must be a scalar, or a list ' 'containing one entry for ' 'each image dimension') return array
[docs]def rescale_image(data_type, image_line, rescale_limits): """Rescale image to the limits of this datatype""" dt_min = np.iinfo(data_type).min dt_max = np.iinfo(data_type).max dt_range = dt_max - dt_min im_range = float(rescale_limits.max) - float(rescale_limits.min) scale = float(dt_range)/float(im_range) image_line = np.clip(image_line, a_min=rescale_limits.min, a_max=rescale_limits.max) image_line = dt_min + scale*(image_line.astype(float) - rescale_limits.min) image_line = np.around(image_line).astype(data_type) return image_line
[docs]def compute_bytes_per_voxel(element_type): """Returns number of bytes required to store one voxel for the given metaIO ElementType """ switcher = { 'MET_CHAR': 1, 'MET_UCHAR': 1, 'MET_SHORT': 2, 'MET_USHORT': 2, 'MET_INT': 4, 'MET_UINT': 4, 'MET_LONG': 4, 'MET_ULONG': 4, 'MET_LONG_LONG': 8, 'MET_ULONG_LONG': 8, 'MET_FLOAT': 4, 'MET_DOUBLE': 8, } return switcher.get(element_type, 2)
[docs]def to_rgb(image_line): """Convert greyscale array to RGB""" image_line = image_line.copy() image_line.resize(image_line.shape + (1,)) return np.repeat(image_line.astype(np.uint8), 3, len(image_line.shape) - 1)
[docs]def get_numpy_datatype(element_type, byte_order_msb): """Returns the numpy datatype corresponding to this ElementType""" if byte_order_msb and (byte_order_msb or byte_order_msb == "True"): prefix = '>' else: prefix = '<' switcher = { 'MET_CHAR': 'i1', 'MET_UCHAR': 'u1', 'MET_SHORT': 'i2', 'MET_USHORT': 'u2', 'MET_INT': 'i4', 'MET_UINT': 'u4', 'MET_LONG': 'i4', 'MET_ULONG': 'u4', 'MET_LONG_LONG': 'i8', 'MET_ULONG_LONG': 'u8', 'MET_FLOAT': 'f4', 'MET_DOUBLE': 'f8', } return prefix + switcher.get(element_type, 2)