Beispiel #1
0
def border_indices(source):
    """Returns the flat indices of the border pixels in source"""

    ndim = source.ndim
    shape = source.shape
    strides = io.element_strides(source)

    border = []
    for d in range(ndim):
        offsets = tuple(0 if i > d else 1 for i in range(ndim))
        for c in [0, shape[d] - 1]:
            sl = tuple(
                slice(o, None if o == 0 else -o) if i != d else c
                for i, o in enumerate(offsets))
            where = np.where(np.logical_not(source[sl]))
            n = len(where[0])
            if n > 0:
                indices = np.zeros(n, dtype=int)
                l = 0
                for k in range(ndim):
                    if k == d:
                        indices += strides[k] * c
                    else:
                        indices += strides[k] * (where[l] + offsets[k])
                        l += 1
                border.append(indices)
    return np.concatenate(border)
Beispiel #2
0
def _apply_code(function, source, sink, sink_dtype = None, sink_shape_per_pixel = None, parameter = None, sigma = None):
  """Helper to apply the core functions"""
  if source.ndim != 3:
    raise ValueError('The tubness measure is implemented for 3d data, found %dd!' % source.ndim);
  
  if source is sink:
    raise ValueError("Cannot perform operation in place!")

  if sink_shape_per_pixel is None:
    shape_per_pixel = (1,);
  else:
    shape_per_pixel = sink_shape_per_pixel;
  
  if sink is None:
    if sink_dtype is None:
      sink_dtype = float
    sink = np.zeros(source.shape + shape_per_pixel, dtype = sink_dtype, order = 'F')
  else:
    if shape_per_pixel != (1,):
      if sink.shape != source.shape + shape_per_pixel:
        raise ValueError('The sink of shape %r does not have expected shape %r!' % (sink.shape, source.shape + shape_per_pixel));
    if sink.shape != source.shape + shape_per_pixel:
      sink = sink.reshape(source.shape + shape_per_pixel)
  
  if sink.dtype == bool:
    s = sink.view('uint8')
  else:
    s = sink;

  sink_stride = io.element_strides(sink)[-1];
    
  if parameter is None:
    parameter = np.zeros(0);
  parameter = np.asarray([parameter], dtype = float).flatten();
                     
  if sigma is not None:
    data = ndi.gaussian_filter(np.asarray(source, dtype=float), sigma=sigma);
  else:
    data = np.asarray(source, dtype=float);
  
  function(source=data, sink=s, sink_stride=sink_stride,  parameter=parameter)
  
  if sink_shape_per_pixel is None:
    sink = sink.reshape(sink.shape[:-1]);
  
  return sink
Beispiel #3
0
def _initialize_sink(sink = None, source = None, return_1d = False, return_strides = False, shape =  None, dtype = None, order = None, memory = None, location = None):
  """Helper to initialize sinks."""
  if sink is None:
    if shape is None:
      if source is None:
        raise ValueError("Cannot determine sink without source.");
      else:
        shape = source.shape;
    if dtype is None:
      if source is None:
        raise ValueError("Cannot determine sink without source.");
      else:
        dtype = source.dtype;  
    if order is None and source is not None:
      order = io.order(source);
  #print('shape=%r, dtype=%r, order=%r, memory=%r, location=%r' % (shape, dtype, order, memory, location));
        
  sink = io.prepare_sink(sink, shape=shape, dtype=dtype, order=order, memory=memory, location=location);
  
  if sink.dtype == bool:
    sink = sink.view('uint8');  

  if return_strides:
    strides = io.element_strides(sink);
  
  if return_1d:
    sink1d = sink.reshape(-1, order = 'A');
  
  if not return_strides and not return_1d:
    return sink;

  result = (sink,)
  if return_strides:
    result += (strides,);
  if return_1d:
    result += (sink1d,);
  return result;
Beispiel #4
0
def threshold(source,
              sink=None,
              threshold=None,
              hysteresis_threshold=None,
              seeds=None,
              background=None):
    """Hysteresis thresholding.
    
    Arguments
    ---------
    source : array
      Input source.
    sink : array or None
      If None, a new array is allocated.
    threshold : float
      The threshold for the intial seeds.
    hysteresis_threshold : float or None
      The hysteresis threshold to extend the initial seeds. 
      If None, no hysteresis thresholding is performed.
    seeds : array or None
      The seeds from which to start the hysteresis thresholds 
    background : array or None
      Exclude this area from the hysteresis thresholding.
    
    Returns
    -------
    sink : array
        Thresholded output.
    """
    if threshold is None and seeds is None:
        raise ValueError('The threshold and seeds cannot both be None!')

    if source is sink:
        raise NotImplementedError("Cannot perform operation in place.")

    if sink is None:
        sink = np.zeros(source.shape, dtype='int8', order=io.order(source))

    source_flat = source.reshape(-1, order=io.order(source))
    sink_flat = sink.reshape(-1, order=io.order(sink))
    strides = np.array(io.element_strides(source))

    if seeds is None:
        seeds = np.where(source_flat >= threshold)[0]
    else:
        seeds_flat = seeds.reshape(-1, order=io.order(seeds))
        seeds = np.where(seeds_flat)[0]

    if hysteresis_threshold is not None:
        parameter_index = np.zeros(0, dtype=int)
        parameter_double = np.array([hysteresis_threshold], dtype=float)

        if background is not None:
            background_flat = background.reshape(-1,
                                                 order=io.order(background))
            background_flat = background_flat.view(dtype='uint8')
            code.threshold_to_background(source_flat, sink_flat,
                                         background_flat, strides, seeds,
                                         parameter_index, parameter_double)
        else:
            code.threshold(source_flat, sink_flat, strides, seeds,
                           parameter_index, parameter_double)

    else:
        sink_flat[seeds] = 1

    return sink
