Source code for aicsimageprocessing.backgroundCrop

# Author: Evan Wiederspan <evanw@alleninstitute.org>
import numpy as np


[docs]def get_edges(img, bg_val=0, axis=(-3, -2, -1)): """ Returns the indices of the edges of the structure in the image Parameters ---------- img CZYX image as a 4d numpy array bg_val value to use for background axis axis to get the edges for. Output length will be equal to axis length. Default is the last three axis Returns ------- tuple of the same length as axis parameter. Contains lists the contain the left and right edges for each axis specified. """ try: ndim = img.ndim except AttributeError: raise ValueError("img must be a numpy array") # turn negative numbers in axis into positive try: axis = tuple(a if a >= 0 else ndim + a for a in axis) ends_list = tuple([0, img.shape[a]] for a in axis) except TypeError: raise ValueError("All values in axis must be integers") except IndexError: raise ValueError( "All axis must be integers in the range of {} to {}".format(-ndim, ndim - 1) ) for a_i, a in enumerate(axis): axis_slice = [slice(None, None)] * ndim axis_length = img.shape[a] - 1 # loop from front to find min for s_i in range(axis_length): axis_slice[a] = s_i # iterate through until we find a slice that contains values other than # bg_val, if not np.all( np.isnan(img[tuple(axis_slice)]) if np.isnan(bg_val) else img[tuple(axis_slice)] == bg_val ): ends_list[a_i][0] = s_i break # loop from back to find max for s_i in range(axis_length, 0, -1): axis_slice[a] = s_i if not np.all( np.isnan(img[tuple(axis_slice)]) if np.isnan(bg_val) else img[tuple(axis_slice)] == bg_val ): ends_list[a_i][1] = s_i + 1 break return ends_list
[docs]def crop(img, bg_val=0, axis=(-3, -2, -1), padding=0, get_slices=False): """ Crops an image to remove the background color bg_val along arbitrary axis Parameters ---------- img numpy array to crop bg_val value to crop out. Default is 0 axis tuple or list of axis indices to crop along. Can be either positive or negative values. Negative values will be from the end of the array as opposed to the start. By default, it crops along the last three axes padding integer. Specifies how much of the background value to leave in the output. Will be applied on all axis that are being cropped get_slices boolean. If True, will return the slice indices that were taken out of the original image along with the cropped image. Default is False Returns ------- either the cropped numpy array, or a tuple containing the cropped array and a tuple of slices taken out of the original data """ # check that padding is a positive integer if not isinstance(padding, int) or padding < 0: raise ValueError("padding must be a positive integer") # get_edges will raise ValueErrors if parameters are bad edges = get_edges(img, bg_val=bg_val, axis=axis) # list of lists representing slice endpoints. Item i refers to the # slice for axis i ends_list = [[0, img.shape[a]] for a in range(img.ndim)] # merge edges into ends_list for a, edge in zip(axis, edges): ends_list[a] = edge # add in padding ends_list = [ [max(0, ends[0] - padding), min(length, ends[1] + padding)] for length, ends in zip(img.shape, ends_list) ] crop_slices = tuple(slice(*axis_slice) for axis_slice in ends_list) if get_slices: return (img[crop_slices].copy(), tuple(ends_list)) else: return img[crop_slices].copy()