def __FilterDataFast(self): data = self.data[:,:,0] mode = _ni_support._extend_mode_to_code("reflect") # lowpass filter to suppress noise output, a = _ni_support._get_output(None, data) _nd_image.correlate1d(data, ofdP.weightsLowpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, ofdP.weightsLowpass, 1, output, mode, 0, 0) # lowpass filter again to find background output, b = _ni_support._get_output(None, data) _nd_image.correlate1d(data, ofdP.weightsHighpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, ofdP.weightsHighpass, 1, output, mode, 0, 0) return a - b
def correlate1d(input, weights, axis=-1, output=None, mode="reflect", cval=0.0, origin=0): """Calculate a one-dimensional correlation along the given axis. The lines of the array along the given axis are correlated with the given weights. Parameters ---------- %(input)s weights : array One-dimensional sequence of numbers. %(axis)s %(output)s %(mode)s %(cval)s %(origin)s """ input = numpy.asarray(input) if numpy.iscomplexobj(input): raise TypeError('Complex type not supported') output, return_value = _ni_support._get_output(output, input) weights = numpy.asarray(weights, dtype=numpy.float64) if weights.ndim != 1 or weights.shape[0] < 1: raise RuntimeError('no filter weights given') if not weights.flags.contiguous: weights = weights.copy() axis = _ni_support._check_axis(axis, input.ndim) if ((len(weights) // 2 + origin < 0) or (len(weights) // 2 + origin > len(weights))): raise ValueError('invalid origin') mode = _ni_support._extend_mode_to_code(mode) _nd_image.correlate1d(input, weights, axis, output, mode, cval, origin) return return_value
def __FilterData2D(self, data): mode = _ni_support._extend_mode_to_code("reflect") #lowpass filter to suppress noise #a = ndimage.gaussian_filter(data.astype('f4'), self.filterRadiusLowpass) #print data.shape data = data - data.mean() output, a = _ni_support._get_output(None, data) if self.PRIaxis == 'x': _nd_image.correlate1d(data, weightsLowpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, weightsHighpass, 1, output, mode, 0, 0) else: _nd_image.correlate1d(data, weightsHighpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, weightsLowpass, 1, output, mode, 0, 0) #print numpy.absolute(a - a_).mean() #lowpass filter again to find background #b = ndimage.gaussian_filter(a, self.filterRadiusHighpass) #output, b = _ni_support._get_output(None, data) #_nd_image.correlate1d(data, weightsHighpass, 0, output, mode, 0,0) #_nd_image.correlate1d(output, weightsHighpass, 1, output, mode, 0,0) return a #- b
def __FilterData2D(self,data): mode = _ni_support._extend_mode_to_code("reflect") #lowpass filter to suppress noise #a = ndimage.gaussian_filter(data.astype('f4'), self.filterRadiusLowpass) #print data.shape data = data - data.mean() output, a = _ni_support._get_output(None, data) if self.PRIaxis == 'x': _nd_image.correlate1d(data, weightsLowpass, 0, output, mode, 0,0) _nd_image.correlate1d(output, weightsHighpass, 1, output, mode, 0,0) else: _nd_image.correlate1d(data, weightsHighpass, 0, output, mode, 0,0) _nd_image.correlate1d(output, weightsLowpass, 1, output, mode, 0,0) #print numpy.absolute(a - a_).mean() #lowpass filter again to find background #b = ndimage.gaussian_filter(a, self.filterRadiusHighpass) #output, b = _ni_support._get_output(None, data) #_nd_image.correlate1d(data, weightsHighpass, 0, output, mode, 0,0) #_nd_image.correlate1d(output, weightsHighpass, 1, output, mode, 0,0) return a #- b
def square_gaussian_filter(input, sigma, output=None, mode="reflect", cval=0.0): """Multi-dimensional Squared Gaussian filter. The standard-deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes. Note: The multi-dimensional filter is implemented as a sequence of one-dimensional convolution filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a limited precision, the results may be imprecise because intermediate results may be stored with insufficient precision. """ input = np.asarray(input) output, return_value = _ni_support._get_output(output, input) sigmas = _ni_support._normalize_sequence(sigma, input.ndim) axes = range(input.ndim) axes = [(axes[ii], sigmas[ii]) for ii in range(len(axes)) if sigmas[ii] > 1e-15] if len(axes) > 0: for axis, sigma in axes: square_gaussian_filter1d(input, sigma, axis, output, mode, cval) input = output else: output[...] = input[...] return return_value
def square_gaussian_filter(input, sigma, output = None, mode = "reflect", cval = 0.0): """Multi-dimensional Squared Gaussian filter. The standard-deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes. Note: The multi-dimensional filter is implemented as a sequence of one-dimensional convolution filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a limited precision, the results may be imprecise because intermediate results may be stored with insufficient precision. """ input = np.asarray(input) output, return_value =_ni_support._get_output(output, input) sigmas =_ni_support._normalize_sequence(sigma, input.ndim) axes = range(input.ndim) axes = [(axes[ii], sigmas[ii]) for ii in range(len(axes)) if sigmas[ii] > 1e-15] if len(axes) > 0: for axis, sigma in axes: square_gaussian_filter1d(input, sigma, axis, output, mode, cval) input = output else: output[...] = input[...] return return_value
def _correlate_or_convolve(input, weights, output, mode, cval, origin, convolution): input = np.asarray(input) if np.iscomplexobj(input): raise TypeError('Complex type not supported') origins = _ni_support._normalize_sequence(origin, input.ndim) weights = np.asarray(weights, dtype=np.float64) wshape = [ii for ii in weights.shape if ii > 0] if len(wshape) != input.ndim: raise RuntimeError('filter weights array has incorrect shape.') if convolution: weights = weights[tuple([slice(None, None, -1)] * weights.ndim)] for ii in range(len(origins)): origins[ii] = -origins[ii] if not weights.shape[ii] & 1: origins[ii] -= 1 for origin, lenw in zip(origins, wshape): if _invalid_origin(origin, lenw): raise ValueError('Invalid origin; origin must satisfy ' '-(weights.shape[k] // 2) <= origin[k] <= ' '(weights.shape[k]-1) // 2') if not weights.flags.contiguous: weights = weights.copy() output = _ni_support._get_output(output, input) mode = _ni_support._extend_mode_to_code(mode) _nd_image.correlate(input, weights, output, mode, cval, origins) return output
def __FilterDataFast(self): data = self.data[:, :, 0] mode = _ni_support._extend_mode_to_code("reflect") # lowpass filter to suppress noise output, a = _ni_support._get_output(None, data) _nd_image.correlate1d(data, ofdP.weightsLowpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, ofdP.weightsLowpass, 1, output, mode, 0, 0) # lowpass filter again to find background output, b = _ni_support._get_output(None, data) _nd_image.correlate1d(data, ofdP.weightsHighpass, 0, output, mode, 0, 0) _nd_image.correlate1d(output, ofdP.weightsHighpass, 1, output, mode, 0, 0) return a - b
def gaussian_filter(input, sigma, order=0, output=None, mode="reflect", cval=0.0, truncate=4.0): """Multidimensional Gaussian filter. Parameters ---------- %(input)s sigma : scalar or sequence of scalars Standard deviation for Gaussian kernel. The standard deviations of the Gaussian filter are given for each axis as a sequence, or as a single number, in which case it is equal for all axes. order : {0, 1, 2, 3} or sequence from same set, optional The order of the filter along each axis is given as a sequence of integers, or as a single number. An order of 0 corresponds to convolution with a Gaussian kernel. An order of 1, 2, or 3 corresponds to convolution with the first, second or third derivatives of a Gaussian. Higher order derivatives are not implemented %(output)s %(mode)s %(cval)s truncate : float Truncate the filter at this many standard deviations. Default is 4.0. Returns ------- gaussian_filter : ndarray Returned array of same shape as `input`. Notes ----- The multidimensional filter is implemented as a sequence of one-dimensional convolution filters. The intermediate arrays are stored in the same data type as the output. Therefore, for output types with a limited precision, the results may be imprecise because intermediate results may be stored with insufficient precision. """ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) orders = _ni_support._normalize_sequence(order, input.ndim) if not set(orders).issubset(set(range(4))): raise ValueError('Order outside 0..4 not implemented') sigmas = _ni_support._normalize_sequence(sigma, input.ndim) axes = list(range(input.ndim)) axes = [(axes[ii], sigmas[ii], orders[ii]) for ii in range(len(axes)) if sigmas[ii] > 1e-15] if len(axes) > 0: for axis, sigma, order in axes: gaussian_filter1d(input, sigma, axis, order, output, mode, cval, truncate) input = output else: output[...] = input[...] return return_value
def _extract_local_histogram(image, mask=slice(None), bins=19, rang="image", cutoffp=(0.0, 100.0), size=None, footprint=None, output=None, mode="ignore", origin=0): """ Internal, single-image version of @see local_histogram Note: Values outside of the histograms range are not considered. Note: Mode constant is not available, instead a mode "ignore" is provided. Note: Default dtype of returned values is float. """ if "constant" == mode: raise RuntimeError('boundary mode not supported') elif "ignore" == mode: mode = "constant" if 'image' == rang: rang = tuple(numpy.percentile(image[mask], cutoffp)) elif not 2 == len(rang): raise RuntimeError( 'the rang must contain exactly two elements or the string "image"') _, bin_edges = numpy.histogram([], bins=bins, range=rang) output, _ = _get_output(numpy.float if None == output else output, image, shape=[bins] + list(image.shape)) # threshold the image into the histogram bins represented by the output images first dimension, treat last bin separately, since upper border is inclusive for i in range(bins - 1): output[i] = (image >= bin_edges[i]) & (image < bin_edges[i + 1]) output[-1] = (image >= bin_edges[-2]) & (image <= bin_edges[-1]) # apply the sum filter to each dimension, then normalize by dividing through the sum of elements in the bins of each histogram for i in range(bins): output[i] = sum_filter(output[i], size=size, footprint=footprint, output=None, mode=mode, cval=0.0, origin=origin) divident = numpy.sum(output, 0) divident[0 == divident] = 1 output /= divident # Notes on modes: # mode=constant with a cval outside histogram range for the histogram equals a mode=constant with a cval = 0 for the sum_filter # mode=constant with a cval inside histogram range for the histogram has no equal for the sum_filter (and does not make much sense) # mode=X for the histogram equals mode=X for the sum_filter # treat as multi-spectral image which intensities to extracted return _extract_feature(_extract_intensities, [h for h in output], mask)
def average_filter(input, size=None, footprint=None, output=None, mode="reflect", cval=0.0, origin=0): r""" Calculates a multi-dimensional average filter. Parameters ---------- input : array-like input array to filter size : scalar or tuple, optional See footprint, below footprint : array, optional Either `size` or `footprint` must be defined. `size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``size=(n,m)`` is equivalent to ``footprint=np.ones((n,m))``. We adjust `size` to the number of dimensions of the input array, so that, if the input array is shape (10,10,10), and `size` is 2, then the actual size used is (2,2,2). output : array, optional The ``output`` parameter passes an array in which to store the filter output. mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional The ``mode`` parameter determines how the array borders are handled, where ``cval`` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if ``mode`` is 'constant'. Default is 0.0 origin : scalar, optional The ``origin`` parameter controls the placement of the filter. Default 0 Returns ------- average_filter : ndarray Returned array of same shape as `input`. Notes ----- Convenience implementation employing convolve. See Also -------- scipy.ndimage.filters.convolve : Convolve an image with a kernel. """ footprint = __make_footprint(input, size, footprint) filter_size = footprint.sum() output = _get_output(output, input) sum_filter(input, footprint=footprint, output=output, mode=mode, cval=cval, origin=origin) output /= filter_size return output
def average_filter(input, size=None, footprint=None, output=None, mode="reflect", cval=0.0, origin=0): """ Calculates a multi-dimensional average filter. Parameters ---------- input : array-like input array to filter size : scalar or tuple, optional See footprint, below footprint : array, optional Either `size` or `footprint` must be defined. `size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``size=(n,m)`` is equivalent to ``footprint=np.ones((n,m))``. We adjust `size` to the number of dimensions of the input array, so that, if the input array is shape (10,10,10), and `size` is 2, then the actual size used is (2,2,2). output : array, optional The ``output`` parameter passes an array in which to store the filter output. mode : {'reflect','constant','nearest','mirror', 'wrap'}, optional The ``mode`` parameter determines how the array borders are handled, where ``cval`` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if ``mode`` is 'constant'. Default is 0.0 origin : scalar, optional The ``origin`` parameter controls the placement of the filter. Default 0 Returns ------- average_filter : ndarray Returned array of same shape as `input`. Notes ----- Convenience implementation employing convolve. See Also -------- convolve : Convolve an image with a kernel. """ footprint = __make_footprint(input, size, footprint) filter_size = footprint.sum() output, return_value = _get_output(output, input) sum_filter(input, footprint=footprint, output=output, mode=mode, cval=cval, origin=origin) output /= filter_size return return_value
def separable_convolution(input, weights, output=None, mode="reflect", cval=0.0, origin=0): r""" Calculate a n-dimensional convolution of a separable kernel to a n-dimensional input. Achieved by calling convolution1d along the first axis, obtaining an intermediate image, on which the next convolution1d along the second axis is called and so on. Parameters ---------- input : array_like Array of which to estimate the noise. weights : ndarray One-dimensional sequence of numbers. output : array, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 origin : scalar, optional The `origin` parameter controls the placement of the filter. Default 0.0. Returns ------- output : ndarray Input image convolved with the supplied kernel. """ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) axes = list(range(input.ndim)) if len(axes) > 0: convolve1d(input, weights, axes[0], output, mode, cval, origin) for ii in range(1, len(axes)): convolve1d(output, weights, axes[ii], output, mode, cval, origin) else: output[...] = input[...] return return_value
def Afunc(self, f): '''Forward transform - convolve with the PSF''' fs = reshape(f, (self.height, self.width, self.depth)) #d = ndimage.gaussian_filter(fs, self.sigma) mode = _ni_support._extend_mode_to_code("reflect") #lowpass filter to suppress noise #a = ndimage.gaussian_filter(data.astype('f4'), self.filterRadiusLowpass) #print data.shape output, a = _ni_support._get_output(None, fs) _nd_image.correlate1d(fs, self.kernel, 0, output, mode, 0,0) _nd_image.correlate1d(output, self.kernel, 1, output, mode, 0,0) #ndimage.uniform_filter(output, self.oversamp, output=output) #d = real(d); return ravel(output)#[::oversamp,::oversamp,:])
def Afunc(self, f): """Forward transform - convolve with the PSF""" fs = np.reshape(f, (self.height, self.width, self.depth)) #d = ndimage.gaussian_filter(fs, self.sigma) mode = _ni_support._extend_mode_to_code("reflect") #lowpass filter to suppress noise #a = ndimage.gaussian_filter(data.astype('f4'), self.filterRadiusLowpass) #print data.shape output, a = _ni_support._get_output(None, fs) _nd_image.correlate1d(fs, self.kernel, 0, output, mode, 0, 0) _nd_image.correlate1d(output, self.kernel, 1, output, mode, 0, 0) #ndimage.uniform_filter(output, self.oversamp, output=output) #d = real(d); return np.ravel(output) #[::oversamp,::oversamp,:])
def sinc_filter(input, sigma, order=0, output=None, mode="reflect", cval=0.0, truncate=6.0): input = np.asarray(input) output = _ni_support._get_output(output, input) orders = _ni_support._normalize_sequence(order, input.ndim) sigmas = _ni_support._normalize_sequence(sigma, input.ndim) modes = _ni_support._normalize_sequence(mode, input.ndim) axes = list(range(input.ndim)) axes = [(axes[ii], sigmas[ii], orders[ii], modes[ii]) for ii in range(len(axes)) if sigmas[ii] > 1e-15] if len(axes) > 0: for axis, sigma, order, mode in axes: sinc_filter1d(input, sigma, axis, order, output, mode, cval, truncate) input = output else: output[...] = input[...] return output
def separable_convolution(input, weights, output=None, mode="reflect", cval=0.0, origin=0): r""" Calculate a n-dimensional convolution of a separable kernel to a n-dimensional input. Achieved by calling convolution1d along the first axis, obtaining an intermediate image, on which the next convolution1d along the second axis is called and so on. Parameters ---------- input : array_like Array of which to estimate the noise. weights : ndarray One-dimensional sequence of numbers. output : array, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 origin : scalar, optional The `origin` parameter controls the placement of the filter. Default 0.0. Returns ------- output : ndarray Input image convolved with the supplied kernel. """ input = numpy.asarray(input) output, return_value = _ni_support._get_output(output, input) axes = list(range(input.ndim)) if len(axes) > 0: convolve1d(input, weights, axes[0], output, mode, cval, origin) for ii in range(1, len(axes)): convolve1d(output, weights, axes[ii], output, mode, cval, origin) else: output[...] = input[...] return return_value
def _extract_local_histogram(image, mask=slice(None), bins=19, rang="image", cutoffp=(0.0, 100.0), size=None, footprint=None, output=None, mode="ignore", origin=0): """ Internal, single-image version of @see local_histogram Note: Values outside of the histograms range are not considered. Note: Mode constant is not available, instead a mode "ignore" is provided. Note: Default dtype of returned values is float. """ if "constant" == mode: raise RuntimeError('boundary mode not supported') elif "ignore" == mode: mode = "constant" if 'image' == rang: rang = tuple(numpy.percentile(image[mask], cutoffp)) elif not 2 == len(rang): raise RuntimeError('the rang must contain exactly two elements or the string "image"') _, bin_edges = numpy.histogram([], bins=bins, range=rang) output, _ = _get_output(numpy.float if None == output else output, image, shape = [bins] + list(image.shape)) # threshold the image into the histogram bins represented by the output images first dimension, treat last bin separately, since upper border is inclusive for i in range(bins - 1): output[i] = (image >= bin_edges[i]) & (image < bin_edges[i + 1]) output[-1] = (image >= bin_edges[-2]) & (image <= bin_edges[-1]) # apply the sum filter to each dimension, then normalize by dividing through the sum of elements in the bins of each histogram for i in range(bins): output[i] = sum_filter(output[i], size=size, footprint=footprint, output=None, mode=mode, cval=0.0, origin=origin) divident = numpy.sum(output, 0) divident[0 == divident] = 1 output /= divident # Notes on modes: # mode=constant with a cval outside histogram range for the histogram equals a mode=constant with a cval = 0 for the sum_filter # mode=constant with a cval inside histogram range for the histogram has no equal for the sum_filter (and does not make much sense) # mode=X for the histogram equals mode=X for the sum_filter # treat as multi-spectral image which intensities to extracted return _extract_feature(_extract_intensities, [h for h in output], mask)
def map_coordinates_parallel(input, coordinates, output=None, order=3, mode='constant', cval=0.0, prefilter=True, chunklen=None, threads=None): """ Parallalized version of `scipy.ndimage.map_coordinates`. `scipy.ndimage.map_coordinates` is slow for large datasets. Speed improvement can be achieved by * Splitting the data into chunks * Performing the transformation of chunks in parallel New parameters: chunklen: Size of the chunks in pixels per axis. Default: None Special values: None: Automatic (Chooses a default based on number of dimensions) 0: Do not split data into chunks. (implicitly sets threads==1) threads: Number of threads. Default: None None: Automatic (One thread per available processing unit) """ # this part is taken without change from scipy's serial implementation if order < 0 or order > 5: raise RuntimeError('spline order not supported') input = np.asarray(input) if np.iscomplexobj(input): raise TypeError('Complex type not supported') coordinates = np.asarray(coordinates) if np.iscomplexobj(coordinates): raise TypeError('Complex type not supported') output_shape = coordinates.shape[1:] if input.ndim < 1 or len(output_shape) < 1: raise RuntimeError('input and output rank must be > 0') if coordinates.shape[0] != input.ndim: raise RuntimeError('invalid shape for coordinate array') mode = _ni_support._extend_mode_to_code(mode) if prefilter and order > 1: filtered = spline_filter(input, order, output=np.float64) else: filtered = input # return value of `_ni_support._get_output` changed between scipy versions, code here is # adapted to work with both output = _ni_support._get_output(output, input, shape=output_shape) retval = output if isinstance(output, tuple): output, retval = output # below here there is the new code for splitting into chunks and parallel execution if chunklen is None: # set defaults chunklen = 128 if output.ndim < 3: chunklen = 1024 def chunk_arguments(filtered, coordinates, output): chunks = [] for axis in range(output.ndim): chunkstarts = np.arange(0, output.shape[axis], chunklen) chunkends = chunkstarts + chunklen chunkends[-1] = output.shape[axis] chunks.append([ slice(start, stop) for start, stop in zip(chunkstarts, chunkends) ]) for chunk in itertools.product(*chunks): sub_coordinates = coordinates[(slice(None), ) + chunk].copy() filtered_region = [] for in_axis in range(filtered.ndim): c = sub_coordinates[in_axis, ...] cmin = max(0, int(np.floor(np.min(c))) - 5) cmax = min(filtered.shape[in_axis], int(np.ceil(np.max(c))) + 5) sub_coordinates[in_axis, ...] -= cmin filtered_region.append(slice(cmin, cmax)) sub_filtered = filtered[tuple(filtered_region)] sub_output = output[chunk] yield (sub_filtered, sub_coordinates, sub_output) def map_coordinates_chunk(arg): sub_filtered, sub_coordinates, sub_output = arg _nd_image.geometric_transform(sub_filtered, None, sub_coordinates, None, None, sub_output, order, mode, cval, None, None) if chunklen > 0: list_of_chunk_args = list( chunk_arguments(filtered, coordinates, output)) else: list_of_chunk_args = [(filtered, coordinates, output)] if len(list_of_chunk_args) == 1: threads = 1 if threads != 1: threadpool = ThreadPoolExecutor(threads) my_map = threadpool.map else: my_map = map # execution happens here list(my_map(map_coordinates_chunk, list_of_chunk_args)) if threads != 1: if have_concurrent_futures: threadpool.shutdown() else: threadpool.close() threadpool.join() return retval
def immerkaer_local(input, size, output=None, mode="reflect", cval=0.0): r""" Estimate the local noise. The input image is assumed to have additive zero mean Gaussian noise. The Immerkaer noise estimation is applied to the image locally over a N-dimensional cube of side-length size. The size of the region should be sufficiently high for a stable noise estimation. Parameters ---------- input : array_like Array of which to estimate the noise. size : integer The local region's side length. output : ndarray, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 Returns ------- sigmas : array_like Map of the estimated standard deviation of the images Gaussian noise per voxel. Notes ----- Does not take the voxel spacing into account. Works good with medium to strong noise. Tends to underestimate for low noise levels. See also -------- immerkaer """ output = _ni_support._get_output(output, input) footprint = numpy.asarray([1] * size) # build nd-kernel to acquire square root of sum of squared elements kernel = [1, -2, 1] for _ in range(input.ndim - 1): kernel = numpy.tensordot(kernel, [1, -2, 1], 0) divider = numpy.square(numpy.abs(kernel)).sum() # 36 for 1d, 216 for 3D, etc. # compute laplace of input laplace = separable_convolution(input, [1, -2, 1], numpy.double, mode, cval) # compute factor factor = numpy.sqrt(numpy.pi / 2.) * 1. / ( numpy.sqrt(divider) * numpy.power(footprint.size, laplace.ndim) ) # locally sum laplacian values separable_convolution(numpy.abs(laplace), footprint, output, mode, cval) output *= factor return output
def zoom(input, zoom, output=None, order=3, mode='constant', cval=0.0, prefilter=True): """ Zoom an array. The array is zoomed using spline interpolation of the requested order. Parameters ---------- input : ndarray The input array. zoom : float or sequence, optional The zoom factor along the axes. If a float, `zoom` is the same for each axis. If a sequence, `zoom` should contain one value for each axis. output : ndarray or dtype, optional The array in which to place the output, or the dtype of the returned array. order : int, optional The order of the spline interpolation, default is 3. The order has to be in the range 0-5. mode : str, optional Points outside the boundaries of the input are filled according to the given mode ('constant', 'nearest', 'reflect' or 'wrap'). Default is 'constant'. cval : scalar, optional Value used for points outside the boundaries of the input if ``mode='constant'``. Default is 0.0 prefilter : bool, optional The parameter prefilter determines if the input is pre-filtered with `spline_filter` before interpolation (necessary for spline interpolation of order > 1). If False, it is assumed that the input is already filtered. Default is True. Returns ------- return_value : ndarray or None The zoomed input. If `output` is given as a parameter, None is returned. """ if order < 0 or order > 5: raise RuntimeError('spline order not supported') input = numpy.asarray(input) if numpy.iscomplexobj(input): raise TypeError('Complex type not supported') if input.ndim < 1: raise RuntimeError('input and output rank must be > 0') mode = _extend_mode_to_code(mode) if prefilter and order > 1: filtered = spline_filter(input, order, output = numpy.float64) else: filtered = input zoom = _ni_support._normalize_sequence(zoom, input.ndim) output_shape = tuple([int(ii * jj) for ii, jj in zip(input.shape, zoom)]) zoom_div = numpy.array(output_shape, float) zoom = (numpy.array(input.shape)) / zoom_div # Zooming to non-finite values in unpredictable, so just choose # zoom factor 1 instead zoom[~numpy.isfinite(zoom)] = 1 output, return_value = _ni_support._get_output(output, input, shape=output_shape) zoom = numpy.asarray(zoom, dtype = numpy.float64) zoom = numpy.ascontiguousarray(zoom) _nd_image.zoom_shift(filtered, zoom, None, output, order, mode, cval) return return_value
def map_coordinates_parallel(input, coordinates, output=None, order=3, mode='constant', cval=0.0, prefilter=True, chunklen=None, threads=None): """ Parallalized version of `scipy.ndimage.map_coordinates`. `scipy.ndimage.map_coordinates` is slow for large datasets. Speed improvement can be achieved by * Splitting the data into chunks * Performing the transformation of chunks in parallel New parameters: chunklen: Size of the chunks in pixels per axis. Default: None Special values: None: Automatic (Chooses a default based on number of dimensions) 0: Do not split data into chunks. (implicitly sets threads==1) threads: Number of threads. Default: None None: Automatic (One thread per available processing unit) """ # this part is taken without change from scipy's serial implementation if order < 0 or order > 5: raise RuntimeError('spline order not supported') input = np.asarray(input) if np.iscomplexobj(input): raise TypeError('Complex type not supported') coordinates = np.asarray(coordinates) if np.iscomplexobj(coordinates): raise TypeError('Complex type not supported') output_shape = coordinates.shape[1:] if input.ndim < 1 or len(output_shape) < 1: raise RuntimeError('input and output rank must be > 0') if coordinates.shape[0] != input.ndim: raise RuntimeError('invalid shape for coordinate array') mode = _ni_support._extend_mode_to_code(mode) if prefilter and order > 1: filtered = spline_filter(input, order, output=np.float64) else: filtered = input # return value of `_ni_support._get_output` changed between scipy versions, code here is # adapted to work with both output = _ni_support._get_output(output, input, shape=output_shape) retval = output if isinstance(output, tuple): output, retval = output # below here there is the new code for splitting into chunks and parallel execution if chunklen is None: # set defaults chunklen = 128 if output.ndim < 3: chunklen = 1024 def chunk_arguments(filtered, coordinates, output): chunks = [] for axis in range(output.ndim): chunkstarts = np.arange(0, output.shape[axis], chunklen) chunkends = chunkstarts + chunklen chunkends[-1] = output.shape[axis] chunks.append([slice(start, stop) for start, stop in zip(chunkstarts, chunkends)]) for chunk in itertools.product(*chunks): sub_coordinates = coordinates[(slice(None),) + chunk].copy() filtered_region = [] for in_axis in range(filtered.ndim): c = sub_coordinates[in_axis, ...] cmin = max(0, int(np.floor(np.min(c)))-5) cmax = min(filtered.shape[in_axis], int(np.ceil(np.max(c)))+5) sub_coordinates[in_axis, ...] -= cmin filtered_region.append(slice(cmin, cmax)) sub_filtered = filtered[tuple(filtered_region)] sub_output = output[chunk] yield (sub_filtered, sub_coordinates, sub_output) def map_coordinates_chunk(arg): sub_filtered, sub_coordinates, sub_output = arg _nd_image.geometric_transform(sub_filtered, None, sub_coordinates, None, None, sub_output, order, mode, cval, None, None) if chunklen > 0: list_of_chunk_args = list(chunk_arguments(filtered, coordinates, output)) else: list_of_chunk_args = [(filtered, coordinates, output)] if len(list_of_chunk_args) == 1: threads = 1 if threads != 1: threadpool = ThreadPoolExecutor(threads) my_map = threadpool.map else: my_map = map # execution happens here list(my_map(map_coordinates_chunk, list_of_chunk_args)) if threads != 1: if have_concurrent_futures: threadpool.shutdown() else: threadpool.close() threadpool.join() return retval
def pad(input, size=None, footprint=None, output=None, mode="reflect", cval=0.0): r""" Returns a copy of the input, padded by the supplied structuring element. In the case of odd dimensionality, the structure element will be centered as following on the currently processed position:: [[T, Tx, T], [T, T , T]] , where Tx denotes the center of the structure element. Simulates the behaviour of scipy.ndimage filters. Parameters ---------- input : array_like Input array to pad. size : scalar or tuple, optional See footprint, below footprint : array, optional Either `size` or `footprint` must be defined. `size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``size=(n,m)`` is equivalent to ``footprint=np.ones((n,m))``. We adjust `size` to the number of dimensions of the input array, so that, if the input array is shape (10,10,10), and `size` is 2, then the actual size used is (2,2,2). output : array, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect'. cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 Returns ------- output : ndarray The padded version of the input image. Notes ----- Since version 1.7.0, numpy supplied a pad function `numpy.pad` that provides the same functionality and should be preferred. Raises ------ ValueError If the provided footprint/size is more than double the image size. """ input = numpy.asarray(input) if footprint is None: if size is None: raise RuntimeError("no footprint or filter size provided") sizes = _ni_support._normalize_sequence(size, input.ndim) footprint = numpy.ones(sizes, dtype=bool) else: footprint = numpy.asarray(footprint, dtype=bool) fshape = [ii for ii in footprint.shape if ii > 0] if len(fshape) != input.ndim: raise RuntimeError('filter footprint array has incorrect shape.') if numpy.any([x > 2 * y for x, y in zip(footprint.shape, input.shape)]): raise ValueError( 'The size of the padding element is not allowed to be more than double the size of the input array in any dimension.' ) padding_offset = [((s - 1) / 2, s / 2) for s in fshape] input_slicer = [ slice(l, None if 0 == r else -1 * r) for l, r in padding_offset ] output_shape = [s + sum(os) for s, os in zip(input.shape, padding_offset)] output, return_value = _ni_support._get_output(output, input, output_shape) if 'constant' == mode: output += cval output[input_slicer] = input return return_value elif 'nearest' == mode: output[input_slicer] = input dim_mult_slices = [ (d, l, slice(None, l), slice(l, l + 1)) for d, (l, _) in zip(list(range(output.ndim)), padding_offset) if not 0 == l ] dim_mult_slices.extend([ (d, r, slice(-1 * r, None), slice(-2 * r, -2 * r + 1)) for d, (_, r) in zip(list(range(output.ndim)), padding_offset) if not 0 == r ]) for dim, mult, to_slice, from_slice in dim_mult_slices: slicer_to = [ to_slice if d == dim else slice(None) for d in range(output.ndim) ] slicer_from = [ from_slice if d == dim else slice(None) for d in range(output.ndim) ] if not 0 == mult: output[slicer_to] = numpy.concatenate([output[slicer_from]] * mult, dim) return return_value elif 'mirror' == mode: dim_slices = [ (d, slice(None, l), slice(l + 1, 2 * l + 1)) for d, (l, _) in zip(list(range(output.ndim)), padding_offset) if not 0 == l ] dim_slices.extend([ (d, slice(-1 * r, None), slice(-2 * r - 1, -1 * r - 1)) for d, (_, r) in zip(list(range(output.ndim)), padding_offset) if not 0 == r ]) reverse_slice = slice(None, None, -1) elif 'reflect' == mode: dim_slices = [ (d, slice(None, l), slice(l, 2 * l)) for d, (l, _) in zip(list(range(output.ndim)), padding_offset) if not 0 == l ] dim_slices.extend([ (d, slice(-1 * r, None), slice(-2 * r, -1 * r)) for d, (_, r) in zip(list(range(output.ndim)), padding_offset) if not 0 == r ]) reverse_slice = slice(None, None, -1) elif 'wrap' == mode: dim_slices = [ (d, slice(None, l), slice(-1 * (l + r), -1 * r if not 0 == r else None)) for d, (l, r) in zip(list(range(output.ndim)), padding_offset) if not 0 == l ] dim_slices.extend([ (d, slice(-1 * r, None), slice(l, r + l)) for d, (l, r) in zip(list(range(output.ndim)), padding_offset) if not 0 == r ]) reverse_slice = slice(None) else: raise RuntimeError('boundary mode not supported') output[input_slicer] = input for dim, to_slice, from_slice in dim_slices: slicer_reverse = [ reverse_slice if d == dim else slice(None) for d in range(output.ndim) ] slicer_to = [ to_slice if d == dim else slice(None) for d in range(output.ndim) ] slicer_from = [ from_slice if d == dim else slice(None) for d in range(output.ndim) ] output[slicer_to] = output[slicer_from][slicer_reverse] return return_value
def pad(input, size=None, footprint=None, output=None, mode="reflect", cval=0.0): """ Returns a copy of the input, padded by the supplied structuring element. In the case of odd dimensionality, the structure element will be centered as following on the currently processed position: [[T, Tx, T], [T, T , T]] , where Tx denotes the center of the structure element. Simulates the behaviour of scipy.ndimage filters. input : array_like Input array to pad. size : scalar or tuple, optional See footprint, below footprint : array, optional Either `size` or `footprint` must be defined. `size` gives the shape that is taken from the input array, at every element position, to define the input to the filter function. `footprint` is a boolean array that specifies (implicitly) a shape, but also which of the elements within this shape will get passed to the filter function. Thus ``size=(n,m)`` is equivalent to ``footprint=np.ones((n,m))``. We adjust `size` to the number of dimensions of the input array, so that, if the input array is shape (10,10,10), and `size` is 2, then the actual size used is (2,2,2). output : array, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect'. cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 """ input = numpy.asarray(input) if footprint is None: if size is None: raise RuntimeError("no footprint or filter size provided") sizes = _ni_support._normalize_sequence(size, input.ndim) footprint = numpy.ones(sizes, dtype=bool) else: footprint = numpy.asarray(footprint, dtype=bool) fshape = [ii for ii in footprint.shape if ii > 0] if len(fshape) != input.ndim: raise RuntimeError('filter footprint array has incorrect shape.') padding_offset = [((s - 1) / 2, s / 2) for s in fshape] input_slicer = [slice(l, None if 0 == r else -1 * r) for l, r in padding_offset] output_shape = [s + sum(os) for s, os in zip(input.shape, padding_offset)] output, return_value = _ni_support._get_output(output, input, output_shape) if 'constant' == mode: output += cval output[input_slicer] = input return return_value elif 'nearest' == mode: output[input_slicer] = input dim_mult_slices = [(d, l, slice(None, l), slice(l, l + 1)) for d, (l, _) in zip(range(output.ndim), padding_offset) if not 0 == l] dim_mult_slices.extend([(d, r, slice(-1 * r, None), slice(-2 * r, -2 * r + 1)) for d, (_, r) in zip(range(output.ndim), padding_offset) if not 0 == r]) for dim, mult, to_slice, from_slice in dim_mult_slices: slicer_to = [to_slice if d == dim else slice(None) for d in range(output.ndim)] slicer_from = [from_slice if d == dim else slice(None) for d in range(output.ndim)] if not 0 == mult: output[slicer_to] = numpy.concatenate([output[slicer_from]] * mult, dim) return return_value elif 'mirror' == mode: dim_slices = [(d, slice(None, l), slice(l + 1, 2 * l + 1)) for d, (l, _) in zip(range(output.ndim), padding_offset) if not 0 == l] dim_slices.extend([(d, slice(-1 * r, None), slice(-2 * r - 1, -1 * r - 1)) for d, (_, r) in zip(range(output.ndim), padding_offset) if not 0 == r]) reverse_slice = slice(None, None, -1) elif 'reflect' == mode: dim_slices = [(d, slice(None, l), slice(l, 2 * l)) for d, (l, _) in zip(range(output.ndim), padding_offset) if not 0 == l] dim_slices.extend([(d, slice(-1 * r, None), slice(-2 * r, -1 * r)) for d, (_, r) in zip(range(output.ndim), padding_offset) if not 0 == r]) reverse_slice = slice(None, None, -1) elif 'wrap' == mode: dim_slices = [(d, slice(None, l), slice(-1 * (l + r), -1 * r if not 0 == r else None)) for d, (l, r) in zip(range(output.ndim), padding_offset) if not 0 == l] dim_slices.extend([(d, slice(-1 * r, None), slice(l, r + l)) for d, (l, r) in zip(range(output.ndim), padding_offset) if not 0 == r]) reverse_slice = slice(None) else: raise RuntimeError('boundary mode not supported') output[input_slicer] = input for dim, to_slice, from_slice in dim_slices: slicer_reverse = [reverse_slice if d == dim else slice(None) for d in range(output.ndim)] slicer_to = [to_slice if d == dim else slice(None) for d in range(output.ndim)] slicer_from = [from_slice if d == dim else slice(None) for d in range(output.ndim)] output[slicer_to] = output[slicer_from][slicer_reverse] return return_value
def immerkaer_local(input, size, output=None, mode="reflect", cval=0.0): r""" Estimate the local noise. The input image is assumed to have additive zero mean Gaussian noise. The Immerkaer noise estimation is applied to the image locally over a N-dimensional cube of side-length size. The size of the region should be sufficiently high for a stable noise estimation. Parameters ---------- input : array_like Array of which to estimate the noise. size : integer The local region's side length. output : ndarray, optional The `output` parameter passes an array in which to store the filter output. mode : {'reflect', 'constant', 'nearest', 'mirror', 'wrap'}, optional The `mode` parameter determines how the array borders are handled, where `cval` is the value when mode is equal to 'constant'. Default is 'reflect' cval : scalar, optional Value to fill past edges of input if `mode` is 'constant'. Default is 0.0 Returns ------- sigmas : array_like Map of the estimated standard deviation of the images Gaussian noise per voxel. Notes ----- Does not take the voxel spacing into account. Works good with medium to strong noise. Tends to underestimate for low noise levels. See also -------- immerkaer """ output, return_value = _ni_support._get_output(output, input) footprint = numpy.asarray([1] * size) # build nd-kernel to acquire square root of sum of squared elements kernel = [1, -2, 1] for _ in range(input.ndim - 1): kernel = numpy.tensordot(kernel, [1, -2, 1], 0) divider = numpy.square(numpy.abs(kernel)).sum() # 36 for 1d, 216 for 3D, etc. # compute laplace of input laplace = separable_convolution(input, [1, -2, 1], numpy.double, mode, cval) # compute factor factor = numpy.sqrt(numpy.pi / 2.) * 1. / ( numpy.sqrt(divider) * numpy.power(footprint.size, laplace.ndim) ) # locally sum laplacian values separable_convolution(numpy.abs(laplace), footprint, output, mode, cval) output *= factor return return_value