Beispiel #5
0
def fill(source, sink=None, seeds=None, processes=None, verbose=False):
    """Fill binary holes.
  
  Arguments
  ---------
  source : array
      Input source.
  sink : array or None
      If None, a new array is allocated.
 

  Returns
  -------
  sink : array
      Binary image with filled holes.
  """
    if source is sink:
        raise NotImplementedError("Cannot perform operation in place.")

    if verbose:
        print('Binary filling: initialized!')
        timer = tmr.Timer()

    #create temporary shared array
    order = io.order(source)
    #temp = sma.empty(source.shape, dtype='int8', order=order);
    temp = np.empty(source.shape, dtype='int8', order=order)

    source_flat = source.reshape(-1, order='A')
    temp_flat = temp.reshape(-1, order='A')

    if source_flat.dtype == bool:
        source_flat = source_flat.view(dtype='uint8')

    if processes is None:
        processes = mp.cpu_count()
    if not isinstance(processes, int):
        processes = 1

    #prepare flood fill
    code.prepare_temp(source_flat, temp_flat, processes=processes)

    #flood fill in parallel using mp
    if seeds is None:
        seeds = border_indices(source)
    else:
        seeds = np.where(seeds.reshape(-1, order=order))[0]

    strides = np.array(io.element_strides(source))

    code.label_temp(temp_flat, strides, seeds, processes=processes)

    if sink is None:
        #sink = sma.empty(source.shape, dtype=bool, order=order);
        sink = np.empty(source.shape, dtype=bool, order=order)
    sink_flat = sink.reshape(-1, order=order)

    if sink_flat.dtype == 'bool':
        sink_flat = sink_flat.view(dtype='uint8')

    code.fill(source_flat, temp_flat, sink_flat, processes=processes)

    if verbose:
        timer.print_elapsed_time('Binary filling')

    del temp, temp_flat
    gc.collect()

    return sink
Beispiel #6
0
def convolve_3d_indices_if_smaller_than(source, kernel, indices, max_value, sink = None, strides = None, check_border = True, processes = cpu_count()):
  """Convolves source with a specified kernel at specific points given by a flat array indx under conditon the value is smaller than a number
    
  Arguments
  ---------
  source : array
    3d binary array to convolve.
  kernel : array
    Convolution kernel.
  indices : array
    Indices to convolve.
  max_value : float
    Checks if the convolution result is smaller than this value.
  sink : array
    Optional sink to write result to.
  strides : array
    The strides of the source in case its given as a 1d list.
  check_border : bool
    If True, check if each kernel element is inside the source array shape.
  processes : int or None
    Number of processes to use.
  
  Returns
  -------
  convolved : array
    List of results of convolution at specified points
  """
  d = source.reshape(-1, order = 'A');
  if source.dtype == bool:
    d = d.view('uint8');
    
  npts = indices.shape[0];
  
  if sink is None:
    sink = np.zeros(npts, dtype = bool);
  
  if sink.shape[0] != npts:
     raise RuntimeError('The sinkput has not the expected size of %d but %d' % (npts, sink.shape[0]));
  
  if sink.dtype == bool:
    o = sink.view('uint8');
  else:
    o = sink;

  if kernel.dtype == bool:
    k = np.array(kernel, dtype = 'uint8');
  else:
    k = kernel;
  
  if processes is None:
    processes = cpu_count();
  
  if strides is None:
    strides = np.array(io.element_strides(source), dtype=int);
  
  #print d.dtype, strides.dtype, kernel.dtype, o.dtype
  if check_border:
    print(d.dtype, strides.dtype, k.dtype, indices.dtype, np.array(max_value).dtype, o.dtype)
    code.convolve_3d_indices_if_smaller_than(d, strides, k, indices, max_value, o, processes);
  else:
    code.convolve_3d_indices_if_smaller_than_no_check(d, strides, k, indices, max_value, o, processes);
  
  return sink;
Beispiel #7
0
def convolve_3d_indices(source, kernel, indices, sink = None, sink_dtype = None, strides = None, check_border = True, processes = cpu_count()):
  """Convolves source with a specified kernel at specific points given by a flat array index.
    
  Arguments
  ---------
  source : array
    3d binary array to convolve.
  kernel : array
    Convolution kernel.
  indices : array
    Indices to convolve.
  sink : array
    Optional sink to write result to.
  sink_dtype : dtype)
    Optional type of the sink. If None, the kernel type is used as default.
  strides : array
    The strides of the source in case its given as a 1d list.
  check_border : bool
    If True, check if each kernel element is inside the source array shape.
  processes : int or None
    Number of processes to use.
  
  Returns
  -------
  convolved : array
    List of results of convolution.
  """
  d = source.reshape(-1, order = 'A');
  if source.dtype == bool:
    d = d.view('uint8');
    
  npts = indices.shape[0];
    
  if sink is None:
    if sink_dtype is None:
      sink_dtype = kernel.dtype;
    sink = np.zeros(npts, dtype = sink_dtype);
  
  if sink.shape[0] != npts:
     raise RuntimeError('The sinkput has not the expected size of %d but %d' % (npts, sink.shape[0]));
  
  if sink.dtype == bool:
    o = sink.view('uint8');
  else:
    o = sink;

  if kernel.dtype == bool:
    k = np.array(kernel, 'uint8');
  else:
    k = kernel; 

  if processes is None:
    processes = cpu_count();
  
  if strides is None:
    strides = np.array(io.element_strides(source));
  
  #print d.dtype, strides.dtype, kernel.dtype, o.dtype
  if check_border:
    code.convolve_3d_indices(d, strides, k, indices, o, processes);
  else:
    code.convolve_3d_indices_no_check(d, strides, k, indices, o, processes);
  
  return sink;