def remove_stripe(data, params): log.info(' *** remove stripe:') if (params.remove_stripe_method == 'fw'): log.info(' *** *** fourier wavelet') data = tomopy.remove_stripe_fw(data, level=params.fw_level, wname=params.fw_filter, sigma=params.fw_sigma, pad=params.fw_pad) log.info(' *** *** *** fw level %d ' % params.fw_level) log.info(' *** *** *** fw wname %s ' % params.fw_filter) log.info(' *** *** *** fw sigma %f ' % params.fw_sigma) log.info(' *** *** *** fw pad %r ' % params.fw_pad) elif (params.remove_stripe_method == 'ti'): log.info(' *** *** titarenko') data = tomopy.remove_stripe_ti(data, nblock=params.ti_nblock, alpha=params.ti_alpha) log.info(' *** *** *** ti nblock %d ' % params.ti_nblock) log.info(' *** *** *** ti alpha %f ' % params.ti_alpha) elif (params.remove_stripe_method == 'sf'): log.info(' *** *** smoothing filter') data = tomopy.remove_stripe_sf(data, size == params.sf_size) log.info(' *** *** *** sf size %d ' % params.sf_size) elif (params.remove_stripe_method == 'none'): log.warning(' *** *** OFF') return data
def recon_slice(row_sino, theta, center_pos, sinogram_order=False, algorithm=None, init_recon=None, ncore=None, nchunk=None, **kwargs): t = time.time() internal_print(row_sino.shape) row_sino = row_sino.astype('float32') # row_sino = tomopy.normalize_bg(row_sino) # WARNING: normalize_bg can unpredicatably give bad results for some slices row_sino = tomopy.remove_stripe_ti(row_sino, alpha=4) rec = tomopy.recon(row_sino, theta, center=center_pos, sinogram_order=sinogram_order, algorithm=algorithm, init_recon=init_recon, ncore=ncore, nchunk=nchunk, filter_name='parzen', **kwargs) internal_print('recon: ' + str(time.time() - t)) return rec
def test_ti(self): # Prepare some test data prj = self.phantom_prj() # Prepare parameters (different from tomopy_cli or tomopy defaults) params = make_params() params.remove_stripe_method = 'ti' params.ti_alpha = 1.2 params.ti_nblock = 2 result = remove_stripe(np.copy(prj), params) # Compare results expected = tomopy.remove_stripe_ti(np.copy(prj), alpha=1.2, nblock=2) np.testing.assert_array_equal(result, expected)
def recon_slice(row_sino, center_pos, sinogram_order=False, algorithm=None, init_recon=None, ncore=None, nchunk=None, **kwargs): t = time.time() ang = tomopy.angles(row_sino.shape[0]) print(row_sino.shape) row_sino = row_sino.astype('float32') # row_sino = tomopy.normalize_bg(row_sino) # WARNING: normalize_bg can unpredicatably give bad results for some slices row_sino = tomopy.remove_stripe_ti(row_sino, alpha=4) rec = tomopy.recon(row_sino, ang, center=center_pos, sinogram_order=sinogram_order, algorithm=algorithm, init_recon=init_recon, ncore=ncore, nchunk=nchunk, **kwargs) print('recon: ' + str(time.time() - t)) return rec
def srxfftomo_recon(corrected_proj_tiff=None, proj=None, rot_center=None, recon_algorithm='art', recon_section=None, outpath=None, recon_outpath='recon', samplename=None, starting_angle=0, last_angle=180): ''' input needs to be either 1) corrected_proj_tiff, provided as a file path and name, e.g. '/home/xf05id1/localdata/TomoCommissioning/testsample_01/testsample_01_corrected.tiff' it is a stack of tiff generated by srxfftomo_correction, where background and stage round out have been corrected 2) projection numpy array, returned from srxfftomo_correction The 'proj' array assignment has priority. If it is None, proj was be read from corrected_proj_tiff recon_section is a list of upper and lower bounds for y range, e.g. [380, 420] ''' if proj is None: print('proj is not asigned, load corrected projection from:', corrected_proj_tiff) proj = tifffile.imread(corrected_proj_tiff) else: print('proj array is not None, use it as is') print('running reconstruction') if recon_section is not None: proj = proj[:, recon_section[0]:recon_section[1], :] theta = tomopy.angles(proj.shape[0], ang1=starting_angle, ang2=last_angle) print(proj.shape, theta.shape) proj = tomopy.remove_stripe_ti(proj) rec = tomopy.recon(proj, theta, center=rot_center, algorithm=recon_algorithm) print('saving reconstruction into') recon_outfile = outpath + '/' + samplename + '/' + recon_outpath + '/' + samplename + '_recon' tomopy.write_tiff_stack(rec, fname=recon_outfile) return rec
def reconstruct(self, center=None, mask_ratio=1, poisson_maxcount=None, remove_ring=True): if center is None: center = self.center if self.padded: ind = int((self.sinogram.shape[1] - self.shape[1]) / 2) center += ind nang = self.sinogram.shape[0] theta = tomopy.angles(nang, ang1=0, ang2=self.fin_angle) data = self.sinogram[:, np.newaxis, :] data = tomopy.remove_stripe_ti(data) # dxchange.write_tiff(np.squeeze(data), '/raid/home/mingdu/data/shirley/local_tomo/temp/raw', dtype='float32') if poisson_maxcount is not None: if self.is_mlogged: data = np.exp(-data) data = self.add_poisson_noise(data, max_count=poisson_maxcount) if self.is_mlogged: data = -np.log(data) m_value = np.mean(data[np.isfinite(data)]) data[np.isinf(data)] = m_value # dxchange.write_tiff(np.squeeze(data), '/raid/home/mingdu/data/shirley/local_tomo/temp/noise_sino', dtype='float32') rec = tomopy.recon(data, theta, center=center, algorithm='gridrec', filter_name='parzen') if self.padded: rec = rec[:, ind:ind + self.shape[1], ind:ind + self.shape[1]] if remove_ring: rec = tomopy.remove_ring(rec) rec = np.squeeze(rec) # if self.normalized_bg: # rec = rec * self.scaler self.recon_mask = tomopy.misc.corr._get_mask(rec.shape[0], rec.shape[1], mask_ratio) self.recon = rec
def preprocess_data(prj, flat, dark, FF_norm=flat_field_norm, remove_rings=remove_rings, FF_drift_corr=flat_field_drift_corr, downsapling=binning): if FF_norm: # dark-flat field correction prj = tomopy.normalize(prj, flat, dark) if FF_drift_corr: # flat field drift correction prj = tomopy.normalize_bg(prj, air=50) prj[prj <= 0] = 1 # check dark<data prj = tomopy.minus_log(prj) # -logarithm if remove_rings: # remove rings # prj = tomopy.remove_stripe_fw( # prj, level=7, wname='sym16', sigma=1, pad=True) prj = tomopy.remove_stripe_ti(prj, 2) if downsapling > 0: # binning prj = tomopy.downsample(prj, level=binning) prj = tomopy.downsample(prj, level=binning, axis=1) return prj
# Read APS 2-BM raw data. if (int(key) > 6): proj, flat, dark, theta = read_aps_2bm_custom(fname, sino=sino) else: proj, flat, dark, theta = dxchange.read_aps_2bm(fname, sino=sino) # zinger_removal proj = tomopy.misc.corr.remove_outlier(proj, zinger_level, size=15, axis=0) flat = tomopy.misc.corr.remove_outlier(flat, zinger_level_w, size=15, axis=0) # Flat-field correction of raw data. data = tomopy.normalize(proj, flat, dark, cutoff=1.4) # remove stripes #proj = tomopy.remove_stripe_fw(proj,level=5,wname='sym16',sigma=1,pad=True) proj = tomopy.remove_stripe_ti(proj,2) proj = tomopy.remove_stripe_sf(proj,10) # phase retrieval ##data = tomopy.prep.phase.retrieve_phase(data,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=8e-3,pad=True) # Find rotation center #rot_center = tomopy.find_center(proj, theta, init=rot_center, ind=start, tol=0.5) print(index, rot_center) proj = tomopy.minus_log(proj) # Reconstruct object using Gridrec algorithm. rec = tomopy.recon(proj, theta, center=rot_center, algorithm='gridrec') # Mask each reconstructed slice with a circle.
# Select the sinogram range to reconstruct. start = 600 end = 900 # Read the APS 1-ID raw data. proj, flat, dark = dxchange.read_aps_1id(fname, sino=(start, end)) print(proj.shape, flat.shape, dark.shape) # Set data collection angles as equally spaced between 0-180 degrees. theta = tomopy.angles(proj.shape[0], ang1=0.0, ang2=360.0) # Flat-field correction of raw data. ndata = tomopy.normalize(proj, flat, dark) ndata = tomopy.remove_stripe_ti(ndata) ndata = tomopy.remove_stripe_sf(ndata) # phase retrieval # ndata = tomopy.prep.phase.retrieve_phase(ndata, pixel_size=detector_pixel_size_x, dist=sample_detector_distance, energy=monochromator_energy, alpha=8e-3, pad=True) # Find rotation center. #rot_center = tomopy.find_center(ndata, theta, init=1024, ind=0, tol=0.5) rot_center = 576 binning = 0 ndata = tomopy.downsample(ndata, level=int(binning)) rot_center = rot_center/np.power(2, float(binning)) ndata = tomopy.minus_log(ndata)
#d.median_filter(size=medfilt_size, axis=0) # Apply a median filter in the projection plane data = tomopy.median_filter(data, size=medfilt_size, axis=0) #if remove_stripe1: d.stripe_removal(level=stripe_lvl, sigma=sig, wname=Wname) if remove_stripe1: data = tomopy.remove_stripe_fw(data, level=stripe_lvl, wname=Wname, sigma=sig) # z = 3 # eng = 31 # pxl = 0.325e-4 # rat = 5e-03 # rat = 1e-03 #d.phase_retrieval(dist=z, energy=eng, pixel_size=pxl, alpha=rat,padding=True) #data = tomopy.retrieve_phase(data, dist=z, energy=eng, pixel_size=pxl, alpha=rat,pad=True) #if remove_stripe2: d.stripe_removal2() if remove_stripe2: data = tomopy.remove_stripe_ti(data) #d.downsample2d(level=level) # apply binning on the data data = tomopy.downsample(data, level=level) # apply binning on the data theta = tomopy.angles(data.shape[0]) if 1: #if not best_center: d.optimize_center() if not best_center: calc_center = tomopy.find_center(data, theta, emission=False, ind=0, tol=0.3) else: #d.center=best_center/pow(2,level) # Manage the rotation center calc_center = best_center/pow(2,level) # Manage the rotation center #d.gridrec(ringWidth=RingW) # Run the reconstruction rec = tomopy.recon(data, theta, center=calc_center, algorithm='gridrec', emission=False) #d.apply_mask(ratio=1) rec = tomopy.circ_mask(rec, axis=0)
if sino_chunk_end > sino_end: break sino = (sino_chunk_start, sino_chunk_end) # Read APS 32-ID raw data. proj, flat, dark, theta = dxchange.read_aps_32id(fname, sino=sino) # Flat-field correction of raw data. proj = tomopy.normalize(proj, flat, dark) # remove stripes #proj = tomopy.remove_stripe_fw(proj,level=5,wname='sym16',sigma=1,pad=True) proj = tomopy.remove_stripe_ti(proj, 2) proj = tomopy.remove_stripe_sf(proj, 10) # phase retrieval #data = tomopy.prep.phase.retrieve_phase(data,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=8e-3,pad=True) # Find rotation center #rot_center = tomopy.find_center(proj, theta, init=rot_center, ind=start, tol=0.5) print(index, rot_center) proj = tomopy.minus_log(proj) # Reconstruct object using Gridrec algorithm. rec = tomopy.recon(proj, theta, center=rot_center,
def recon( filename, inputPath = './', outputPath = None, outputFilename = None, doOutliers1D = False, # outlier removal in 1d (along sinogram columns) outlier_diff1D = 750, # difference between good data and outlier data (outlier removal) outlier_size1D = 3, # radius around each pixel to look for outliers (outlier removal) doOutliers2D = False, # outlier removal, standard 2d on each projection outlier_diff2D = 750, # difference between good data and outlier data (outlier removal) outlier_size2D = 3, # radius around each pixel to look for outliers (outlier removal) doFWringremoval = True, # Fourier-wavelet ring removal doTIringremoval = False, # Titarenko ring removal doSFringremoval = False, # Smoothing filter ring removal ringSigma = 3, # damping parameter in Fourier space (Fourier-wavelet ring removal) ringLevel = 8, # number of wavelet transform levels (Fourier-wavelet ring removal) ringWavelet = 'db5', # type of wavelet filter (Fourier-wavelet ring removal) ringNBlock = 0, # used in Titarenko ring removal (doTIringremoval) ringAlpha = 1.5, # used in Titarenko ring removal (doTIringremoval) ringSize = 5, # used in smoothing filter ring removal (doSFringremoval) doPhaseRetrieval = False, # phase retrieval alphaReg = 0.0002, # smaller = smoother (used for phase retrieval) propagation_dist = 75, # sample-to-scintillator distance (phase retrieval) kev = 24, # energy level (phase retrieval) butterworth_cutoff = 0.25, #0.1 would be very smooth, 0.4 would be very grainy (reconstruction) butterworth_order = 2, # for reconstruction doTranslationCorrection = False, # correct for linear drift during scan xshift = 0, # undesired dx transation correction (from 0 degree to 180 degree proj) yshift = 0, # undesired dy transation correction (from 0 degree to 180 degree proj) doPolarRing = False, # ring removal Rarc=30, # min angle needed to be considered ring artifact (ring removal) Rmaxwidth=100, # max width of rings to be filtered (ring removal) Rtmax=3000.0, # max portion of image to filter (ring removal) Rthr=3000.0, # max value of offset due to ring artifact (ring removal) Rtmin=-3000.0, # min value of image to filter (ring removal) cor=None, # center of rotation (float). If not used then cor will be detected automatically corFunction = 'pc', # center of rotation function to use - can be 'pc', 'vo', or 'nm' voInd = None, # index of slice to use for cor search (vo) voSMin = -40, # min radius for searching in sinogram (vo) voSMax = 40, # max radius for searching in sinogram (vo) voSRad = 10, # search radius (vo) voStep = 0.5, # search step (vo) voRatio = 2.0, # ratio of field-of-view and object size (vo) voDrop = 20, # drop lines around vertical center of mask (vo) nmInd = None, # index of slice to use for cor search (nm) nmInit = None, # initial guess for center (nm) nmTol = 0.5, # desired sub-pixel accuracy (nm) nmMask = True, # if True, limits analysis to circular region (nm) nmRatio = 1.0, # ratio of radius of circular mask to edge of reconstructed image (nm) nmSinoOrder = False, # if True, analyzes in sinogram space. If False, analyzes in radiograph space use360to180 = False, # use 360 to 180 conversion doBilateralFilter = False, # if True, uses bilateral filter on image just before write step # NOTE: image will be converted to 8bit if it is not already bilateral_srad = 3, # spatial radius for bilateral filter (image will be converted to 8bit if not already) bilateral_rrad = 30, # range radius for bilateral filter (image will be converted to 8bit if not already) castTo8bit = False, # convert data to 8bit before writing cast8bit_min=-10, # min value if converting to 8bit cast8bit_max=30, # max value if converting to 8bit useNormalize_nf = False, # normalize based on background intensity (nf) chunk_proj = 100, # chunk size in projection direction chunk_sino = 100, # chunk size in sinogram direction npad = None, # amount to pad data before reconstruction projused = None, #should be slicing in projection dimension (start,end,step) sinoused = None, #should be sliceing in sinogram dimension (start,end,step). If first value is negative, it takes the number of slices from the second value in the middle of the stack. correcttilt = 0, #tilt dataset tiltcenter_slice = None, # tilt center (x direction) tiltcenter_det = None, # tilt center (y direction) angle_offset = 0, #this is the angle offset from our default (270) so that tomopy yields output in the same orientation as previous software (Octopus) anglelist = None, #if not set, will assume evenly spaced angles which will be calculated by the angular range and number of angles found in the file. if set to -1, will read individual angles from each image. alternatively, a list of angles can be passed. doBeamHardening = False, #turn on beam hardening correction, based on "Correction for beam hardening in computed tomography", Gabor Herman, 1979 Phys. Med. Biol. 24 81 BeamHardeningCoefficients = None, #6 values, tomo = a0 + a1*tomo + a2*tomo^2 + a3*tomo^3 + a4*tomo^4 + a5*tomo^5 projIgnoreList = None, #projections to be ignored in the reconstruction (for simplicity in the code, they will not be removed and will be processed as all other projections but will be set to zero absorption right before reconstruction. *args, **kwargs): start_time = time.time() print("Start {} at:".format(filename)+time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())) outputPath = inputPath if outputPath is None else outputPath outputFilename = filename if outputFilename is None else outputFilename outputFilename = outputFilename.replace('.h5','') tempfilenames = [outputPath+'tmp0.h5',outputPath+'tmp1.h5'] filenametowrite = outputPath+'/rec'+filename.strip(".h5")+'/'+outputFilename #filenametowrite = outputPath+'/rec'+filename+'/'+outputFilename print("cleaning up previous temp files", end="") for tmpfile in tempfilenames: try: os.remove(tmpfile) except OSError: pass print(", reading metadata") datafile = h5py.File(inputPath+filename, 'r') gdata = dict(dxchange.reader._find_dataset_group(datafile).attrs) pxsize = float(gdata['pxsize'])/10 # /10 to convert units from mm to cm numslices = int(gdata['nslices']) numangles = int(gdata['nangles']) angularrange = float(gdata['arange']) numrays = int(gdata['nrays']) npad = int(np.ceil(numrays * np.sqrt(2)) - numrays)//2 if npad is None else npad projused = (0,numangles-1,1) if projused is None else projused # ndark = int(gdata['num_dark_fields']) # ind_dark = list(range(0, ndark)) # group_dark = [numangles - 1] inter_bright = int(gdata['i0cycle']) nflat = int(gdata['num_bright_field']) ind_flat = list(range(0, nflat)) if inter_bright > 0: group_flat = list(range(0, numangles, inter_bright)) if group_flat[-1] != numangles - 1: group_flat.append(numangles - 1) elif inter_bright == 0: group_flat = [0, numangles - 1] else: group_flat = None ind_tomo = list(range(0, numangles)) floc_independent = dxchange.reader._map_loc(ind_tomo, group_flat) #figure out the angle list (a list of angles, one per projection image) dtemp = datafile[list(datafile.keys())[0]] fltemp = list(dtemp.keys()) firstangle = float(dtemp[fltemp[0]].attrs.get('rot_angle',0)) if anglelist is None: #the offset angle should offset from the angle of the first image, which is usually 0, but in the case of timbir data may not be. #we add the 270 to be inte same orientation as previous software used at bl832 angle_offset = 270 + angle_offset - firstangle anglelist = tomopy.angles(numangles, angle_offset, angle_offset-angularrange) elif anglelist==-1: anglelist = np.zeros(shape=numangles) for icount in range(0,numangles): anglelist[icount] = np.pi/180*(270 + angle_offset - float(dtemp[fltemp[icount]].attrs['rot_angle'])) #if projused is different than default, need to chnage numangles and angularrange #can't do useNormalize_nf and doOutliers2D at the same time, or doOutliers2D and doOutliers1D at the same time, b/c of the way we chunk, for now just disable that if useNormalize_nf==True and doOutliers2D==True: useNormalize_nf = False print("we cannot currently do useNormalize_nf and doOutliers2D at the same time, turning off useNormalize_nf") if doOutliers2D==True and doOutliers1D==True: doOutliers1D = False print("we cannot currently do doOutliers1D and doOutliers2D at the same time, turning off doOutliers1D") #figure out how user can pass to do central x number of slices, or set of slices dispersed throughout (without knowing a priori the value of numslices) if sinoused is None: sinoused = (0,numslices,1) elif sinoused[0]<0: sinoused=(int(np.floor(numslices/2.0)-np.ceil(sinoused[1]/2.0)),int(np.floor(numslices/2.0)+np.floor(sinoused[1]/2.0)),1) num_proj_per_chunk = np.minimum(chunk_proj,projused[1]-projused[0]) numprojchunks = (projused[1]-projused[0]-1)//num_proj_per_chunk+1 num_sino_per_chunk = np.minimum(chunk_sino,sinoused[1]-sinoused[0]) numsinochunks = (sinoused[1]-sinoused[0]-1)//num_sino_per_chunk+1 numprojused = (projused[1]-projused[0])//projused[2] numsinoused = (sinoused[1]-sinoused[0])//sinoused[2] BeamHardeningCoefficients = (0, 1, 0, 0, 0, .1) if BeamHardeningCoefficients is None else BeamHardeningCoefficients if cor is None: print("Detecting center of rotation", end="") if angularrange>300: lastcor = int(np.floor(numangles/2)-1) else: lastcor = numangles-1 #I don't want to see the warnings about the reader using a deprecated variable in dxchange with warnings.catch_warnings(): warnings.simplefilter("ignore") tomo, flat, dark, floc = dxchange.read_als_832h5(inputPath+filename,ind_tomo=(0,lastcor)) tomo = tomo.astype(np.float32) if useNormalize_nf: tomopy.normalize_nf(tomo, flat, dark, floc, out=tomo) else: tomopy.normalize(tomo, flat, dark, out=tomo) if corFunction == 'vo': # same reason for catching warnings as above with warnings.catch_warnings(): warnings.simplefilter("ignore") cor = tomopy.find_center_vo(tomo, ind=voInd, smin=voSMin, smax=voSMax, srad=voSRad, step=voStep, ratio=voRatio, drop=voDrop) elif corFunction == 'nm': cor = tomopy.find_center(tomo, tomopy.angles(numangles, angle_offset, angle_offset-angularrange), ind=nmInd, init=nmInit, tol=nmTol, mask=nmMask, ratio=nmRatio, sinogram_order=nmSinoOrder) elif corFunction == 'pc': cor = tomopy.find_center_pc(tomo[0], tomo[1], tol=0.25) else: raise ValueError("\'corFunction\' must be one of: [ pc, vo, nm ].") print(", {}".format(cor)) else: print("using user input center of {}".format(cor)) function_list = [] if doOutliers1D: function_list.append('remove_outlier1d') if doOutliers2D: function_list.append('remove_outlier2d') if useNormalize_nf: function_list.append('normalize_nf') else: function_list.append('normalize') function_list.append('minus_log') if doBeamHardening: function_list.append('beam_hardening') if doFWringremoval: function_list.append('remove_stripe_fw') if doTIringremoval: function_list.append('remove_stripe_ti') if doSFringremoval: function_list.append('remove_stripe_sf') if correcttilt: function_list.append('correcttilt') if use360to180: function_list.append('do_360_to_180') if doPhaseRetrieval: function_list.append('phase_retrieval') function_list.append('recon_mask') if doPolarRing: function_list.append('polar_ring') if castTo8bit: function_list.append('castTo8bit') if doBilateralFilter: function_list.append('bilateral_filter') function_list.append('write_output') # Figure out first direction to slice for func in function_list: if slice_dir[func] != 'both': axis = slice_dir[func] break done = False curfunc = 0 curtemp = 0 while True: # Loop over reading data in certain chunking direction if axis=='proj': niter = numprojchunks else: niter = numsinochunks for y in range(niter): # Loop over chunks print("{} chunk {} of {}".format(axis, y+1, niter)) if curfunc==0: with warnings.catch_warnings(): warnings.simplefilter("ignore") if axis=='proj': tomo, flat, dark, floc = dxchange.read_als_832h5(inputPath+filename,ind_tomo=range(y*num_proj_per_chunk+projused[0],np.minimum((y + 1)*num_proj_per_chunk+projused[0],numangles)),sino=(sinoused[0],sinoused[1], sinoused[2]) ) else: tomo, flat, dark, floc = dxchange.read_als_832h5(inputPath+filename,ind_tomo=range(projused[0],projused[1],projused[2]),sino=(y*num_sino_per_chunk+sinoused[0],np.minimum((y + 1)*num_sino_per_chunk+sinoused[0],numslices),1) ) else: if axis=='proj': start, end = y * num_proj_per_chunk, np.minimum((y + 1) * num_proj_per_chunk,numprojused) tomo = dxchange.reader.read_hdf5(tempfilenames[curtemp],'/tmp/tmp',slc=((start,end,1),(0,numslices,1),(0,numrays,1))) #read in intermediate file else: start, end = y * num_sino_per_chunk, np.minimum((y + 1) * num_sino_per_chunk,numsinoused) tomo = dxchange.reader.read_hdf5(tempfilenames[curtemp],'/tmp/tmp',slc=((0,numangles,1),(start,end,1),(0,numrays,1))) dofunc = curfunc keepvalues = None while True: # Loop over operations to do in current chunking direction func_name = function_list[dofunc] newaxis = slice_dir[func_name] if newaxis != 'both' and newaxis != axis: # We have to switch axis, so flush to disk if y==0: try: os.remove(tempfilenames[1-curtemp]) except OSError: pass appendaxis = 1 if axis=='sino' else 0 dxchange.writer.write_hdf5(tomo,fname=tempfilenames[1-curtemp],gname='tmp',dname='tmp',overwrite=False,appendaxis=appendaxis) #writing intermediate file... break print(func_name, end=" ") curtime = time.time() if func_name == 'remove_outlier1d': tomo = tomo.astype(np.float32,copy=False) remove_outlier1d(tomo, outlier_diff1D, size=outlier_size1D, out=tomo) if func_name == 'remove_outlier2d': tomo = tomo.astype(np.float32,copy=False) tomopy.remove_outlier(tomo, outlier_diff2D, size=outlier_size2D, axis=0, out=tomo) elif func_name == 'normalize_nf': tomo = tomo.astype(np.float32,copy=False) tomopy.normalize_nf(tomo, flat, dark, floc_independent, out=tomo) #use floc_independent b/c when you read file in proj chunks, you don't get the correct floc returned right now to use here. elif func_name == 'normalize': tomo = tomo.astype(np.float32,copy=False) tomopy.normalize(tomo, flat, dark, out=tomo) elif func_name == 'minus_log': mx = np.float32(0.00000000000000000001) ne.evaluate('where(tomo>mx, tomo, mx)', out=tomo) tomopy.minus_log(tomo, out=tomo) elif func_name == 'beam_hardening': loc_dict = {'a{}'.format(i):np.float32(val) for i,val in enumerate(BeamHardeningCoefficients)} tomo = ne.evaluate('a0 + a1*tomo + a2*tomo**2 + a3*tomo**3 + a4*tomo**4 + a5*tomo**5', local_dict=loc_dict, out=tomo) elif func_name == 'remove_stripe_fw': tomo = tomopy.remove_stripe_fw(tomo, sigma=ringSigma, level=ringLevel, pad=True, wname=ringWavelet) elif func_name == 'remove_stripe_ti': tomo = tomopy.remove_stripe_ti(tomo, nblock=ringNBlock, alpha=ringAlpha) elif func_name == 'remove_stripe_sf': tomo = tomopy.remove_stripe_sf(tomo, size=ringSize) elif func_name == 'correcttilt': if tiltcenter_slice is None: tiltcenter_slice = numslices/2. if tiltcenter_det is None: tiltcenter_det = tomo.shape[2]/2 new_center = tiltcenter_slice - 0.5 - sinoused[0] center_det = tiltcenter_det - 0.5 #add padding of 10 pixels, to be unpadded right after tilt correction. This makes the tilted image not have zeros at certain edges, which matters in cases where sample is bigger than the field of view. For the small amounts we are generally tilting the images, 10 pixels is sufficient. # tomo = tomopy.pad(tomo, 2, npad=10, mode='edge') # center_det = center_det + 10 cntr = (center_det, new_center) for b in range(tomo.shape[0]): tomo[b] = st.rotate(tomo[b], correcttilt, center=cntr, preserve_range=True, order=1, mode='edge', clip=True) #center=None means image is rotated around its center; order=1 is default, order of spline interpolation # tomo = tomo[:, :, 10:-10] elif func_name == 'do_360_to_180': # Keep values around for processing the next chunk in the list keepvalues = [angularrange, numangles, projused, num_proj_per_chunk, numprojchunks, numprojused, numrays, anglelist] #why -.5 on one and not on the other? if tomo.shape[0]%2>0: tomo = sino_360_to_180(tomo[0:-1,:,:], overlap=int(np.round((tomo.shape[2]-cor-.5))*2), rotation='right') angularrange = angularrange/2 - angularrange/(tomo.shape[0]-1) else: tomo = sino_360_to_180(tomo[:,:,:], overlap=int(np.round((tomo.shape[2]-cor))*2), rotation='right') angularrange = angularrange/2 numangles = int(numangles/2) projused = (0,numangles-1,1) num_proj_per_chunk = np.minimum(chunk_proj,projused[1]-projused[0]) numprojchunks = (projused[1]-projused[0]-1)//num_proj_per_chunk+1 numprojused = (projused[1]-projused[0])//projused[2] numrays = tomo.shape[2] anglelist = anglelist[:numangles] elif func_name == 'phase_retrieval': tomo = tomopy.retrieve_phase(tomo, pixel_size=pxsize, dist=propagation_dist, energy=kev, alpha=alphaReg, pad=True) elif func_name == 'translation_correction': tomo = linear_translation_correction(tomo,dx=xshift,dy=yshift,interpolation=False): elif func_name == 'recon_mask': tomo = tomopy.pad(tomo, 2, npad=npad, mode='edge') if projIgnoreList is not None: for badproj in projIgnoreList: tomo[badproj] = 0 rec = tomopy.recon(tomo, anglelist, center=cor+npad, algorithm='gridrec', filter_name='butterworth', filter_par=[butterworth_cutoff, butterworth_order]) rec = rec[:, npad:-npad, npad:-npad] rec /= pxsize # convert reconstructed voxel values from 1/pixel to 1/cm rec = tomopy.circ_mask(rec, 0) elif func_name == 'polar_ring': rec = np.ascontiguousarray(rec, dtype=np.float32) rec = tomopy.remove_ring(rec, theta_min=Rarc, rwidth=Rmaxwidth, thresh_max=Rtmax, thresh=Rthr, thresh_min=Rtmin,out=rec) elif func_name == 'castTo8bit': rec = convert8bit(rec, cast8bit_min, cast8bit_max) elif func_name == 'bilateral_filter': rec = pyF3D.run_BilateralFilter(rec, spatialRadius=bilateral_srad, rangeRadius=bilateral_rrad) elif func_name == 'write_output': dxchange.write_tiff_stack(rec, fname=filenametowrite, start=y*num_sino_per_chunk + sinoused[0]) print('(took {:.2f} seconds)'.format(time.time()-curtime)) dofunc+=1 if dofunc==len(function_list): break if y<niter-1 and keepvalues: # Reset original values for next chunk angularrange, numangles, projused, num_proj_per_chunk, numprojchunks, numprojused, numrays, anglelist = keepvalues curtemp = 1 - curtemp curfunc = dofunc if curfunc==len(function_list): break axis = slice_dir[function_list[curfunc]] print("cleaning up temp files") for tmpfile in tempfilenames: try: os.remove(tmpfile) except OSError: pass print("End Time: "+time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())) print('It took {:.3f} s to process {}'.format(time.time()-start_time,inputPath+filename))
def recon_hdf5(src_fanme, dest_folder, sino_range, sino_step, shift_grid, center_vec=None, center_eq=None, dtype='float32', algorithm='gridrec', tolerance=1, chunk_size=20, save_sino=False, sino_blur=None, flattened_radius=120, mode='180', test_mode=False, phase_retrieval=None, ring_removal=True, **kwargs): """ center_eq: a and b parameters in fitted center position equation center = a*slice + b. """ if not os.path.exists(dest_folder): try: os.mkdir(dest_folder) except: pass sino_ini = int(sino_range[0]) sino_end = int(sino_range[1]) sino_ls_all = np.arange(sino_ini, sino_end, sino_step, dtype='int') alloc_set = allocate_mpi_subsets(sino_ls_all.size, size, task_list=sino_ls_all) sino_ls = alloc_set[rank] # prepare metadata f = h5py.File(src_fanme) dset = f['exchange/data'] full_shape = dset.shape theta = tomopy.angles(full_shape[0]) if center_eq is not None: a, b = center_eq center_ls = sino_ls * a + b center_ls = np.round(center_ls) for iblock in range(int(sino_ls.size/chunk_size)+1): print('Beginning block {:d}.'.format(iblock)) t0 = time.time() istart = iblock*chunk_size iend = np.min([(iblock+1)*chunk_size, sino_ls.size]) fstart = sino_ls[istart] fend = sino_ls[iend] center = center_ls[istart:iend] data = dset[:, fstart:fend:sino_step, :] data[np.isnan(data)] = 0 data = data.astype('float32') data = tomopy.remove_stripe_ti(data, alpha=4) if sino_blur is not None: for i in range(data.shape[1]): data[:, i, :] = gaussian_filter(data[:, i, :], sino_blur) rec = tomopy.recon(data, theta, center=center, algorithm=algorithm, **kwargs) rec = tomopy.remove_ring(rec) rec = tomopy.remove_outlier(rec, tolerance) rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) for i in range(rec.shape[0]): slice = fstart + i*sino_step dxchange.write_tiff(rec[i, :, :], fname=os.path.join(dest_folder, 'recon/recon_{:05d}_{:05d}.tiff').format(slice, sino_ini)) if save_sino: dxchange.write_tiff(data[:, i, :], fname=os.path.join(dest_folder, 'sino/recon_{:05d}_{:d}.tiff').format(slice, int(center[i]))) iblock += 1 print('Block {:d} finished in {:.2f} s.'.format(iblock, time.time()-t0)) else: # divide chunks grid_bins = np.append(np.ceil(shift_grid[:, 0, 0]), full_shape[1]) chunks = [] center_ls = [] istart = 0 counter = 0 # irow should be 0 for slice 0 irow = np.searchsorted(grid_bins, sino_ls[0], side='right')-1 for i in range(sino_ls.size): counter += 1 sino_next = i+1 if i != sino_ls.size-1 else i if counter >= chunk_size or sino_ls[sino_next] >= grid_bins[irow+1] or sino_next == i: iend = i+1 chunks.append((istart, iend)) istart = iend center_ls.append(center_vec[irow]) if sino_ls[sino_next] >= grid_bins[irow+1]: irow += 1 counter = 0 # reconstruct chunks iblock = 1 for (istart, iend), center in izip(chunks, center_ls): print('Beginning block {:d}.'.format(iblock)) t0 = time.time() fstart = sino_ls[istart] fend = sino_ls[iend-1] print('Reading data...') data = dset[:, fstart:fend+1:sino_step, :] if mode == '360': overlap = 2 * (dset.shape[2] - center) data = tomosaic.morph.sino_360_to_180(data, overlap=overlap, rotation='right') theta = tomopy.angles(data.shape[0]) data[np.isnan(data)] = 0 data = data.astype('float32') if sino_blur is not None: for i in range(data.shape[1]): data[:, i, :] = gaussian_filter(data[:, i, :], sino_blur) if ring_removal: data = tomopy.remove_stripe_ti(data, alpha=4) if phase_retrieval: data = tomopy.retrieve_phase(data, kwargs['pixel_size'], kwargs['dist'], kwargs['energy'], kwargs['alpha']) rec0 = tomopy.recon(data, theta, center=center, algorithm=algorithm, **kwargs) rec = tomopy.remove_ring(np.copy(rec0)) cent = int((rec.shape[1]-1) / 2) xx, yy = np.meshgrid(np.arange(rec.shape[2]), np.arange(rec.shape[1])) mask0 = ((xx-cent)**2+(yy-cent)**2 <= flattened_radius**2) mask = np.zeros(rec.shape, dtype='bool') for i in range(mask.shape[0]): mask[i, :, :] = mask0 rec[mask] = (rec[mask] + rec0[mask])/2 else: rec = tomopy.recon(data, theta, center=center, algorithm=algorithm, **kwargs) rec = tomopy.remove_outlier(rec, tolerance) rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) for i in range(rec.shape[0]): slice = fstart + i*sino_step if test_mode: dxchange.write_tiff(rec[i, :, :], fname=os.path.join(dest_folder, 'recon/recon_{:05d}_{:d}.tiff').format(slice, center), dtype=dtype) else: dxchange.write_tiff(rec[i, :, :], fname=os.path.join(dest_folder, 'recon/recon_{:05d}.tiff').format(slice), dtype=dtype) if save_sino: dxchange.write_tiff(data[:, i, :], fname=os.path.join(dest_folder, 'sino/recon_{:05d}_{:d}.tiff').format(slice, center), dtype=dtype) print('Block {:d} finished in {:.2f} s.'.format(iblock, time.time()-t0)) iblock += 1 return
def reconstruct(h5fname, sino, rot_center, binning, algorithm='gridrec'): sample_detector_distance = 30 # Propagation distance of the wavefront in cm detector_pixel_size_x = 1.17e-4 # Detector pixel size in cm (5x: 1.17e-4, 2X: 2.93e-4) monochromator_energy = 25.74 # Energy of incident wave in keV alpha = 1e-02 # Phase retrieval coeff. zinger_level = 1000 # Zinger level for projections zinger_level_w = 1000 # Zinger level for white miss_angles = [500, 1050] # Read APS 32-BM raw data. proj, flat, dark, theta = dxchange.read_aps_32id(h5fname, sino=sino) print(theta) # Manage the missing angles: #proj_size = np.shape(proj) #theta = np.linspace(0,180,proj_size[0]) print(proj.shape, theta.shape) proj = np.concatenate( (proj[0:miss_angles[0], :, :], proj[miss_angles[1] + 1:-1, :, :]), axis=0) theta = np.concatenate( (theta[0:miss_angles[0]], theta[miss_angles[1] + 1:-1])) print(proj.shape, theta.shape) # zinger_removal #proj = tomopy.misc.corr.remove_outlier(proj, zinger_level, size=15, axis=0) #flat = tomopy.misc.corr.remove_outlier(flat, zinger_level_w, size=15, axis=0) # Flat-field correction of raw data. data = tomopy.normalize(proj, flat, dark, cutoff=0.8) # remove stripes # data = tomopy.remove_stripe_fw(data,level=7,wname='sym16',sigma=1,pad=True) data = tomopy.remove_stripe_ti(data, 2) # phase retrieval # data = tomopy.prep.phase.retrieve_phase(data,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=alpha,pad=True) print("Raw data: ", h5fname) print("Center: ", rot_center) data = tomopy.minus_log(data) data = tomopy.remove_nan(data, val=0.0) data = tomopy.remove_neg(data, val=0.00) data[np.where(data == np.inf)] = 0.00 rot_center = rot_center / np.power(2, float(binning)) data = tomopy.downsample(data, level=binning) data = tomopy.downsample(data, level=binning, axis=1) # Reconstruct object. if algorithm == 'sirtfbp': rec = rec_sirtfbp(data, theta, rot_center) else: rec = tomopy.recon(data, theta, center=rot_center, algorithm=algorithm, filter_name='parzen') print("Algorithm: ", algorithm) # Mask each reconstructed slice with a circle. ##rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) return rec
def fast_tomo_recon(argv): """ Reconstruct subset slices (sinograms) equally spaced within tomographic dataset """ logger = logging.getLogger('fast_tomopy.fast_tomo_recon') # Parse arguments passed to function parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, help='path to input raw ' 'dataset', required=True) parser.add_argument('-o', '--output-file', type=str, help='full path to h5 output ' 'file', default=os.path.join(os.getcwd(), "fast-tomopy.h5")) parser.add_argument('-sn', '--sino-num', type=int, help='Number of slices ' 'to reconstruct', default=5) parser.add_argument('-a', '--algorithm', type=str, help='Reconstruction' ' algorithm', default='gridrec', choices=['art', 'bart', 'fbp', 'gridrec', 'mlem', 'ospml_hybrid', 'ospml_quad', 'pml_hybrid', 'pml_quad', 'sirt']) parser.add_argument('-c', '--center', type=float, help='Center of rotation', default=None) parser.add_argument('-fn', '--filter-name', type=str, help='Name of filter' ' used for reconstruction', choices=['none', 'shepp', 'cosine', 'hann', 'hamming', 'ramlak', 'parzen', 'butterworth'], default='butterworth') parser.add_argument('-rr', '--ring-remove', type=str, help='Ring removal ' 'method', choices=['Octopus', 'Tomopy-FW', 'Tomopy-T'], default='Tomopy-FW') parser.add_argument('-lf', '--log-file', type=str, help='log file name', default='fast-tomopy.log') args = parser.parse_args() fh = logging.FileHandler(args.log_file) fh.setLevel(logging.INFO) fh.setFormatter(formatter) logger.addHandler(fh) if os.path.isdir(os.path.dirname(args.output_file)) is False: raise IOError(2, 'Directory of output file does not exist', args.output_file) # Read file metadata logger.info('Reading input file metadata') fdata, gdata = tomopy.read_als_832h5_metadata(args.input) proj_total = int(gdata['nangles']) last = proj_total - 1 sino_total = int(gdata['nslices']) ray_total = int(gdata['nrays']) px_size = float(gdata['pxsize'])/10 # cm # Set parameters for sinograms to read step = sino_total // (args.sino_num + 2) start = step end = step*(args.sino_num + 1) sino = (start, end, step) # Read full first and last projection to determine center of rotation if args.center is None: logger.info('Reading full first and last projection for COR') first_last, flats, darks, floc = tomopy.read_als_832h5(args.input, ind_tomo=(0, last)) first_last = tomopy.normalize_nf(first_last, flats, darks, floc) args.center = tomopy.find_center_pc(first_last[0, :, :], first_last[1, :, :], tol=0.1) logger.info('Detected center: %f', args.center) # Read and normalize raw sinograms logger.info('Reading raw data') tomo, flats, darks, floc = tomopy.read_als_832h5(args.input, sino=sino) logger.info('Normalizing raw data') tomo = tomopy.normalize_nf(tomo, flats, darks, floc) # Remove stripes from sinograms (remove rings) logger.info('Preprocessing normalized data') if args.ring_remove == 'Tomopy-FW': logger.info('Removing stripes from sinograms with %s', args.ring_remove) tomo = tomopy.remove_stripe_fw(tomo) elif args.ring_remove == 'Tomopy-T': logger.info('Removing stripes from sinograms with %s', args.ring_remove) tomo = tomopy.remove_stripe_ti(tomo) # Pad sinograms with edge values npad = int(np.ceil(ray_total*np.sqrt(2)) - ray_total)//2 tomo = tomopy.pad(tomo, 2, npad=npad, mode='edge') args.center += npad # account for padding filter_name = np.array(args.filter_name, dtype=(str, 16)) theta = tomopy.angles(tomo.shape[0], 270, 90) logger.info('Reconstructing normalized data') # Reconstruct sinograms rec = tomopy.recon(tomo, theta, center=args.center, emission=False, algorithm=args.algorithm, filter_name=filter_name) rec = tomopy.circ_mask(rec[:, npad:-npad, npad:-npad], 0) rec = rec/px_size # Remove rings from reconstruction if args.ring_remove == 'Octopus': logger.info('Removing rings from reconstructions with %s', args.ring_remove) thresh = float(gdata['ring_threshold']) thresh_max = float(gdata['upp_ring_value']) thresh_min = float(gdata['low_ring_value']) theta_min = int(gdata['max_arc_length']) rwidth = int(gdata['max_ring_size']) rec = tomopy.remove_rings(rec, center_x=args.center, thresh=thresh, thresh_max=thresh_max, thresh_min=thresh_min, theta_min=theta_min, rwidth=rwidth) # Write reconstruction data to new hdf5 file fdata['stage'] = 'fast-tomopy' fdata['stage_flow'] = '/raw/' + fdata['stage'] fdata['stage_version'] = 'fast-tomopy-0.1' # WHAT ABOUT uuid ????? Who asigns this??? del fdata['uuid'] # I'll get rid of it altogether then... gdata['Reconstruction_Type'] = 'tomopy-gridrec' gdata['ring_removal_method'] = args.ring_remove gdata['rfilter'] = args.filter_name logger.info('Writing reconstructed data to h5 file') write_als_832h5(rec, args.input, fdata, gdata, args.output_file, step) return
def recon_single(fname, center, dest_folder, sino_range=None, chunk_size=50, read_theta=True, pad_length=0, phase_retrieval=False, ring_removal=True, algorithm='gridrec', flattened_radius=40, crop=None, remove_padding=True, **kwargs): prj_shape = read_data_adaptive(fname, shape_only=True) if read_theta: theta = read_data_adaptive(fname, proj=(0, 1), return_theta=True) else: theta = tomopy.angles(prj_shape[0]) if sino_range is None: sino_st = 0 sino_end = prj_shape[1] sino_step = 1 else: sino_st, sino_end = sino_range[:2] if len(sino_range) == 3: sino_step = sino_range[-1] else: sino_step = 1 chunks = np.arange(0, sino_end, chunk_size * sino_step, dtype='int') for chunk_st in chunks: t0 = time.time() chunk_end = min(chunk_st + chunk_size * sino_step, prj_shape[1]) data, flt, drk = read_data_adaptive(fname, sino=(chunk_st, chunk_end, sino_step), return_theta=False) data = tomopy.normalize(data, flt, drk) data = data.astype('float32') data = tomopy.remove_stripe_ti(data, alpha=4) if phase_retrieval: data = tomopy.retrieve_phase(data, kwargs['pixel_size'], kwargs['dist'], kwargs['energy'], kwargs['alpha']) if pad_length != 0: data = pad_sinogram(data, pad_length) if ring_removal: data = tomopy.remove_stripe_ti(data, alpha=4) rec0 = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) rec = tomopy.remove_ring(np.copy(rec0)) cent = int((rec.shape[1] - 1) / 2) xx, yy = np.meshgrid(np.arange(rec.shape[2]), np.arange(rec.shape[1])) mask0 = ((xx - cent)**2 + (yy - cent)**2 <= flattened_radius**2) mask = np.zeros(rec.shape, dtype='bool') for i in range(mask.shape[0]): mask[i, :, :] = mask0 rec[mask] = (rec[mask] + rec0[mask]) / 2 else: rec = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) if pad_length != 0 and remove_padding: rec = rec[:, pad_length:pad_length + prj_shape[2], pad_length:pad_length + prj_shape[2]] rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) if crop is not None: crop = np.asarray(crop) rec = rec[:, crop[0, 0]:crop[1, 0], crop[0, 1]:crop[1, 1]] for i in range(rec.shape[0]): slice = chunk_st + sino_step * i internal_print('Saving slice {}'.format(slice)) dxchange.write_tiff( rec[i, :, :], fname=os.path.join(dest_folder, 'recon_{:05d}.tiff').format(slice), dtype='float32') internal_print('Block finished in {:.2f} s.'.format(time.time() - t0))
# Select the sinogram range to reconstruct. start = 600 end = 900 # Read the APS 1-ID raw data. proj, flat, dark = dxchange.read_aps_1id(fname, sino=(start, end)) print(proj.shape, flat.shape, dark.shape) # Set data collection angles as equally spaced between 0-180 degrees. theta = tomopy.angles(proj.shape[0], ang1=0.0, ang2=360.0) # Flat-field correction of raw data. ndata = tomopy.normalize(proj, flat, dark) ndata = tomopy.remove_stripe_ti(ndata) ndata = tomopy.remove_stripe_sf(ndata) # phase retrieval # ndata = tomopy.prep.phase.retrieve_phase(ndata, pixel_size=detector_pixel_size_x, dist=sample_detector_distance, energy=monochromator_energy, alpha=8e-3, pad=True) # Find rotation center. #rot_center = tomopy.find_center(ndata, theta, init=1024, ind=0, tol=0.5) rot_center = 576 binning = 0 ndata = tomopy.downsample(ndata, level=int(binning)) rot_center = rot_center / np.power(2, float(binning)) ndata = tomopy.minus_log(ndata)
prj = tomopy.minus_log(prj) print('\n** minus log applied!') if debug: print('## Debug: after minus log:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.misc.corr.remove_neg(prj, val=0.001) prj = tomopy.misc.corr.remove_nan(prj, val=0.001) prj[np.where(prj == np.inf)] = 0.001 if debug: print('## Debug: after cleaning bad values:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.remove_stripe_ti(prj,4) print('\n** Stripe removal done!') if debug: print('## Debug: after remove_stripe:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) # phase retrieval #data = tomopy.prep.phase.retrieve_phase(prj,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=alpha,pad=True) prj = tomopy.median_filter(prj,size=medfilt_size) print('\n** Median filter done!') if debug: print('## Debug: after nedian filter:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj)))
def write_center_360(file_name, output_path, slice_no, center_st, center_end, medfilt_size=1, level=0, debug=1): try: prj0, flat, dark, theta = dxchange.read_aps_32id(file_name, sino=(slice_no, slice_no + 1)) except: prj0, flat, dark = dxchange.read_aps_32id(file_name, sino=(slice_no, slice_no + 1)) f = h5py.File(file_name, "r") theta = tomopy.angles(f['exchange/data'].shape[0], ang1=0, ang2=360) if debug: print('## Debug: after reading data:') print('\n** Shape of the data:' + str(np.shape(prj0))) print('** Shape of theta:' + str(np.shape(theta))) print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj0), np.max(prj0))) prj0 = tomopy.normalize(prj0, flat, dark) print('\n** Flat field correction done!') for center in range(center_st, center_end): overlap = 2 * (f['exchange/data'].shape[2] - center) prj = np.copy(prj0) prj = sino_360_to_180(prj, overlap=overlap, rotation='right') print('\n** Sinogram converted!') if debug: print('## Debug: after normalization:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.minus_log(prj) print('\n** minus log applied!') if debug: print('## Debug: after minus log:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.misc.corr.remove_neg(prj, val=0.001) prj = tomopy.misc.corr.remove_nan(prj, val=0.001) prj[np.where(prj == np.inf)] = 0.001 if debug: print('## Debug: after cleaning bad values:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.remove_stripe_ti(prj, 4) print('\n** Stripe removal done!') if debug: print('## Debug: after remove_stripe:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) prj = tomopy.median_filter(prj, size=medfilt_size) print('\n** Median filter done!') if debug: print('## Debug: after nedian filter:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) if level > 0: prj = tomopy.downsample(prj, level=level) print('\n** Down sampling done!\n') if debug: print('## Debug: after down sampling:') print('\n** Min and max val in prj before recon: %0.5f, %0.3f' % (np.min(prj), np.max(prj))) rec = tomopy.recon(prj, theta, center=center, algorithm='gridrec') print('\nReconstruction done!\n') dxchange.write_tiff(rec, fname=os.path.join(output_path, '{0:.2f}'.format(center)), dtype='float32')
def preprocess_data(prj, flat, dark, FF_norm=flat_field_norm, remove_rings=remove_rings, medfilt_size=medfilt_size, FF_drift_corr=flat_field_drift_corr, downspling=binning): if FF_norm: # normalize the prj print('\n*** Applying flat field correction:') start_norm_time = time.time() prj = tomopy.normalize(prj, flat, dark) print(' done in %0.3f min' % ((time.time() - start_norm_time) / 60)) if FF_drift_corr: print('\n*** Applying flat field drift correction:') start_norm_bg_time = time.time() prj = tomopy.normalize_bg(prj, air=100) print(' done in %0.3f min' % ((time.time() - start_norm_bg_time) / 60)) # Applying -log print('\n*** Applying -log:') start_log_time = time.time() prj = tomopy.minus_log(prj) print(' done in %0.3f min' % ((time.time() - start_log_time) / 60)) prj = tomopy.misc.corr.remove_neg(prj, val=0.000) prj = tomopy.misc.corr.remove_nan(prj, val=0.000) prj[np.where(prj == np.inf)] = 0.000 # prj[np.where(prj == 0)] = 0.000 print('\n*** Min and max val in prj before recon: %0.3f, %0.3f' % (np.min(prj), np.max(prj))) if remove_rings: # remove ring artefacts tmp = prj[-1, :, :] # use to fixe the bug of remove_stripe_ti print('\n*** Applying ring removal algo:') start_ring_time = time.time() prj = tomopy.remove_stripe_ti(prj, 2) # prj = tomopy.remove_stripe_sf(prj,10); prj = tomopy.misc.corr.remove_neg(prj, val=0.000) # remove the neg values coming from remove_stripe_sf print(' done in %0.3f min' % ((time.time() - start_ring_time) / 60)) prj[-1, :, :] = tmp # fixe the bug of remove_stripe_ti if phase_retrieval: # phase retrieval prj = tomopy.prep.phase.retrieve_phase( prj, pixel_size=detector_pixel_size_x, dist=sample_detector_distance, energy=monochromator_energy, alpha=alpha, pad=True) # Filtering data with 2D median filter before downsampling and recon if medfilt_size > 1: start_filter_time = time.time() print('\n*** Applying median filter') #prj = tomopy.median_filter(prj,size=1) prj = ndimage.median_filter(prj, footprint=np.ones( (1, medfilt_size, medfilt_size))) print(' done in %0.3f min' % ((time.time() - start_filter_time) / 60)) # Downsampling data: if downspling > 0: print('\n** Applying downsampling') start_down_time = time.time() prj = tomopy.downsample(prj, level=binning) prj = tomopy.downsample(prj, level=binning, axis=1) print(' done in %0.3f min' % ((time.time() - start_down_time) / 60)) print('\n*** Shape of the data:' + str(np.shape(prj))) print(' Dimension of theta:' + str(np.shape(theta))) return prj
def find_center_discrete(source_folder, file_grid, shift_grid, row_range, search_range, search_step=1, slice=600, method='entropy', data_format='aps_32id', output_fname='center_pos.txt', read_theta=True): t00 = time.time() log = open(output_fname, 'a') row_st, row_end = row_range center_st, center_end = search_range row_list = range(row_st, row_end) sets = allocate_mpi_subsets(len(row_list), size, task_list=row_list) full_shape = read_data_adaptive(os.path.join(source_folder, file_grid[0, 0]), shape_only=True) if read_theta: _, _, _, theta = read_data_adaptive(os.path.join( source_folder, file_grid[0, 0]), proj=(0, 1)) else: theta = tomopy.angles(full_shape[0]) for row in sets[rank]: internal_print('Row {}'.format(row)) t0 = time.time() slice = int(shift_grid[row, 0, 0] + slice) # create sinogram try: sino = dxchange.read_tiff( os.path.join('center_temp', 'sino', 'sino_{:05d}.tiff'.format(slice))) sino = sino.reshape([sino.shape[0], 1, sino.shape[1]]) except: center_vec = [center_st] * file_grid.shape[0] center_vec = np.array(center_vec) sino, _ = create_row_sinogram(file_grid, shift_grid, source_folder, slice, center_vec, 0, blend_method='pyramid', data_format=data_format) dxchange.write_tiff( sino, os.path.join('center_temp', 'sino', 'sino_{:05d}.tiff'.format(slice))) sino = tomopy.remove_stripe_ti(sino, alpha=4) if method == 'manual' or 'entropy': write_center(sino, theta, dpath='center/{}'.format(row), cen_range=(center_st, center_end, search_step)) if method == 'entropy': center = minimum_entropy(os.path.join('center', str(row)), reliability_screening=True) if center is None: internal_print( 'Entropy result did not pass reliability screening. Switching to CNN...' ) rad = int(sino.shape[-1] * 0.3) rec_mid = int(sino.shape[-1] / 2) center = search_in_folder_dnn( os.path.join('center', str(row)), window=((rec_mid - rad, rec_mid - rad), (rec_mid + rad, rec_mid + rad))) internal_print('For {} center is {}. ({} s)'.format( row, center, time.time() - t0)) log.write('{} {}\n'.format(row, center)) elif method == 'vo': mid = sino.shape[2] / 2 smin = (center_st - mid) * 2 smax = (center_end - mid) * 2 center = find_center_vo(sino, smin=smin, smax=smax, step=search_step) internal_print('For {} center is {}. ({} s)'.format( row, center, time.time() - t0)) log.write('{} {}\n'.format(row, center)) log.close() internal_print('Total time: {} s.'.format(time.time() - t00))
def recon( filename, inputPath='./', outputPath=None, outputFilename=None, doOutliers1D=False, # outlier removal in 1d (along sinogram columns) outlier_diff1D=750, # difference between good data and outlier data (outlier removal) outlier_size1D=3, # radius around each pixel to look for outliers (outlier removal) doOutliers2D=False, # outlier removal, standard 2d on each projection outlier_diff2D=750, # difference between good data and outlier data (outlier removal) outlier_size2D=3, # radius around each pixel to look for outliers (outlier removal) doFWringremoval=True, # Fourier-wavelet ring removal doTIringremoval=False, # Titarenko ring removal doSFringremoval=False, # Smoothing filter ring removal ringSigma=3, # damping parameter in Fourier space (Fourier-wavelet ring removal) ringLevel=8, # number of wavelet transform levels (Fourier-wavelet ring removal) ringWavelet='db5', # type of wavelet filter (Fourier-wavelet ring removal) ringNBlock=0, # used in Titarenko ring removal (doTIringremoval) ringAlpha=1.5, # used in Titarenko ring removal (doTIringremoval) ringSize=5, # used in smoothing filter ring removal (doSFringremoval) doPhaseRetrieval=False, # phase retrieval alphaReg=0.0002, # smaller = smoother (used for phase retrieval) propagation_dist=75, # sample-to-scintillator distance (phase retrieval) kev=24, # energy level (phase retrieval) butterworth_cutoff=0.25, #0.1 would be very smooth, 0.4 would be very grainy (reconstruction) butterworth_order=2, # for reconstruction doPolarRing=False, # ring removal Rarc=30, # min angle needed to be considered ring artifact (ring removal) Rmaxwidth=100, # max width of rings to be filtered (ring removal) Rtmax=3000.0, # max portion of image to filter (ring removal) Rthr=3000.0, # max value of offset due to ring artifact (ring removal) Rtmin=-3000.0, # min value of image to filter (ring removal) cor=None, # center of rotation (float). If not used then cor will be detected automatically corFunction='pc', # center of rotation function to use - can be 'pc', 'vo', or 'nm' voInd=None, # index of slice to use for cor search (vo) voSMin=-40, # min radius for searching in sinogram (vo) voSMax=40, # max radius for searching in sinogram (vo) voSRad=10, # search radius (vo) voStep=0.5, # search step (vo) voRatio=2.0, # ratio of field-of-view and object size (vo) voDrop=20, # drop lines around vertical center of mask (vo) nmInd=None, # index of slice to use for cor search (nm) nmInit=None, # initial guess for center (nm) nmTol=0.5, # desired sub-pixel accuracy (nm) nmMask=True, # if True, limits analysis to circular region (nm) nmRatio=1.0, # ratio of radius of circular mask to edge of reconstructed image (nm) nmSinoOrder=False, # if True, analyzes in sinogram space. If False, analyzes in radiograph space use360to180=False, # use 360 to 180 conversion doBilateralFilter=False, # if True, uses bilateral filter on image just before write step # NOTE: image will be converted to 8bit if it is not already bilateral_srad=3, # spatial radius for bilateral filter (image will be converted to 8bit if not already) bilateral_rrad=30, # range radius for bilateral filter (image will be converted to 8bit if not already) castTo8bit=False, # convert data to 8bit before writing cast8bit_min=-10, # min value if converting to 8bit cast8bit_max=30, # max value if converting to 8bit useNormalize_nf=False, # normalize based on background intensity (nf) chunk_proj=100, # chunk size in projection direction chunk_sino=100, # chunk size in sinogram direction npad=None, # amount to pad data before reconstruction projused=None, #should be slicing in projection dimension (start,end,step) sinoused=None, #should be sliceing in sinogram dimension (start,end,step). If first value is negative, it takes the number of slices from the second value in the middle of the stack. correcttilt=0, #tilt dataset tiltcenter_slice=None, # tilt center (x direction) tiltcenter_det=None, # tilt center (y direction) angle_offset=0, #this is the angle offset from our default (270) so that tomopy yields output in the same orientation as previous software (Octopus) anglelist=None, #if not set, will assume evenly spaced angles which will be calculated by the angular range and number of angles found in the file. if set to -1, will read individual angles from each image. alternatively, a list of angles can be passed. doBeamHardening=False, #turn on beam hardening correction, based on "Correction for beam hardening in computed tomography", Gabor Herman, 1979 Phys. Med. Biol. 24 81 BeamHardeningCoefficients=None, #6 values, tomo = a0 + a1*tomo + a2*tomo^2 + a3*tomo^3 + a4*tomo^4 + a5*tomo^5 projIgnoreList=None, #projections to be ignored in the reconstruction (for simplicity in the code, they will not be removed and will be processed as all other projections but will be set to zero absorption right before reconstruction. *args, **kwargs): start_time = time.time() print("Start {} at:".format(filename) + time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())) outputPath = inputPath if outputPath is None else outputPath outputFilename = filename if outputFilename is None else outputFilename tempfilenames = [outputPath + 'tmp0.h5', outputPath + 'tmp1.h5'] filenametowrite = outputPath + '/rec' + filename.strip( ".h5") + '/' + outputFilename #filenametowrite = outputPath+'/rec'+filename+'/'+outputFilename print("cleaning up previous temp files", end="") for tmpfile in tempfilenames: try: os.remove(tmpfile) except OSError: pass print(", reading metadata") datafile = h5py.File(inputPath + filename, 'r') gdata = dict(dxchange.reader._find_dataset_group(datafile).attrs) pxsize = float(gdata['pxsize']) / 10 # /10 to convert unites from mm to cm numslices = int(gdata['nslices']) numangles = int(gdata['nangles']) angularrange = float(gdata['arange']) numrays = int(gdata['nrays']) npad = int(np.ceil(numrays * np.sqrt(2)) - numrays) // 2 if npad is None else npad projused = (0, numangles - 1, 1) if projused is None else projused # ndark = int(gdata['num_dark_fields']) # ind_dark = list(range(0, ndark)) # group_dark = [numangles - 1] inter_bright = int(gdata['i0cycle']) nflat = int(gdata['num_bright_field']) ind_flat = list(range(0, nflat)) if inter_bright > 0: group_flat = list(range(0, numangles, inter_bright)) if group_flat[-1] != numangles - 1: group_flat.append(numangles - 1) elif inter_bright == 0: group_flat = [0, numangles - 1] else: group_flat = None ind_tomo = list(range(0, numangles)) floc_independent = dxchange.reader._map_loc(ind_tomo, group_flat) #figure out the angle list (a list of angles, one per projection image) dtemp = datafile[list(datafile.keys())[0]] fltemp = list(dtemp.keys()) firstangle = float(dtemp[fltemp[0]].attrs.get('rot_angle', 0)) if anglelist is None: #the offset angle should offset from the angle of the first image, which is usually 0, but in the case of timbir data may not be. #we add the 270 to be inte same orientation as previous software used at bl832 angle_offset = 270 + angle_offset - firstangle anglelist = tomopy.angles(numangles, angle_offset, angle_offset - angularrange) elif anglelist == -1: anglelist = np.zeros(shape=numangles) for icount in range(0, numangles): anglelist[icount] = np.pi / 180 * (270 + angle_offset - float( dtemp[fltemp[icount]].attrs['rot_angle'])) #if projused is different than default, need to chnage numangles and angularrange #can't do useNormalize_nf and doOutliers2D at the same time, or doOutliers2D and doOutliers1D at the same time, b/c of the way we chunk, for now just disable that if useNormalize_nf == True and doOutliers2D == True: useNormalize_nf = False print( "we cannot currently do useNormalize_nf and doOutliers2D at the same time, turning off useNormalize_nf" ) if doOutliers2D == True and doOutliers1D == True: doOutliers1D = False print( "we cannot currently do doOutliers1D and doOutliers2D at the same time, turning off doOutliers1D" ) #figure out how user can pass to do central x number of slices, or set of slices dispersed throughout (without knowing a priori the value of numslices) if sinoused is None: sinoused = (0, numslices, 1) elif sinoused[0] < 0: sinoused = ( int(np.floor(numslices / 2.0) - np.ceil(sinoused[1] / 2.0)), int(np.floor(numslices / 2.0) + np.floor(sinoused[1] / 2.0)), 1) num_proj_per_chunk = np.minimum(chunk_proj, projused[1] - projused[0]) numprojchunks = (projused[1] - projused[0] - 1) // num_proj_per_chunk + 1 num_sino_per_chunk = np.minimum(chunk_sino, sinoused[1] - sinoused[0]) numsinochunks = (sinoused[1] - sinoused[0] - 1) // num_sino_per_chunk + 1 numprojused = (projused[1] - projused[0]) // projused[2] numsinoused = (sinoused[1] - sinoused[0]) // sinoused[2] BeamHardeningCoefficients = ( 0, 1, 0, 0, 0, .1) if BeamHardeningCoefficients is None else BeamHardeningCoefficients if cor is None: print("Detecting center of rotation", end="") if angularrange > 300: lastcor = int(np.floor(numangles / 2) - 1) else: lastcor = numangles - 1 #I don't want to see the warnings about the reader using a deprecated variable in dxchange with warnings.catch_warnings(): warnings.simplefilter("ignore") tomo, flat, dark, floc = dxchange.read_als_832h5( inputPath + filename, ind_tomo=(0, lastcor)) tomo = tomo.astype(np.float32) if useNormalize_nf: tomopy.normalize_nf(tomo, flat, dark, floc, out=tomo) else: tomopy.normalize(tomo, flat, dark, out=tomo) if corFunction == 'vo': # same reason for catching warnings as above with warnings.catch_warnings(): warnings.simplefilter("ignore") cor = tomopy.find_center_vo(tomo, ind=voInd, smin=voSMin, smax=voSMax, srad=voSRad, step=voStep, ratio=voRatio, drop=voDrop) elif corFunction == 'nm': cor = tomopy.find_center( tomo, tomopy.angles(numangles, angle_offset, angle_offset - angularrange), ind=nmInd, init=nmInit, tol=nmTol, mask=nmMask, ratio=nmRatio, sinogram_order=nmSinoOrder) elif corFunction == 'pc': cor = tomopy.find_center_pc(tomo[0], tomo[1], tol=0.25) else: raise ValueError("\'corFunction\' must be one of: [ pc, vo, nm ].") print(", {}".format(cor)) else: print("using user input center of {}".format(cor)) function_list = [] if doOutliers1D: function_list.append('remove_outlier1d') if doOutliers2D: function_list.append('remove_outlier2d') if useNormalize_nf: function_list.append('normalize_nf') else: function_list.append('normalize') function_list.append('minus_log') if doBeamHardening: function_list.append('beam_hardening') if doFWringremoval: function_list.append('remove_stripe_fw') if doTIringremoval: function_list.append('remove_stripe_ti') if doSFringremoval: function_list.append('remove_stripe_sf') if correcttilt: function_list.append('correcttilt') if use360to180: function_list.append('do_360_to_180') if doPhaseRetrieval: function_list.append('phase_retrieval') function_list.append('recon_mask') if doPolarRing: function_list.append('polar_ring') if castTo8bit: function_list.append('castTo8bit') if doBilateralFilter: function_list.append('bilateral_filter') function_list.append('write_output') # Figure out first direction to slice for func in function_list: if slice_dir[func] != 'both': axis = slice_dir[func] break done = False curfunc = 0 curtemp = 0 while True: # Loop over reading data in certain chunking direction if axis == 'proj': niter = numprojchunks else: niter = numsinochunks for y in range(niter): # Loop over chunks print("{} chunk {} of {}".format(axis, y + 1, niter)) if curfunc == 0: with warnings.catch_warnings(): warnings.simplefilter("ignore") if axis == 'proj': tomo, flat, dark, floc = dxchange.read_als_832h5( inputPath + filename, ind_tomo=range( y * num_proj_per_chunk + projused[0], np.minimum( (y + 1) * num_proj_per_chunk + projused[0], numangles)), sino=(sinoused[0], sinoused[1], sinoused[2])) else: tomo, flat, dark, floc = dxchange.read_als_832h5( inputPath + filename, ind_tomo=range(projused[0], projused[1], projused[2]), sino=(y * num_sino_per_chunk + sinoused[0], np.minimum((y + 1) * num_sino_per_chunk + sinoused[0], numslices), 1)) else: if axis == 'proj': start, end = y * num_proj_per_chunk, np.minimum( (y + 1) * num_proj_per_chunk, numprojused) tomo = dxchange.reader.read_hdf5( tempfilenames[curtemp], '/tmp/tmp', slc=((start, end, 1), (0, numslices, 1), (0, numrays, 1))) #read in intermediate file else: start, end = y * num_sino_per_chunk, np.minimum( (y + 1) * num_sino_per_chunk, numsinoused) tomo = dxchange.reader.read_hdf5(tempfilenames[curtemp], '/tmp/tmp', slc=((0, numangles, 1), (start, end, 1), (0, numrays, 1))) dofunc = curfunc keepvalues = None while True: # Loop over operations to do in current chunking direction func_name = function_list[dofunc] newaxis = slice_dir[func_name] if newaxis != 'both' and newaxis != axis: # We have to switch axis, so flush to disk if y == 0: try: os.remove(tempfilenames[1 - curtemp]) except OSError: pass appendaxis = 1 if axis == 'sino' else 0 dxchange.writer.write_hdf5( tomo, fname=tempfilenames[1 - curtemp], gname='tmp', dname='tmp', overwrite=False, appendaxis=appendaxis) #writing intermediate file... break print(func_name, end=" ") curtime = time.time() if func_name == 'remove_outlier1d': tomo = tomo.astype(np.float32, copy=False) remove_outlier1d(tomo, outlier_diff1D, size=outlier_size1D, out=tomo) if func_name == 'remove_outlier2d': tomo = tomo.astype(np.float32, copy=False) tomopy.remove_outlier(tomo, outlier_diff2D, size=outlier_size2D, axis=0, out=tomo) elif func_name == 'normalize_nf': tomo = tomo.astype(np.float32, copy=False) tomopy.normalize_nf( tomo, flat, dark, floc_independent, out=tomo ) #use floc_independent b/c when you read file in proj chunks, you don't get the correct floc returned right now to use here. elif func_name == 'normalize': tomo = tomo.astype(np.float32, copy=False) tomopy.normalize(tomo, flat, dark, out=tomo) elif func_name == 'minus_log': mx = np.float32(0.00000000000000000001) ne.evaluate('where(tomo>mx, tomo, mx)', out=tomo) tomopy.minus_log(tomo, out=tomo) elif func_name == 'beam_hardening': loc_dict = { 'a{}'.format(i): np.float32(val) for i, val in enumerate(BeamHardeningCoefficients) } tomo = ne.evaluate( 'a0 + a1*tomo + a2*tomo**2 + a3*tomo**3 + a4*tomo**4 + a5*tomo**5', local_dict=loc_dict, out=tomo) elif func_name == 'remove_stripe_fw': tomo = tomopy.remove_stripe_fw(tomo, sigma=ringSigma, level=ringLevel, pad=True, wname=ringWavelet) elif func_name == 'remove_stripe_ti': tomo = tomopy.remove_stripe_ti(tomo, nblock=ringNBlock, alpha=ringAlpha) elif func_name == 'remove_stripe_sf': tomo = tomopy.remove_stripe_sf(tomo, size=ringSize) elif func_name == 'correcttilt': if tiltcenter_slice is None: tiltcenter_slice = numslices / 2. if tiltcenter_det is None: tiltcenter_det = tomo.shape[2] / 2 new_center = tiltcenter_slice - 0.5 - sinoused[0] center_det = tiltcenter_det - 0.5 #add padding of 10 pixels, to be unpadded right after tilt correction. This makes the tilted image not have zeros at certain edges, which matters in cases where sample is bigger than the field of view. For the small amounts we are generally tilting the images, 10 pixels is sufficient. # tomo = tomopy.pad(tomo, 2, npad=10, mode='edge') # center_det = center_det + 10 cntr = (center_det, new_center) for b in range(tomo.shape[0]): tomo[b] = st.rotate( tomo[b], correcttilt, center=cntr, preserve_range=True, order=1, mode='edge', clip=True ) #center=None means image is rotated around its center; order=1 is default, order of spline interpolation # tomo = tomo[:, :, 10:-10] elif func_name == 'do_360_to_180': # Keep values around for processing the next chunk in the list keepvalues = [ angularrange, numangles, projused, num_proj_per_chunk, numprojchunks, numprojused, numrays, anglelist ] #why -.5 on one and not on the other? if tomo.shape[0] % 2 > 0: tomo = sino_360_to_180( tomo[0:-1, :, :], overlap=int( np.round((tomo.shape[2] - cor - .5)) * 2), rotation='right') angularrange = angularrange / 2 - angularrange / ( tomo.shape[0] - 1) else: tomo = sino_360_to_180( tomo[:, :, :], overlap=int(np.round((tomo.shape[2] - cor)) * 2), rotation='right') angularrange = angularrange / 2 numangles = int(numangles / 2) projused = (0, numangles - 1, 1) num_proj_per_chunk = np.minimum(chunk_proj, projused[1] - projused[0]) numprojchunks = (projused[1] - projused[0] - 1) // num_proj_per_chunk + 1 numprojused = (projused[1] - projused[0]) // projused[2] numrays = tomo.shape[2] anglelist = anglelist[:numangles] elif func_name == 'phase_retrieval': tomo = tomopy.retrieve_phase(tomo, pixel_size=pxsize, dist=propagation_dist, energy=kev, alpha=alphaReg, pad=True) elif func_name == 'recon_mask': tomo = tomopy.pad(tomo, 2, npad=npad, mode='edge') if projIgnoreList is not None: for badproj in projIgnoreList: tomo[badproj] = 0 rec = tomopy.recon( tomo, anglelist, center=cor + npad, algorithm='gridrec', filter_name='butterworth', filter_par=[butterworth_cutoff, butterworth_order]) rec = rec[:, npad:-npad, npad:-npad] rec /= pxsize # convert reconstructed voxel values from 1/pixel to 1/cm rec = tomopy.circ_mask(rec, 0) elif func_name == 'polar_ring': rec = np.ascontiguousarray(rec, dtype=np.float32) rec = tomopy.remove_ring(rec, theta_min=Rarc, rwidth=Rmaxwidth, thresh_max=Rtmax, thresh=Rthr, thresh_min=Rtmin, out=rec) elif func_name == 'castTo8bit': rec = convert8bit(rec, cast8bit_min, cast8bit_max) elif func_name == 'bilateral_filter': rec = pyF3D.run_BilateralFilter( rec, spatialRadius=bilateral_srad, rangeRadius=bilateral_rrad) elif func_name == 'write_output': dxchange.write_tiff_stack(rec, fname=filenametowrite, start=y * num_sino_per_chunk + sinoused[0]) print('(took {:.2f} seconds)'.format(time.time() - curtime)) dofunc += 1 if dofunc == len(function_list): break if y < niter - 1 and keepvalues: # Reset original values for next chunk angularrange, numangles, projused, num_proj_per_chunk, numprojchunks, numprojused, numrays, anglelist = keepvalues curtemp = 1 - curtemp curfunc = dofunc if curfunc == len(function_list): break axis = slice_dir[function_list[curfunc]] print("cleaning up temp files") for tmpfile in tempfilenames: try: os.remove(tmpfile) except OSError: pass print("End Time: " + time.strftime("%a, %d %b %Y %H:%M:%S +0000", time.localtime())) print('It took {:.3f} s to process {}'.format(time.time() - start_time, inputPath + filename))
def reconstruct(h5fname, sino, rot_center, binning, algorithm='gridrec'): sample_detector_distance = 30 # Propagation distance of the wavefront in cm detector_pixel_size_x = 1.17e-4 # Detector pixel size in cm (5x: 1.17e-4, 2X: 2.93e-4) monochromator_energy = 25.74 # Energy of incident wave in keV alpha = 1e-02 # Phase retrieval coeff. zinger_level = 1000 # Zinger level for projections zinger_level_w = 1000 # Zinger level for white miss_angles = [500,1050] # Read APS 32-BM raw data. proj, flat, dark, theta = dxchange.read_aps_32id(h5fname, sino=sino) print (theta) # Manage the missing angles: #proj_size = np.shape(proj) #theta = np.linspace(0,180,proj_size[0]) print(proj.shape, theta.shape) proj = np.concatenate((proj[0:miss_angles[0],:,:], proj[miss_angles[1]+1:-1,:,:]), axis=0) theta = np.concatenate((theta[0:miss_angles[0]], theta[miss_angles[1]+1:-1])) print(proj.shape, theta.shape) # zinger_removal #proj = tomopy.misc.corr.remove_outlier(proj, zinger_level, size=15, axis=0) #flat = tomopy.misc.corr.remove_outlier(flat, zinger_level_w, size=15, axis=0) # Flat-field correction of raw data. data = tomopy.normalize(proj, flat, dark, cutoff=0.8) # remove stripes # data = tomopy.remove_stripe_fw(data,level=7,wname='sym16',sigma=1,pad=True) data = tomopy.remove_stripe_ti(data, 2) # phase retrieval # data = tomopy.prep.phase.retrieve_phase(data,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=alpha,pad=True) print("Raw data: ", h5fname) print("Center: ", rot_center) data = tomopy.minus_log(data) data = tomopy.remove_nan(data, val=0.0) data = tomopy.remove_neg(data, val=0.00) data[np.where(data == np.inf)] = 0.00 rot_center = rot_center/np.power(2, float(binning)) data = tomopy.downsample(data, level=binning) data = tomopy.downsample(data, level=binning, axis=1) # Reconstruct object. if algorithm == 'sirtfbp': rec = rec_sirtfbp(data, theta, rot_center) else: rec = tomopy.recon(data, theta, center=rot_center, algorithm=algorithm, filter_name='parzen') print("Algorithm: ", algorithm) # Mask each reconstructed slice with a circle. ##rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) return rec
print("Size of projection is", proj.shape) # Flat-field correction of raw data. tic = time.time() print("Normalization....") proj = tomopy.normalize(proj, white2, dark) print("Done. %.4f sec" % (time.time() - tic)) # Set data collection angles as equally spaced between theta_start ~ theta_end (in degrees.) theta = tomopy.angles(proj.shape[0], ang1=th_start, ang2=th_end) # Ring removal. tic = time.time() print('Apply Ring removal filter...') #proj = tomopy.remove_stripe_fw(proj) # pretty effective, bg distortion proj = tomopy.remove_stripe_ti(proj) # pretty effective, bg distortion #proj = tomopy.remove_stripe_sf(proj) # less useful, but won't distort background print("Done. %.4f sec" % (time.time() - tic)) tic = time.time() print('Calculate minus_log of projection...') proj = tomopy.minus_log(proj) print("Done. %.4f sec" % (time.time() - tic)) print(proj.shape, proj.dtype, proj.max(), proj.min()) print('Create & Cleanup destination folder...') # create output folder if not exist if not os.path.exists(outpath): os.makedirs(outpath) else:
def fast_tomo_recon(argv): """ Reconstruct subset slices (sinograms) equally spaced within tomographic dataset """ logger = logging.getLogger('fast_tomopy.fast_tomo_recon') # Parse arguments passed to function parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, help='path to input raw ' 'dataset', required=True) parser.add_argument('-o', '--output-file', type=str, help='full path to h5 output ' 'file', default=os.path.join(os.getcwd(), "fast-tomopy.h5")) parser.add_argument('-sn', '--sino-num', type=int, help='Number of slices ' 'to reconstruct', default=5) parser.add_argument('-a', '--algorithm', type=str, help='Reconstruction' ' algorithm', default='gridrec', choices=[ 'art', 'bart', 'fbp', 'gridrec', 'mlem', 'ospml_hybrid', 'ospml_quad', 'pml_hybrid', 'pml_quad', 'sirt' ]) parser.add_argument('-c', '--center', type=float, help='Center of rotation', default=None) parser.add_argument('-fn', '--filter-name', type=str, help='Name of filter' ' used for reconstruction', choices=[ 'none', 'shepp', 'cosine', 'hann', 'hamming', 'ramlak', 'parzen', 'butterworth' ], default='butterworth') parser.add_argument('-rr', '--ring-remove', type=str, help='Ring removal ' 'method', choices=['Octopus', 'Tomopy-FW', 'Tomopy-T'], default='Tomopy-T') parser.add_argument('-lf', '--log-file', type=str, help='log file name', default='fast-tomopy.log') args = parser.parse_args() fh = logging.FileHandler(args.log_file) fh.setLevel(logging.INFO) fh.setFormatter(formatter) logger.addHandler(fh) if os.path.isdir(os.path.dirname(args.output_file)) is False: raise IOError(2, 'Directory of output file does not exist', args.output_file) # Read file metadata logger.info('Reading input file metadata') fdata, gdata = read_als_832h5_metadata(args.input) proj_total = int(gdata['nangles']) last = proj_total - 1 sino_total = int(gdata['nslices']) ray_total = int(gdata['nrays']) px_size = float(gdata['pxsize']) / 10 # cm # Set parameters for sinograms to read step = sino_total // (args.sino_num + 2) start = step end = step * (args.sino_num + 1) sino = (start, end, step) # Read full first and last projection to determine center of rotation if args.center is None: logger.info('Reading full first and last projection for COR') first_last, flats, darks, foobar = dx.read_als_832h5(args.input, ind_tomo=(0, last)) first_last = tomopy.normalize(first_last, flats, darks) args.center = tomopy.find_center_pc(first_last[0, :, :], first_last[1, :, :], tol=0.1) logger.info('Detected center: %f', args.center) # Read and normalize raw sinograms logger.info('Reading raw data') tomo, flats, darks, foobar = dx.read_als_832h5(args.input, sino=sino) logger.info('Normalizing raw data') tomo = tomopy.normalize(tomo, flats, darks) tomo = tomopy.minus_log(tomo) # Remove stripes from sinograms (remove rings) logger.info('Preprocessing normalized data') if args.ring_remove == 'Tomopy-FW': logger.info('Removing stripes from sinograms with %s', args.ring_remove) tomo = tomopy.remove_stripe_fw(tomo) elif args.ring_remove == 'Tomopy-T': logger.info('Removing stripes from sinograms with %s', args.ring_remove) tomo = tomopy.remove_stripe_ti(tomo) # Pad sinograms with edge values npad = int(np.ceil(ray_total * np.sqrt(2)) - ray_total) // 2 tomo = tomopy.pad(tomo, 2, npad=npad, mode='edge') args.center += npad # account for padding filter_name = np.array(args.filter_name, dtype=(str, 16)) theta = tomopy.angles(proj_total, 270, 90) logger.info('Reconstructing normalized data') # Reconstruct sinograms # rec = tomopy.minus_log(tomo, out=tomo) rec = tomopy.recon(tomo, theta, center=args.center, algorithm=args.algorithm, filter_name=filter_name) rec = tomopy.circ_mask(rec[:, npad:-npad, npad:-npad], 0) rec = rec / px_size # Remove rings from reconstruction if args.ring_remove == 'Octopus': logger.info('Removing rings from reconstructions with %s', args.ring_remove) thresh = float(gdata['ring_threshold']) thresh_max = float(gdata['upp_ring_value']) thresh_min = float(gdata['low_ring_value']) theta_min = int(gdata['max_arc_length']) rwidth = int(gdata['max_ring_size']) rec = tomopy.remove_rings(rec, center_x=args.center, thresh=thresh, thresh_max=thresh_max, thresh_min=thresh_min, theta_min=theta_min, rwidth=rwidth) # Write reconstruction data to new hdf5 file fdata['stage'] = 'fast-tomopy' fdata['stage_flow'] = '/raw/' + fdata['stage'] fdata['stage_version'] = 'fast-tomopy-0.1' # Generate a new uuid based on host ID and current time fdata['uuid'] = str(uuid.uuid1()) gdata['Reconstruction_Type'] = 'tomopy-gridrec' gdata['ring_removal_method'] = args.ring_remove gdata['rfilter'] = args.filter_name logger.info('Writing reconstructed data to h5 file') write_als_832h5(rec, args.input, fdata, gdata, args.output_file, step) return
def evaluate(self): self.tomo.value = tomopy.remove_stripe_ti(self.tomo.value, nblock=self.nblock.value, alpha=self.alpha.value, ncore=self.ncore.value, nchunk=self.nchunk.value)
def recon_hdf5(src_fanme, dest_folder, sino_range, sino_step, shift_grid, center_vec=None, center_eq=None, dtype='float32', algorithm='gridrec', tolerance=1, chunk_size=20, save_sino=False, sino_blur=None, flattened_radius=120, mode='180', test_mode=False, phase_retrieval=None, ring_removal=True, crop=None, num_iter=None, pad_length=0, read_theta=True, **kwargs): """ center_eq: a and b parameters in fitted center position equation center = a*slice + b. """ if not os.path.exists(dest_folder): try: os.mkdir(dest_folder) except: pass sino_ini = int(sino_range[0]) sino_end = int(sino_range[1]) sino_ls_all = np.arange(sino_ini, sino_end, sino_step, dtype='int') alloc_set = allocate_mpi_subsets(sino_ls_all.size, size, task_list=sino_ls_all) sino_ls = alloc_set[rank] # prepare metadata f = h5py.File(src_fanme) dset = f['exchange/data'] full_shape = dset.shape if read_theta: _, _, _, theta = read_data_adaptive(src_fanme, proj=(0, 1)) else: theta = tomopy.angles(full_shape[0]) if center_eq is not None: a, b = center_eq center_ls = sino_ls_all * a + b center_ls = np.round(center_ls) for iblock in range(int(sino_ls.size / chunk_size) + 1): internal_print('Beginning block {:d}.'.format(iblock)) t0 = time.time() istart = iblock * chunk_size iend = np.min([(iblock + 1) * chunk_size, sino_ls.size]) sub_sino_ls = sino_ls[istart:iend - 1] center = np.take(center_ls, sub_sino_ls) data = np.zeros([dset.shape[0], len(sub_sino_ls), dset.shape[2]]) for ind, i in enumerate(sub_sino_ls): data[:, ind, :] = dset[:, i, :] data[np.isnan(data)] = 0 data = data.astype('float32') data = tomopy.remove_stripe_ti(data, alpha=4) if sino_blur is not None: for i in range(data.shape[1]): data[:, i, :] = gaussian_filter(data[:, i, :], sino_blur) if phase_retrieval: data = tomopy.retrieve_phase(data, kwargs['pixel_size'], kwargs['dist'], kwargs['energy'], kwargs['alpha']) if pad_length != 0: data = pad_sinogram(data, pad_length) data = tomopy.remove_stripe_ti(data, alpha=4) if ring_removal: rec0 = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) rec = tomopy.remove_ring(np.copy(rec0)) cent = int((rec.shape[1] - 1) / 2) xx, yy = np.meshgrid(np.arange(rec.shape[2]), np.arange(rec.shape[1])) mask0 = ((xx - cent)**2 + (yy - cent)**2 <= flattened_radius**2) mask = np.zeros(rec.shape, dtype='bool') for i in range(mask.shape[0]): mask[i, :, :] = mask0 rec[mask] = (rec[mask] + rec0[mask]) / 2 else: rec = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) if pad_length != 0: rec = rec[:, pad_length:pad_length + full_shape[2], pad_length:pad_length + full_shape[2]] rec = tomopy.remove_outlier(rec, tolerance) rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) if crop is not None: crop = np.asarray(crop) rec = rec[:, crop[0, 0]:crop[1, 0], crop[0, 1]:crop[1, 1]] for i in range(rec.shape[0]): slice = sub_sino_ls[i] dxchange.write_tiff( rec[i, :, :], fname=os.path.join( dest_folder, 'recon/recon_{:05d}.tiff').format(slice)) if save_sino: dxchange.write_tiff( data[:, i, :], fname=os.path.join( dest_folder, 'sino/recon_{:05d}_{:d}.tiff').format( slice, int(center[i]))) iblock += 1 internal_print('Block {:d} finished in {:.2f} s.'.format( iblock, time.time() - t0)) else: # divide chunks grid_bins = np.append(np.ceil(shift_grid[:, 0, 0]), full_shape[1]) chunks = [] center_ls = [] istart = 0 counter = 0 # irow should be 0 for slice 0 irow = np.searchsorted(grid_bins, sino_ls[0], side='right') - 1 for i in range(sino_ls.size): counter += 1 sino_next = i + 1 if i != sino_ls.size - 1 else i if counter >= chunk_size or sino_ls[sino_next] >= grid_bins[ irow + 1] or sino_next == i: iend = i + 1 chunks.append((istart, iend)) istart = iend center_ls.append(center_vec[irow]) if sino_ls[sino_next] >= grid_bins[irow + 1]: irow += 1 counter = 0 # reconstruct chunks iblock = 1 for (istart, iend), center in zip(chunks, center_ls): internal_print('Beginning block {:d}.'.format(iblock)) t0 = time.time() internal_print('Reading data...') sub_sino_ls = sino_ls[istart:iend] data = np.zeros([dset.shape[0], len(sub_sino_ls), dset.shape[2]]) for ind, i in enumerate(sub_sino_ls): data[:, ind, :] = dset[:, i, :] if mode == '360': overlap = 2 * (dset.shape[2] - center) data = tomosaic.sino_360_to_180(data, overlap=overlap, rotation='right') theta = tomopy.angles(data.shape[0]) data[np.isnan(data)] = 0 data = data.astype('float32') if sino_blur is not None: for i in range(data.shape[1]): data[:, i, :] = gaussian_filter(data[:, i, :], sino_blur) if phase_retrieval: data = tomopy.retrieve_phase(data, kwargs['pixel_size'], kwargs['dist'], kwargs['energy'], kwargs['alpha']) if pad_length != 0: data = pad_sinogram(data, pad_length) data = tomopy.remove_stripe_ti(data, alpha=4) if ring_removal: rec0 = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) rec = tomopy.remove_ring(np.copy(rec0)) cent = int((rec.shape[1] - 1) / 2) xx, yy = np.meshgrid(np.arange(rec.shape[2]), np.arange(rec.shape[1])) mask0 = ((xx - cent)**2 + (yy - cent)**2 <= flattened_radius**2) mask = np.zeros(rec.shape, dtype='bool') for i in range(mask.shape[0]): mask[i, :, :] = mask0 rec[mask] = (rec[mask] + rec0[mask]) / 2 else: rec = tomopy.recon(data, theta, center=center + pad_length, algorithm=algorithm, **kwargs) if pad_length != 0: rec = rec[:, pad_length:pad_length + full_shape[2], pad_length:pad_length + full_shape[2]] rec = tomopy.remove_outlier(rec, tolerance) rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) if crop is not None: crop = np.asarray(crop) rec = rec[:, crop[0, 0]:crop[1, 0], crop[0, 1]:crop[1, 1]] for i in range(rec.shape[0]): slice = sub_sino_ls[i] if test_mode: dxchange.write_tiff( rec[i, :, :], fname=os.path.join( dest_folder, 'recon/recon_{:05d}_{:d}.tiff').format( slice, center), dtype=dtype) else: dxchange.write_tiff( rec[i, :, :], fname=os.path.join( dest_folder, 'recon/recon_{:05d}.tiff').format(slice), dtype=dtype) if save_sino: dxchange.write_tiff( data[:, i, :], fname=os.path.join( dest_folder, 'sino/recon_{:05d}_{:d}.tiff').format( slice, center), dtype=dtype) internal_print('Block {:d} finished in {:.2f} s.'.format( iblock, time.time() - t0)) iblock += 1 return
def fast_tomo_recon(argv): """ Reconstruct subset slices (sinograms) equally spaced within tomographic dataset """ logger = logging.getLogger("fast_tomopy.fast_tomo_recon") # Parse arguments passed to function parser = argparse.ArgumentParser() parser.add_argument("-i", "--input", type=str, help="path to input raw " "dataset", required=True) parser.add_argument( "-o", "--output-file", type=str, help="full path to h5 output " "file", default=os.path.join(os.getcwd(), "fast-tomopy.h5"), ) parser.add_argument("-sn", "--sino-num", type=int, help="Number of slices " "to reconstruct", default=5) parser.add_argument( "-a", "--algorithm", type=str, help="Reconstruction" " algorithm", default="gridrec", choices=[ "art", "bart", "fbp", "gridrec", "mlem", "ospml_hybrid", "ospml_quad", "pml_hybrid", "pml_quad", "sirt", ], ) parser.add_argument("-c", "--center", type=float, help="Center of rotation", default=None) parser.add_argument( "-fn", "--filter-name", type=str, help="Name of filter" " used for reconstruction", choices=["none", "shepp", "cosine", "hann", "hamming", "ramlak", "parzen", "butterworth"], default="butterworth", ) parser.add_argument( "-rr", "--ring-remove", type=str, help="Ring removal " "method", choices=["Octopus", "Tomopy-FW", "Tomopy-T"], default="Tomopy-T", ) parser.add_argument("-lf", "--log-file", type=str, help="log file name", default="fast-tomopy.log") args = parser.parse_args() fh = logging.FileHandler(args.log_file) fh.setLevel(logging.INFO) fh.setFormatter(formatter) logger.addHandler(fh) if os.path.isdir(os.path.dirname(args.output_file)) is False: raise IOError(2, "Directory of output file does not exist", args.output_file) # Read file metadata logger.info("Reading input file metadata") fdata, gdata = read_als_832h5_metadata(args.input) proj_total = int(gdata["nangles"]) last = proj_total - 1 sino_total = int(gdata["nslices"]) ray_total = int(gdata["nrays"]) px_size = float(gdata["pxsize"]) / 10 # cm # Set parameters for sinograms to read step = sino_total // (args.sino_num + 2) start = step end = step * (args.sino_num + 1) sino = (start, end, step) # Read full first and last projection to determine center of rotation if args.center is None: logger.info("Reading full first and last projection for COR") first_last, flats, darks, floc = tomopy.read_als_832h5(args.input, ind_tomo=(0, last)) first_last = tomopy.normalize(first_last, flats, darks) args.center = tomopy.find_center_pc(first_last[0, :, :], first_last[1, :, :], tol=0.1) logger.info("Detected center: %f", args.center) # Read and normalize raw sinograms logger.info("Reading raw data") tomo, flats, darks, floc = tomopy.read_als_832h5(args.input, sino=sino) logger.info("Normalizing raw data") tomo = tomopy.normalize_nf(tomo, flats, darks, floc) # Remove stripes from sinograms (remove rings) logger.info("Preprocessing normalized data") if args.ring_remove == "Tomopy-FW": logger.info("Removing stripes from sinograms with %s", args.ring_remove) tomo = tomopy.remove_stripe_fw(tomo) elif args.ring_remove == "Tomopy-T": logger.info("Removing stripes from sinograms with %s", args.ring_remove) tomo = tomopy.remove_stripe_ti(tomo) # Pad sinograms with edge values npad = int(np.ceil(ray_total * np.sqrt(2)) - ray_total) // 2 tomo = tomopy.pad(tomo, 2, npad=npad, mode="edge") args.center += npad # account for padding filter_name = np.array(args.filter_name, dtype=(str, 16)) theta = tomopy.angles(proj_total, 270, 90) logger.info("Reconstructing normalized data") # Reconstruct sinograms # rec = tomopy.minus_log(tomo, out=tomo) rec = tomopy.recon( tomo, theta, center=args.center, emission=False, algorithm=args.algorithm, filter_name=filter_name ) rec = tomopy.circ_mask(rec[:, npad:-npad, npad:-npad], 0) rec = rec / px_size # Remove rings from reconstruction if args.ring_remove == "Octopus": logger.info("Removing rings from reconstructions with %s", args.ring_remove) thresh = float(gdata["ring_threshold"]) thresh_max = float(gdata["upp_ring_value"]) thresh_min = float(gdata["low_ring_value"]) theta_min = int(gdata["max_arc_length"]) rwidth = int(gdata["max_ring_size"]) rec = tomopy.remove_rings( rec, center_x=args.center, thresh=thresh, thresh_max=thresh_max, thresh_min=thresh_min, theta_min=theta_min, rwidth=rwidth, ) # Write reconstruction data to new hdf5 file fdata["stage"] = "fast-tomopy" fdata["stage_flow"] = "/raw/" + fdata["stage"] fdata["stage_version"] = "fast-tomopy-0.1" # Generate a new uuid based on host ID and current time fdata["uuid"] = str(uuid.uuid1()) gdata["Reconstruction_Type"] = "tomopy-gridrec" gdata["ring_removal_method"] = args.ring_remove gdata["rfilter"] = args.filter_name logger.info("Writing reconstructed data to h5 file") write_als_832h5(rec, args.input, fdata, gdata, args.output_file, step) return
def preprocess_data(prj, flat, dark, FF_norm=flat_field_norm, remove_rings = remove_rings, medfilt_size=medfilt_size, FF_drift_corr=flat_field_drift_corr, downspling=binning): if FF_norm: # normalize the prj print('\n*** Applying flat field correction:') start_norm_time = time.time() prj = tomopy.normalize(prj, flat, dark) print(' done in %0.3f min' % ((time.time() - start_norm_time)/60)) if FF_drift_corr: print('\n*** Applying flat field drift correction:') start_norm_bg_time = time.time() prj = tomopy.normalize_bg(prj, air=100) print(' done in %0.3f min' % ((time.time() - start_norm_bg_time)/60)) # Applying -log print('\n*** Applying -log:') start_log_time = time.time() prj = tomopy.minus_log(prj) print(' done in %0.3f min' % ((time.time() - start_log_time)/60)) prj = tomopy.misc.corr.remove_neg(prj, val=0.000) prj = tomopy.misc.corr.remove_nan(prj, val=0.000) prj[np.where(prj == np.inf)] = 0.000 # prj[np.where(prj == 0)] = 0.000 print('\n*** Min and max val in prj before recon: %0.3f, %0.3f' % (np.min(prj), np.max(prj))) if remove_rings: # remove ring artefacts tmp = prj[-1,:,:] # use to fixe the bug of remove_stripe_ti print('\n*** Applying ring removal algo:') start_ring_time = time.time() prj = tomopy.remove_stripe_ti(prj,2) # prj = tomopy.remove_stripe_sf(prj,10); prj = tomopy.misc.corr.remove_neg(prj, val=0.000) # remove the neg values coming from remove_stripe_sf print(' done in %0.3f min' % ((time.time() - start_ring_time)/60)) prj[-1,:,:] = tmp # fixe the bug of remove_stripe_ti if phase_retrieval: # phase retrieval prj = tomopy.prep.phase.retrieve_phase(prj,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=alpha,pad=True) # Filtering data with 2D median filter before downsampling and recon if medfilt_size>1: start_filter_time = time.time() print('\n*** Applying median filter') #prj = tomopy.median_filter(prj,size=1) prj = ndimage.median_filter(prj,footprint=np.ones((1, medfilt_size, medfilt_size))) print(' done in %0.3f min' % ((time.time() - start_filter_time)/60)) # Downsampling data: if downspling>0: print('\n** Applying downsampling') start_down_time = time.time() prj = tomopy.downsample(prj, level=binning) prj = tomopy.downsample(prj, level=binning, axis=1) print(' done in %0.3f min' % ((time.time() - start_down_time)/60)) print('\n*** Shape of the data:'+str(np.shape(prj))) print(' Dimension of theta:'+str(np.shape(theta))) return prj
def reconstruct(h5fname, sino, rot_center, binning, algorithm='gridrec', options=None, num_iter=100, dark_file=None): sample_detector_distance = 10 # Propagation distance of the wavefront in cm detector_pixel_size_x = 2.247e-4 # Detector pixel size in cm (5x: 1.17e-4, 2X: 2.93e-4) monochromator_energy = 35 # Energy of incident wave in keV alpha = 1e-01 # Phase retrieval coeff. zinger_level = 500 # Zinger level for projections zinger_level_w = 1000 # Zinger level for white # Read APS 32-BM raw data. proj, flat, dark, theta = dxchange.read_aps_32id(h5fname, sino=sino) if dark_file is not None: proj_, flat, dark, theta_ = dxchange.read_aps_32id(dark_file, sino=sino) del proj_, theta_ # zinger_removal proj = tomopy.misc.corr.remove_outlier(proj, zinger_level, size=15, axis=0) # flat = tomopy.misc.corr.remove_outlier(flat, zinger_level_w, size=15, axis=0) # Flat-field correction of raw data. ##data = tomopy.normalize(proj, flat, dark, cutoff=0.8) data = tomopy.normalize(proj, flat, dark) # remove stripes data = tomopy.remove_stripe_fw(data,level=7,wname='sym16',sigma=1,pad=True) data = tomopy.remove_stripe_ti(data, alpha=1.5) data = tomopy.remove_stripe_sf(data, size=150) # phase retrieval #data = tomopy.prep.phase.retrieve_phase(data,pixel_size=detector_pixel_size_x,dist=sample_detector_distance,energy=monochromator_energy,alpha=alpha,pad=True) print("Raw data: ", h5fname) print("Center: ", rot_center) data = tomopy.minus_log(data) data = tomopy.remove_nan(data, val=0.0) data = tomopy.remove_neg(data, val=0.00) data[np.where(data == np.inf)] = 0.00 rot_center = rot_center/np.power(2, float(binning)) data = tomopy.downsample(data, level=binning) data = tomopy.downsample(data, level=binning, axis=1) print(algorithm) # Reconstruct object. if algorithm == 'sirtfbp': rec = rec_sirtfbp(data, theta, rot_center) elif algorithm == "astra_fbp": if options == 'linear': options = {'proj_type':'linear', 'method':'FBP'} else: options = {'proj_type':'cuda', 'method':'FBP_CUDA'} rec = tomopy.recon(data, theta, center=rot_center, algorithm=tomopy.astra, options=options, ncore=1) elif algorithm == "astra_sirt": extra_options = {'MinConstraint':0} options = {'proj_type':'cuda', 'method':'SIRT_CUDA', 'num_iter':num_iter, 'extra_options':extra_options} rec = tomopy.recon(data, theta, center=rot_center, algorithm=tomopy.astra, options=options) elif algorithm == tomopy.astra: rec = tomopy.recon(data, theta, center=rot_center, algorithm=tomopy.astra, options=options) else: try: rec = tomopy.recon(data, theta, center=rot_center, algorithm=algorithm, filter_name='parzen') except: rec = tomopy.recon(data, theta, center=rot_center, algorithm=algorithm) print("Algorithm: ", algorithm) # Mask each reconstructed slice with a circle. rec = tomopy.circ_mask(rec, axis=0, ratio=0.95) return rec