def std(image, size): """ a moving std calculation on an nd image """ import numpy as np import ctypes import scipy.ndimage as ndi from numba import cfunc, carray from numba.core.types import intc, intp, float64, voidptr, CPointer from scipy import LowLevelCallable @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr), fastmath=True) def _std(values_ptr, len_values, result): values = carray(values_ptr, (len_values, ), dtype=float64) accumx = 0 accumx2 = 0 for x in values: accumx += x accumx2 += x * x mean = accumx / len_values std = np.sqrt((accumx2 / len_values) - mean**2) result[0] = std return 1 res = ndi.generic_filter(image, LowLevelCallable(_std.ctypes), size) return res
def filter_std(image, size, sigma=1): """ explicitly filters an nd image based on deviation by local stdev over local mean. return mask of points that are sigma local stdev over(under) the local mean if sigma is positiv(negativ) """ import numpy as np import ctypes import scipy.ndimage as ndi from numba import cfunc, carray from numba.core.types import intc, intp, float64, voidptr, CPointer from scipy import LowLevelCallable @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr), fastmath=True) def _std(values_ptr, len_values, result, data): values = carray(values_ptr, (len_values, ), dtype=float64) accumx = 0 accumx2 = 0 sigma = carray(data, (1, ), dtype=float64)[0] for x in values: accumx += x accumx2 += x * x mean = accumx / len_values std = np.sqrt((accumx2 / len_values) - mean**2) result[0] = sigma * std + mean return 1 csigma = ctypes.c_double(sigma) ptr = ctypes.cast(ctypes.pointer(csigma), ctypes.c_void_p) res = image > ndi.generic_filter(image, LowLevelCallable(_std.ctypes, ptr), size) if sigma < 0: res = ~res return res
def jit_filter_function(filter_function): """Decorator for use with scipy.ndimage.generic_filter.""" jitted_function = numba.jit(filter_function, nopython=True) @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr)) def wrapped(values_ptr, len_values, result, data): values = carray(values_ptr, (len_values, ), dtype=float64) result[0] = jitted_function(values) return 1 return LowLevelCallable(wrapped.ctypes)
def jit_geometric_function(geometric_function): jitted_function = numba.jit(geometric_function, nopython=True) @cfunc(intc(CPointer(intp), CPointer(float64), intc, intc, voidptr)) def wrapped(output_ptr, input_ptr, output_rank, input_rank, user_data): output_coords = carray(output_ptr, (output_rank, ), dtype=intp) input_coords = carray(input_ptr, (output_rank, ), dtype=float64) jitted_function(output_coords, input_coords) return 1 return LowLevelCallable(wrapped.ctypes)
def jit_filter_function(filter_function): """Decorator for use with scipy.ndimage.generic_filter.""" jitted_function = numba.jit(filter_function, nopython=True) @cfunc(intc(CPointer(float64), intp, CPointer(float64), voidptr)) def wrapped(values_ptr, len_values, result, data): values = carray(values_ptr, (len_values,), dtype=float64) result[0] = jitted_function(values) return 1 sig = None if sys.platform == "win32": sig = "int (double *, npy_intp, double *, void *)" return LowLevelCallable(wrapped.ctypes, signature=sig)
def jit_geometric_function(geometric_function): jitted_function = numba.jit(geometric_function, nopython=True) @cfunc(intc(CPointer(intp), CPointer(float64), intc, intc, voidptr)) def wrapped(output_ptr, input_ptr, output_rank, input_rank, user_data): output_coords = carray(output_ptr, (output_rank,), dtype=intp) input_coords = carray(input_ptr, (output_rank,), dtype=float64) jitted_function(output_coords, input_coords) return 1 # needs to be tested # sig = None # if sys.platform == "win32": # sig = "int (double *, double *, int, int, void *)" return LowLevelCallable(wrapped.ctypes, signature=sig)