def preprocess(array, flats=None, darks=None, mode='sides', dim=1): ''' Apply flatfield correction based on availability of flat- and dark-field. Args: flats (ndarray): divide by flats darks (ndarray): subtract darks mode (str): "sides" to use maximum values of the detector sides to estimate the flat field or a mode of intensity distribution with "single". dim (int): dimension that represents the projection number ''' logger.print('Pre-processing...') # Cast to float if int: if (array.dtype.kind == 'i') | (array.dtype.kind == 'u'): # In case array is mapped on disk, we need to rewrite the file as another type: new = array.astype('float32') array = data.rewrite_memmap(array, new) if darks is not None: darks = darks.astype('float32') if darks.ndim > 2: darks = darks.mean(dim) # Subtract: data.add_dim(array, -darks, dim) else: darks = numpy.zeros(1, dtype='float32') if flats is not None: flats = flats.astype('float32') if flats.ndim > 2: flats = flats.mean(dim) # Subtract: data.add_dim(flats, -darks, dim) data.mult_dim(array, 1 / flats, dim) numpy.log(array, out=array) array *= -1 # Fix nans and infs after log: array[~numpy.isfinite(array)] = 0 return array
def FISTA( projections, volume, geometry, iterations, lmbda = 0): ''' FISTA reconstruction. Right now there is no TV minimization substep here! ''' ss = settings preview = ss.preview bounds = ss.bounds # Residual norms: rnorms = [] # Various variables: t = 1 volume_t = volume.copy() volume_old = volume.copy() # TV residual: sz = list(volume.shape) sz.insert(0, 3) volume_tv = numpy.zeros(sz, dtype = 'float32') logger.print('FISTING started...') # Progress bar: pbar = _pbar_start_(iterations, 'iterations') for ii in range(iterations): # L2 update: norm = fista_update(projections, volume, volume_old, volume_t, volume_tv, t, geometry, lmbda = lmbda) if norm: rnorms.append(norm) # Apply bounds: if bounds: numpy.clip(volume, a_min = bounds[0], a_max = bounds[1], out = volume) # Show preview or progress: if preview: display.slice(volume, dim = 1, title = 'Preview') else: _pbar_update_(pbar) # Stop progress bar _pbar_close_(pbar) if rnorms: display.plot(rnorms, semilogy = True, title = 'Resudual norm')
def EM( projections, volume, geometry, iterations): """ Expectation Maximization """ ss = settings preview = ss.preview bounds = ss.bounds # Make sure that the volume is positive: if (volume.max() == 0)|(volume.min()<0): logger.error('Wrong initial guess. Make sure that initial guess for EM is positive.') if (projections.min() < 0): logger.error('Wrong projection data. Make sure that projections have no negative values.') logger.print('Em Emm Emmmm...') # Residual norms: rnorms = [] # Progress bar: pbar = _pbar_start_(iterations, 'iterations') for ii in range(iterations): # Update volume: norm = em_update(projections, volume, geometry) # Apply bounds if bounds: numpy.clip(volume, a_min = bounds[0], a_max = bounds[1], out = volume) if norm: rnorms.append(norm) if preview: display.slice(volume, dim = 1, title = 'Preview') else: _pbar_update_(pbar) # Stop progress bar _pbar_close_(pbar) if rnorms: display.plot(rnorms, semilogy = True, title = 'Resudual norm')
def residual_rings(array, kernel=[3, 3]): ''' Apply correction by computing outlayers . ''' # Compute mean image of intensity variations that are < 5x5 pixels logger.print( 'Our best agents are working on the case of the Residual Rings. This can take years if the kernel size is too big!' ) tmp = numpy.zeros(array.shape[::2]) for ii in tqdm(range(array.shape[1]), unit='images'): block = array[:, ii, :] # Compute: tmp += (block - ndimage.filters.median_filter(block, size=kernel)).sum(1) tmp /= array.shape[1] logger.print('Subtract residual rings.') for ii in tqdm(range(array.shape[1]), unit='images'): block = array[:, ii, :] block -= tmp array[:, ii, :] = block logger.print('Residual ring correcion applied.')
def PWLS(projections, volume, geometry, iterations): """ Simple implementation of the Penalized Weighted Least Squeares. Gives better results when photon starvation and metal artifacts are present in small parts of the volume. Needs more memory than SIRT! """ ss = settings preview = ss.preview bounds = ss.bounds logger.print('PWLS-PWLS-PWLS-PWLS...') # Residual norms: rnorms = [] # Progress bar: pbar = _pbar_start_(iterations, 'iterations') for ii in range(iterations): # L2 update: norm = pwls_update(projections, volume, geometry) if norm: rnorms.append(norm) # Apply bounds if bounds: numpy.clip(volume, a_min = bounds[0], a_max = bounds[1], out = volume) if preview: display.slice(volume, dim = 1, title = 'Preview') else: _pbar_update_(pbar) # Stop progress bar _pbar_close_(pbar) if rnorms: display.plot(rnorms, semilogy = True, title = 'Resudual L2')
def SIRT( projections, volume, geometry, iterations): """ Simultaneous Iterative Reconstruction Technique. """ ss = settings preview = ss.preview bounds = ss.bounds logger.print('Feeling SIRTy...') # Residual norms: rnorms = [] # Progress bar: pbar = _pbar_start_(iterations, 'iterations') for ii in range(iterations): # L2 update: norm = l2_update(projections, volume, geometry) if norm: rnorms.append(norm) # Apply bounds if bounds: numpy.clip(volume, a_min = bounds[0], a_max = bounds[1], out = volume) if preview: display.slice(volume, dim = 1, title = 'Preview') else: _pbar_update_(pbar) # Stop progress bar _pbar_close_(pbar) if rnorms: display.plot2d(rnorms, semilogy = True, title = 'Resudual L2')