def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): axis_size = recon.shape[0] ncore, slcs = mproc.get_ncore_slices(axis_size, ncore, nchunk) if len(slcs) < ncore: ncore = int(len(slcs)) # calculate how many real slices there are use_slcs = [] nreal = 0 for slc in slcs: _tomo = tomo[slc] _min = min(_tomo.shape) if _min > 0: nreal += 1 use_slcs.append(slc) # if less real slices than ncores, reduce number of cores if nreal < ncore: ncore = int(nreal) # check if ncore is limited by env variable pythreads = os.environ.get("TOMOPY_PYTHON_THREADS") if pythreads is not None and ncore > int(pythreads): print( "Warning! 'TOMOPY_PYTHON_THREADS' has been set to '{0}', which is less than" " specified ncore={1}. Limiting ncore to {0}...".format( pythreads, ncore)) ncore = int(pythreads) print("Reconstructing {} slice groups with {} master threads...".format( len(slcs), ncore)) # this is used internally to prevent oversubscription os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(ncore) if ncore == 1: for slc in use_slcs: # run in this thread (useful for debugging) algorithm(tomo[slc], center[slc], recon[slc], *args, **kwargs) else: # execute recon on ncore threads with cf.ThreadPoolExecutor(ncore) as e: for slc in use_slcs: e.submit(algorithm, tomo[slc], center[slc], recon[slc], *args, **kwargs) if pythreads is not None: # reset to default os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(pythreads) elif os.environ.get("TOMOPY_PYTHON_THREADS"): # if no default set, then del os.environ["TOMOPY_PYTHON_THREADS"] return recon
def remove_outlier1d(arr, dif, size=3, axis=0, ncore=None, out=None): """ Remove high intensity bright spots from an array, using a one-dimensional median filter along the specified axis. Dula: also removes dark spots Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Corrected array. """ arr = arr.astype(np.float32, copy=False) dif = np.float32(dif) tmp = np.empty_like(arr) other_axes = [i for i in range(arr.ndim) if i != axis] largest = np.argmax([arr.shape[i] for i in other_axes]) lar_axis = other_axes[largest] ncore, chnk_slices = mproc.get_ncore_slices(arr.shape[lar_axis], ncore=ncore) filt_size = [1] * arr.ndim filt_size[axis] = size with cf.ThreadPoolExecutor(ncore) as e: slc = [slice(None)] * arr.ndim for i in range(ncore): slc[lar_axis] = chnk_slices[i] e.submit(snf.median_filter, arr[slc], size=filt_size, output=tmp[slc], mode='mirror') with mproc.set_numexpr_threads(ncore): out = ne.evaluate('where(abs(arr-tmp)>=dif,tmp,arr)', out=out) return out
def remove_outlier(arr, dif, size=3, axis=0, ncore=None, out=None): """ Remove high intensity bright spots from a N-dimensional array by chunking along the specified dimension, and performing (N-1)-dimensional median filtering along the other dimensions. Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which to chunk. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Corrected array. """ tmp = np.empty_like(arr) ncore, chnk_slices = mproc.get_ncore_slices(arr.shape[axis], ncore=ncore) filt_size = [size] * arr.ndim filt_size[axis] = 1 with cf.ThreadPoolExecutor(ncore) as e: slc = [slice(None)] * arr.ndim for i in range(ncore): slc[axis] = chnk_slices[i] e.submit(scipy.ndimage.median_filter, arr[tuple(slc)], size=filt_size, output=tmp[tuple(slc)]) arr = dtype.as_float32(arr) tmp = dtype.as_float32(tmp) dif = np.float32(dif) with mproc.set_numexpr_threads(ncore): out = ne.evaluate('where(arr-tmp>=dif,tmp,arr)', out=out) return out
def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): axis_size = recon.shape[0] ncore, slcs = mproc.get_ncore_slices(axis_size, ncore, nchunk) if ncore == 1: for slc in slcs: # run in this thread (useful for debugging) algorithm(tomo[slc], center[slc], recon[slc], *args, **kwargs) else: # execute recon on ncore threads with cf.ThreadPoolExecutor(ncore) as e: for slc in slcs: e.submit(algorithm, tomo[slc], center[slc], recon[slc], *args, **kwargs) return recon
def remove_outlier1d(arr, dif, size=3, axis=0, ncore=None, out=None): """ Remove high intensity bright spots from an array, using a one-dimensional median filter along the specified axis. Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which median filtering is performed. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Corrected array. """ arr = dtype.as_float32(arr) dif = np.float32(dif) tmp = np.empty_like(arr) other_axes = [i for i in range(arr.ndim) if i != axis] largest = np.argmax([arr.shape[i] for i in other_axes]) lar_axis = other_axes[largest] ncore, chnk_slices = mproc.get_ncore_slices( arr.shape[lar_axis], ncore=ncore) filt_size = [1]*arr.ndim filt_size[axis] = size with cf.ThreadPoolExecutor(ncore) as e: slc = [slice(None)]*arr.ndim for i in range(ncore): slc[lar_axis] = chnk_slices[i] e.submit(filters.median_filter, arr[slc], size=filt_size, output=tmp[slc], mode='mirror') with mproc.set_numexpr_threads(ncore): out = ne.evaluate('where(arr-tmp>=dif,tmp,arr)', out=out) return out
def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): axis_size = recon.shape[0] ncore, slcs = mproc.get_ncore_slices(axis_size, ncore, nchunk) if len(slcs) < ncore: ncore = int(len(slcs)) # calculate how many real slices there are use_slcs = [] nreal = 0 for slc in slcs: _tomo = tomo[slc] _min = min(_tomo.shape) if _min > 0: nreal += 1 use_slcs.append(slc) # if less real slices than ncores, reduce number of cores if nreal < ncore: ncore = int(nreal) # check if ncore is limited by env variable pythreads = os.environ.get("TOMOPY_PYTHON_THREADS") if pythreads is not None and ncore > int(pythreads): print("Warning! 'TOMOPY_PYTHON_THREADS' has been set to '{0}', which is less than" " specified ncore={1}. Limiting ncore to {0}...".format(pythreads, ncore)) ncore = int(pythreads) print("Reconstructing {} slice groups with {} master threads...".format(len(slcs), ncore)) # this is used internally to prevent oversubscription os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(ncore) if ncore == 1: for slc in use_slcs: # run in this thread (useful for debugging) algorithm(tomo[slc], center[slc], recon[slc], *args, **kwargs) else: # execute recon on ncore threads with cf.ThreadPoolExecutor(ncore) as e: for slc in use_slcs: e.submit(algorithm, tomo[slc], center[slc], recon[slc], *args, **kwargs) if pythreads is not None: # reset to default os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(pythreads) elif os.environ.get("TOMOPY_PYTHON_THREADS"): # if no default set, then del os.environ["TOMOPY_PYTHON_THREADS"] return recon
def remove_outlier(arr, dif, size=3, axis=0, ncore=None, out=None): """ Remove high intensity bright spots from a N-dimensional array by chunking along the specified dimension, and performing (N-1)-dimensional median filtering along the other dimensions. Parameters ---------- arr : ndarray Input array. dif : float Expected difference value between outlier value and the median value of the array. size : int Size of the median filter. axis : int, optional Axis along which to chunk. ncore : int, optional Number of cores that will be assigned to jobs. out : ndarray, optional Output array for result. If same as arr, process will be done in-place. Returns ------- ndarray Corrected array. """ arr = dtype.as_float32(arr) dif = np.float32(dif) tmp = np.empty_like(arr) ncore, chnk_slices = mproc.get_ncore_slices(arr.shape[axis], ncore=ncore) filt_size = [size]*arr.ndim filt_size[axis] = 1 with cf.ThreadPoolExecutor(ncore) as e: slc = [slice(None)]*arr.ndim for i in range(ncore): slc[axis] = chnk_slices[i] e.submit(filters.median_filter, arr[tuple(slc)], size=filt_size, output=tmp[tuple(slc)]) with mproc.set_numexpr_threads(ncore): out = ne.evaluate('where(arr-tmp>=dif,tmp,arr)', out=out) return out
def astra(tomo, center, recon, theta, **kwargs): """ Reconstruct object using the ASTRA toolbox Extra options ---------- method : str ASTRA reconstruction method to use. num_iter : int, optional Number of algorithm iterations performed. proj_type : str, optional ASTRA projector type to use (see ASTRA docs for more information): - 'cuda' (for GPU algorithms) - 'line', 'linear', or 'strip' (for CPU algorithms) gpu_list : list, optional List of GPU indices to use extra_options : dict, optional Extra options for the ASTRA config (i.e. those in cfg['option']) Example ------- >>> import tomopy >>> obj = tomopy.shepp3d() # Generate an object. >>> ang = tomopy.angles(180) # Generate uniformly spaced tilt angles. >>> sim = tomopy.project(obj, ang) # Calculate projections. >>> >>> # Reconstruct object: >>> rec = tomopy.recon(sim, ang, algorithm=tomopy.astra, >>> options={'method':'SART', 'num_iter':10*180, >>> 'proj_type':'linear', >>> 'extra_options':{'MinConstraint':0}}) >>> >>> # Show 64th slice of the reconstructed object. >>> import pylab >>> pylab.imshow(rec[64], cmap='gray') >>> pylab.show() """ # Lazy import ASTRA import astra as astra_mod # Unpack arguments nslices = tomo.shape[0] num_gridx = kwargs['num_gridx'] num_gridy = kwargs['num_gridy'] opts = kwargs['options'] # Check options for o in needed_options['astra']: if o not in opts: logger.error("Option %s needed for ASTRA reconstruction." % (o, )) raise ValueError() for o in default_options['astra']: if o not in opts: opts[o] = default_options['astra'][o] niter = opts['num_iter'] proj_type = opts['proj_type'] # Create ASTRA geometries vol_geom = astra_mod.create_vol_geom((num_gridx, num_gridy)) # Number of GPUs to use if proj_type == 'cuda': if opts['gpu_list'] is not None: import concurrent.futures as cf gpu_list = opts['gpu_list'] ngpu = len(gpu_list) _, slcs = mproc.get_ncore_slices(nslices, ngpu) # execute recon on a thread per GPU with cf.ThreadPoolExecutor(ngpu) as e: for gpu, slc in zip(gpu_list, slcs): e.submit(astra_rec_cuda, tomo[slc], center[slc], recon[slc], theta, vol_geom, niter, proj_type, gpu, opts) else: astra_rec_cuda(tomo, center, recon, theta, vol_geom, niter, proj_type, None, opts) else: astra_rec_cpu(tomo, center, recon, theta, vol_geom, niter, proj_type, opts)
def astra(tomo, center, recon, theta, **kwargs): """ Reconstruct object using the ASTRA toolbox Extra options ---------- method : str ASTRA reconstruction method to use. num_iter : int, optional Number of algorithm iterations performed. proj_type : str, optional ASTRA projector type to use (see ASTRA docs for more information): - 'cuda' (for GPU algorithms) - 'line', 'linear', or 'strip' (for CPU algorithms) gpu_list : list, optional List of GPU indices to use extra_options : dict, optional Extra options for the ASTRA config (i.e. those in cfg['option']) Example ------- >>> import tomopy >>> obj = tomopy.shepp3d() # Generate an object. >>> ang = tomopy.angles(180) # Generate uniformly spaced tilt angles. >>> sim = tomopy.project(obj, ang) # Calculate projections. >>> >>> # Reconstruct object: >>> rec = tomopy.recon(sim, ang, algorithm=tomopy.astra, >>> options={'method':'SART', 'num_iter':10*180, >>> 'proj_type':'linear', >>> 'extra_options':{'MinConstraint':0}}) >>> >>> # Show 64th slice of the reconstructed object. >>> import pylab >>> pylab.imshow(rec[64], cmap='gray') >>> pylab.show() """ # Lazy import ASTRA import astra as astra_mod # Unpack arguments nslices = tomo.shape[0] num_gridx = kwargs['num_gridx'] num_gridy = kwargs['num_gridy'] opts = kwargs['options'] # Check options for o in needed_options['astra']: if o not in opts: logger.error("Option %s needed for ASTRA reconstruction." % (o,)) raise ValueError() for o in default_options['astra']: if o not in opts: opts[o] = default_options['astra'][o] niter = opts['num_iter'] proj_type = opts['proj_type'] # Create ASTRA geometries vol_geom = astra_mod.create_vol_geom((num_gridx, num_gridy)) # Number of GPUs to use if proj_type == 'cuda': if opts['gpu_list'] is not None: import concurrent.futures as cf gpu_list = opts['gpu_list'] ngpu = len(gpu_list) _, slcs = mproc.get_ncore_slices(nslices, ngpu) # execute recon on a thread per GPU with cf.ThreadPoolExecutor(ngpu) as e: for gpu, slc in zip(gpu_list, slcs): e.submit(astra_rec_cuda, tomo[slc], center[slc], recon[slc], theta, vol_geom, niter, proj_type, gpu, opts) else: astra_rec_cuda(tomo, center, recon, theta, vol_geom, niter, proj_type, None, opts) else: astra_rec_cpu(tomo, center, recon, theta, vol_geom, niter, proj_type, opts)
def _dist_recon(tomo, center, recon, algorithm, args, kwargs, ncore, nchunk): axis_size = recon.shape[0] ncore, slcs = mproc.get_ncore_slices(axis_size, ncore, nchunk) if len(slcs) < ncore: ncore = int(len(slcs)) # calculate how many real slices there are use_slcs = [] nreal = 0 for slc in slcs: _tomo = tomo[slc] _min = min(_tomo.shape) if _min > 0: nreal += 1 use_slcs.append(slc) # if less real slices than ncores, reduce number of cores if nreal < ncore: ncore = int(nreal) # check if ncore is limited by env variable pythreads = os.environ.get("TOMOPY_PYTHON_THREADS") if pythreads is not None and ncore > int(pythreads): warnings.warn( "The environment variable 'TOMOPY_PYTHON_THREADS' is limiting " "the requested ncore={1} to {0} cores. " "Set ncore <= 'TOMOPY_PYTHON_THREADS'.".format(pythreads, ncore)) ncore = int(pythreads) logger.info( "Reconstructing {} slice groups with {} master threads...".format( len(slcs), ncore)) # this is used internally to prevent oversubscription os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(ncore) if ncore == 1: for slc in use_slcs: # run in this thread (useful for debugging) algorithm(tomo[slc], center[slc], recon[slc], *args, **kwargs) else: # execute recon on ncore processes. Accelerated methods have internal # thread-pool and NVIDIA NPP library does not support simulatenously # leveraging multiple devices within the same process if "accelerated" in kwargs and kwargs["accelerated"]: futures = [] with cf.ProcessPoolExecutor(ncore) as e: for idx, slc in enumerate(use_slcs): futures.append( e.submit(_run_accel_algorithm, idx, algorithm, tomo[slc], center[slc], recon[slc], *args, **kwargs)) for f, slc in zip(futures, use_slcs): if f.exception() is not None: raise f.exception() recon[slc] = f.result() else: # execute recon on ncore threads with cf.ThreadPoolExecutor(ncore) as e: for slc in use_slcs: e.submit(algorithm, tomo[slc], center[slc], recon[slc], *args, **kwargs) if pythreads is not None: # reset to default os.environ["TOMOPY_PYTHON_THREADS"] = "{}".format(pythreads) elif os.environ.get("TOMOPY_PYTHON_THREADS"): # if no default set, then del os.environ["TOMOPY_PYTHON_THREADS"] return recon