Esempio n. 1
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;
Esempio n. 2
0
def detect_cells(
        source,
        sink=None,
        cell_detection_parameter=default_cell_detection_parameter,
        processing_parameter=default_cell_detection_processing_parameter):
    """Cell detection pipeline.
  
  Arguments
  ---------
  source : source specification
    The source of the stitched raw data.
  sink : sink specification or None
    The sink to write the result to. If None, an array is returned.
  cell_detection_parameter : dict
    Parameter for the binarization. See below for details.
  processing_parameter : dict
    Parameter for the parallel processing. 
    See :func:`ClearMap.ParallelProcessing.BlockProcesing.process` for 
    description of all the parameter.
  verbose : bool
    If True, print progress output.
  
  Returns
  -------
  sink : Source
    The result of the cell detection.
  
  Notes
  -----
  Effectively this function performs the following steps:
    * illumination correction via :func:`~ClearMap.ImageProcessing.IlluminationCorrection.correct_illumination`
    * background removal
    * difference of Gaussians (DoG) filter
    * maxima detection via :func:`~ClearMap.Analysis.Measurements.MaximaDetection.find_extended_maxima`
    * cell shape detection via :func:`~ClearMap.Analysis.Measurements.ShapeDetection.detect_shape`
    * cell intensity and size measurements via: :func:`~ClearMap.ImageProcessing.Measurements.ShapeDetection.find_intensity`,
      :func:`~ClearMap.ImageProcessing.Measurements.ShapeDetection.find_size`. 

  
  The parameters for each step are passed as sub-dictionaries to the 
    cell_detection_parameter dictionary.
  
  * If None is passed for one of the steps this step is skipped.
  
  * Each step also has an additional parameter 'save' that enables saving of 
    the result of that step to a file to inspect the pipeline.
  
  
  Illumination correction
  -----------------------
  illumination_correction : dict or None
    Illumination correction step parameter.

    flatfield : array or str 
      The flat field estimate for the image planes.
    
    background : array or None
      A background level to assume for the flatfield correction.
    
    scaling : float, 'max', 'mean' or None
      Optional scaling after the flat field correction.
    
    save : str or None
      Save the result of this step to the specified file if not None.
          
  See also :func:`ClearMap.ImageProcessing.IlluminationCorrection.correct_illumination`
  
  
  Background removal
  ------------------
  background_correction : dict or None
    Background removal step parameter.

    shape : tuple
      The shape of the structure lement to estimate the background.
      This should be larger than the typical cell size.
    
    form : str
      The form of the structur element (e.g. 'Disk')
        
    save : str or None
      Save the result of this step to the specified file if not None.
  
  Equalization
  ------------
  equalization : dict or None
    Equalization step parameter.
    See also :func:`ClearMap.ImageProcessing.LocalStatistics.local_percentile`
    
    precentile : tuple
      The lower and upper percentiles used to estimate the equalization.
      The lower percentile is used for normalization, the upper to limit the
      maximal boost to a maximal intensity above this percentile.
    
    max_value : float
      The maximal intensity value in the equalized image.
    
    selem : tuple
      The structural element size to estimate the percentiles. 
      Should be larger than the larger vessels.
    
    spacing : tuple
      The spacing used to move the structural elements.
      Larger spacings speed up processing but become locally less precise.
        
    interpolate : int
      The order of the interpoltation used in constructing the full 
      background estimate in case a non-trivial spacing is used.
      
    save : str or None
      Save the result of this step to the specified file if not None.
  
  
  DoG Filter
  ----------
  dog_filter : dict or None
    Difference of Gaussian filter step parameter.

    shape : tuple
      The shape of the filter.
      This should be near the typical cell size.
      
    sigma : tuple or None
       The std of the inner Gaussian.
       If None, detemined automatically from shape.
    
    sigma2 : tuple or None
       The std of the outer Gaussian.
       If None, detemined automatically from shape.
    
    save : str or None
      Save the result of this step to the specified file if not None.
  
  
  Maxima detection
  ----------------
  maxima_detection : dict or None
    Extended maxima detection step parameter.

    h_max : float or None
      The 'height'for the extended maxima.
      If None, simple local maxima detection isused.

    shape : tuple
      The shape of the structural element for extended maxima detection.
      This should be near the typical cell size.
    
    threshold : float or None
      Only maxima above this threshold are detected. If None, all maxima
      are detected.
      
    valid : bool
      If True, only detect cell centers in the valid range of the blocks with
      overlap.
    
    save : str or None
      Save the result of this step to the specified file if not None.
  
  
  Shape detection
  ---------------
  shape_detection : dict or None
    Shape detection step parameter.

    threshold : float
      Cell shape is expanded from maxima if pixles are above this threshold
      and not closer to another maxima.
    
    save : str or None
      Save the result of this step to the specified file if not None.
  
  
  Intensity detection
  -------------------
  intensity_detection : dict or None
    Intensity detection step parameter.

    method : {'max'|'min','mean'|'sum'}
      The method to use to measure the intensity of a cell.
      
    shape : tuple or None
      If no cell shapes are detected a disk of this shape is used to measure
      the cell intensity.
    
    save : str or None
      Save the result of this step to the specified file if not None.
  
  References
  ----------
  [1] Renier, Adams, Kirst, Wu et al., "Mapping of Brain Activity by Automated Volume Analysis of Immediate Early Genes.", Cell 165, 1789 (2016)
  [1] Kirst et al., "Mapping the Fine-Scale Organization and Plasticity of the Brain Vasculature", Cell 180, 780 (2020)
  """

    #initialize sink
    shape = io.shape(source)
    order = io.order(source)

    for key in cell_detection_parameter.keys():
        par = cell_detection_parameter[key]
        if isinstance(par, dict):
            filename = par.get('save', None)
            if filename:
                ap.initialize_sink(filename,
                                   shape=shape,
                                   order=order,
                                   dtype='float')

    cell_detection_parameter.update(
        verbose=processing_parameter.get('verbose', False))

    results, blocks = bp.process(detect_cells_block,
                                 source,
                                 sink=None,
                                 function_type='block',
                                 return_result=True,
                                 return_blocks=True,
                                 parameter=cell_detection_parameter,
                                 **processing_parameter)

    #merge results
    results = np.vstack([np.hstack(r) for r in results])

    #create column headers
    header = ['x', 'y', 'z']
    dtypes = [int, int, int]
    if cell_detection_parameter['shape_detection'] is not None:
        header += ['size']
        dtypes += [int]
    measures = cell_detection_parameter['intensity_detection']['measure']
    header += measures
    dtypes += [float] * len(measures)

    dt = {
        'names': header,
        'formats': dtypes
    }
    cells = np.zeros(len(results), dtype=dt)
    for i, h in enumerate(header):
        cells[h] = results[:, i]

    #save results
    return io.write(sink, cells)
