示例#1
0
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
示例#2
0
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