def threshold(a, threshold_function, num_blocks, block_dims = None, smoothing_factor = 0.003, *args): a_dims = a.shape if num_blocks >= 16: spline_order = 3 else: spline_order = int(np.sqrt(num_blocks) - 1) if spline_order == 0: return (np.ones_like(a) * threshold_function(a, *args)) if block_dims is None: block_dim = int(round(np.sqrt(2 * a.size / num_blocks))) block_dims = (block_dim, block_dim) points = best_candidate_sample(a_dims, num_blocks) th = [] for p in points: block = get_block(a, p, block_dims) threshold = threshold_function(block, *args) th.append(threshold) th = np.asarray(th) # Maybe consider using lower-order spline for large images # (if large indices create problems for cubic functions) fit = spline2d(points[:,0], points[:,1], th, bbox = [0, a_dims[0], 0, a_dims[1]], kx = spline_order, ky = spline_order, s = num_blocks * smoothing_factor) th_new = fit(x = np.arange(a_dims[0]), y = np.arange(a_dims[1])) th_new = fix_border(th_new, points) return th_new
def load_lsf(lsf_fname, wl, nsub=1): """ Load a Line-Spread Function table following format from HST: First line gives wavelength in Angstrom and the column below each given wavelength defines the kernel in pixel space:: wl1 wl2 wl3 ... wlN lsf11 lsf21 lsf31 ... lsfN1 lsf12 lsf22 lsf32 ... lsfN2 : : lsf1M lsf2M lsf3M ... lsfNM Parameters ---------- lsf_fname : string The filename containing the LSF data. wl : array like, shape (N) The wavelength grid onto which the LSF will be evaluated nsub : integer [default = 1] Kernel subsampling factor relative to the data. Returns ------- kernel : np.array, shape(N, M) A grid of interpolated LSF evaluated at each given input wavelength of the array `wl` of shape N, where M is the number of pixels in the LSF. Notes ----- The output kernel is transposed with respect to the input format for ease of computation in the convolution since indexing is faster along rows than columns. """ if nsub > 1: wl = np.linspace(wl.min(), wl.max(), nsub * len(wl)) lsf_tab = np.loadtxt(lsf_fname) # Get the wavelength array from the first line in the file: lsf_wl = lsf_tab[0] # The LSF data is the resulting table excluding the first line: lsf = lsf_tab[1:, :] # Normalize the LSF: lsf_norm = np.sum(lsf, axis=0) lsf = lsf / lsf_norm # Make an array of pixel indeces: lsf_pix = np.arange(lsf.shape[0]) # Linearly interpolate the LSF grid: LSF = spline2d(lsf_pix, lsf_wl, lsf, kx=1, ky=1) kernel = LSF(lsf_pix, wl).T return kernel
def threshold(img, threshold_function, num_blocks, block_dims=None, smoothing=0.003): ''' Get a smoothly varying threshold from an image by applying the threshold function to multiple randomly positioned blocks of the image and using a 2-D smoothing spline to set the threshold across the image. Parameters ------------ img : 2-D numpy array The grayscale image. threshold_function : a function The threshold function should take a grayscale image as an input and output an int or float. num_blocks : int The number of blocks within the image to which to apply the threshold function. A higher number will provide better coverage across the image but will take longer to evaluate. block_dims : tuple or numpy array, optional The dimensions of the rectangular blocks. Dimensions should be less than the dimensions of the image. If left unspecified, the blocks will be squares with area approximately equal to two times the area of the image, divided by num_blocks. smoothing : float, optional A parameter to adjust the smoothness of the 2-D smoothing spline. A higher number increases the smoothness of the output. An input of zero is equivalent to interpolation. Returns --------- th_new : 2-D numpy array The threshold. The array is the same shape as the original input image. ''' img_dims = img.shape if num_blocks >= 16: spline_order = 3 else: spline_order = int(np.sqrt(num_blocks) - 1) if spline_order == 0: return (np.ones_like(img) * threshold_function(img)) if (type(img) is MaskedArray): mask = img.mask else: mask = np.zeros(img_dims, dtype=bool) candidate_coords = np.transpose(np.nonzero(~mask)) if block_dims is None: block_dim = int(round(np.sqrt(2 * img.size / num_blocks))) block_dims = (block_dim, block_dim) timeStart("select block centers") points = best_candidate_sample(candidate_coords, num_blocks) timeEnd("select block centers") def get_threshold_for_block(center): block = get_block(img, center, block_dims) if (type(block) is MaskedArray): return threshold_function(block.compressed()) else: return threshold_function(block) timeStart("calculate thresholds for blocks of size %s" % block_dim) thresholds = np.asarray( [get_threshold_for_block(center) for center in points]) timeEnd("calculate thresholds for blocks of size %s" % block_dim) timeStart("fit 2-D spline") # Maybe consider using lower-order spline for large images # (if large indices create problems for cubic functions) fit = spline2d(points[:, 0], points[:, 1], thresholds, bbox=[0, img_dims[0], 0, img_dims[1]], kx=spline_order, ky=spline_order, s=num_blocks * smoothing) th_new = fit(x=np.arange(img_dims[0]), y=np.arange(img_dims[1])) th_new = fix_border(th_new, points) timeEnd("fit 2-D spline") return th_new