Esempio n. 3
0
def binarize(source, sink = None, binarization_parameter = default_binarization_parameter, processing_parameter = default_binarization_processing_parameter):
  """Multi-path binarization of iDISCO+ cleared vasculature data.
  
  Arguments
  ---------
  source : source specification
    The source of the stitched raw data.
  sink : sink specification or None
    The sink to write the result to. If None, an array is returned.
  binarization_parameter : dict
    Parameter for the binarization. See below for details.
  processing_parameter : dict
    Parameter for the parallel processing. 
    See :func:`ClearMap.ParallelProcessing.BlockProcesing.process` for 
    description of all the parameter.
  verbose : bool
    If True, print progress output.
  
  Returns
  -------
  sink : Source
    The result of the binarization.
  
  Notes
  -----
  * The binarization pipeline is composed of several steps. The parameters for
    each step are passed as sub-dictionaries to the binarization_parameter 
    dictionary.
  
  * If None is passed for one of the steps this step is skipped.
  
  * Each step also has an additional parameter 'save' that enables saving of 
    the result of that step to a file to inspect the pipeline.
    
  General parameter
  -----------------
  binary_status : str or None
    File name to save the information about which part of the multi-path 
    binarization contributed to the final result.
    
  max_bin : int
    Number of intensity levels to use for the data after preprocessing.
    Higher values will increase the intensity resolution but slow down
    processing. 
    
    For the vasculature a typical value is 2**12.

  Clipping
  --------
  clip : dict or None
    Clipping and mask generation step parameter.

    clip_range : tuple 
      The range to clip the raw data as (lowest, highest)
      Voxels above lowest define the foregournd mask used 
      in the following steps.
      
      For the vasculature a typical value is (400,60000). 
      
    save : str or None
      Save the result of this step to the specified file if not None.
          
  See also :mod:`ClearMap.ImageProcessing.Clipping.Clipping`
      
  Lightsheet correction
  ---------------------  
  lightsheet : dict or None
    Lightsheet correction step parameter.
   
    percentile : float
      Percentile in [0,1] used to estimate the lightshieet artifact.
      
      For the vasculature a typical value is 0.25.
      
    lightsheet : dict
      Parameter for the ligthsheet artifact percentile estimation. 
      See :func:`ClearMap.ImageProcessing.LightsheetCorrection.correct_lightsheet`
      for list of all parameters. The crucial parameter is
      
      selem : tuple
        The structural element shape used to estimate the stripe artifact.
        It should match the typical lenght, width, and depth of the artifact 
        in the data.
        
        For the vasculature a typical value is (150,1,1).
    
    background : dict
      Parameter for the background estimation in the light sheet correction. 
      See :func:`ClearMap.ImageProcessing.LightsheetCorrection.correct_lightsheet`
      for list of all parameters. The crucial parameters are
      
      selem : tuple
        The structural element shape used to estimate the background.
        It should be bigger than the largest vessels,
        
        For the vasculature a typical value is (200,200,1).

      spacing : tuple
        The spacing to use to estimate the background. Larger spacings speed up
        processing but become less local estimates.
        
        For the vasculature a typical value is (25,25,1)
        
      step : tuple
        This parameter enables to subsample from the entire array defined by
        the structural element using larger than single voxel steps.
        
        For the vasculature a typical value is (2,2,1).
        
      interpolate : int
        The order of the interpoltation used in constructing the full 
        background estimate in case a non-trivial spacing is used.
        
        For the vasculature a typical value is 1.
        
    lightsheet_vs_background : float
      The background is multiplied by this weight before comparing to the
      lightsheet artifact estimate. 
      
      For the vasculature a typical value is 2.
    
    save : str or None
      Save the result of this step to the specified file if not None.

  Median filter
  -------------
  median : dict or None
    Median correction step parameter.
    See :func:`ClearMap.ImageProcessing.Filter.Rank.median` for all parameter.
    The important parameters are

    selem : tuple
      The structural element size for the median filter.
      
      For the vascualture a typical value is (3,3,3).
    
    save : str or None
      Save the result of this step to the specified file if not None.  
  
  Pseudo Deconvolution
  --------------------
  deconvolve : dict
    The deconvolution step parameter.
    
    sigma : float
      The std of a Gaussina filter applied to the high intensity pixel image.
      The number should reflect the scale of the halo effect seen around high
      intensity structures.
      
      For the vasculature a typical value is 10.
    
    save : str or None
      Save the result of this step to the specified file if not None.   
      
    threshold : float 
      Voxels above this threshold will be added to the binarization result
      in the multi-path biniarization.
      
      For the vasculature a typical value is 750.
  
  Adaptive Thresholding
  ---------------------
  adaptive : dict or None
    Adaptive thresholding step parameter.
    A local ISODATA threshold is estimated.
    See also :mod:`ClearMap.ImageProcessing.LocalStatistics`.
    
    selem : tuple
      The structural element size to estimate the percentiles. 
      Should be larger than the larger vessels.
      
      For the vasculature a typical value is (200,200,5).
    
    spacing : tuple
      The spacing used to move the structural elements.
      Larger spacings speed up processing but become locally less precise.
               
      For the vasculature a typical value is (50,50,5)
        
    interpolate : int
      The order of the interpoltation used in constructing the full 
      background estimate in case a non-trivial spacing is used.
      
      For the vasculature a typical value is 1.
      
    save : str or None
      Save the result of this step to the specified file if not None.   


  Equalization
  ------------
  equalize : dict or None
    Equalization step parameter.
    See also :func:`ClearMap.ImageProcessing.LocalStatistics.local_percentile`
    
    precentile : tuple
      The lower and upper percentiles used to estimate the equalization.
      The lower percentile is used for normalization, the upper to limit the
      maximal boost to a maximal intensity above this percentile.
    
      For the vasculature a typical value is (0.4, 0.975).
    
    max_value : float
      The maximal intensity value in the equalized image.
               
      For the vasculature a typical value is 1.5. 
    
    selem : tuple
      The structural element size to estimate the percentiles. 
      Should be larger than the larger vessels.
      
      For the vasculature a typical value is (200,200,5).
    
    spacing : tuple
      The spacing used to move the structural elements.
      Larger spacings speed up processing but become locally less precise.
               
      For the vasculature a typical value is (50,50,5)
        
    interpolate : int
      The order of the interpoltation used in constructing the full 
      background estimate in case a non-trivial spacing is used.
      
      For the vasculature a typical value is 1.
      
    save : str or None
      Save the result of this step to the specified file if not None.   
      
    threshold : float 
      Voxels above this threshold will be added to the binarization result
      in the multi-path biniarization.
      
      For the vasculature a typical value is 1.1.

  Tube filter
  -----------
  vesselize : dict
    The tube filter step parameter.
    
    background : dict or None
      Parameters to correct for local background. See 
      :func:`ClearMap.ImageProcessing.Filter.Rank.percentile`.
      If None, no background correction is done before the tube filter.
      
      selem : tuple
        The structural element specification to estimate the percentiles. 
        Should be larger than the largest vessels intended to be 
        boosted by the tube filter.
        
        For the vasculature a typical value is ('disk', (30,30,1)) .

      percentile : float
        Percentile in [0,1] used to estimate the background.

        For the vasculature a typical value is 0.5.
        
    tubness : dict
      Parameters used for the tube filter. See 
      :func:`ClearMap.ImageProcessing.Differentiation.Hessian.lambda123`.
      
      sigma : float
        The scale of the vessels to boos in the filter.
        
        For the vasculature a typical value is 1.0.
  
    save : str or None
      Save the result of this step to the specified file if not None.   
      
    threshold : float 
      Voxels above this threshold will be added to the binarization result
      in the multi-path biniarization.
      
      For the vasculature a typical value is 120.
  
  Binary filling
  --------------
  fill : dict or None
    If not None, apply a binary filling the binarized result.

  For the vasculature this step is set to None and done globally 
  in the postprocessing step.
  
  Binary smoothing
  ----------------
  smooth : dict or None
    The smoothing parameter passed to 
    :func:`ClearMap.ImageProcessing.Binary.Smoothing.smooth_by_configuration`.
  
  For the vasculature this step is set to None and done globally 
  in the postprocessing step.
  
  References
  ----------
  [1] C. Kirst et al., "Mapping the Fine-Scale Organization and Plasticity of the Brain Vasculature", Cell 180, 780 (2020)
  """
    
  #initialize sink
  shape = io.shape(source);
  order = io.order(source);
  sink, sink_buffer = ap.initialize_sink(sink=sink, shape=shape, order=order, dtype=bool); #, memory='shared');
  
  #initialize addition output sinks  
  binary_status = binarization_parameter.get('binary_status', None);
  if binary_status:
    ap.initialize_sink(binary_status, source=sink, shape=shape, order=order, dtype='uint16');

  for key in binarization_parameter.keys():
    par = binarization_parameter[key];
    if isinstance(par, dict):
      filename = par.get('save', None);
      if filename:
        ap.initialize_sink(filename, shape=shape, order=order, dtype='float');
        
  binarization_parameter.update(verbose=processing_parameter.get('verbose', False));
  
  bp.process(binarize_block, source, sink, function_type='block', parameter=binarization_parameter, **processing_parameter)                   
  
  return sink;                
Esempio n. 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
Esempio n. 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