def _medianize(dset): num_imgs = get_nr_projs ( dset ) # Return error if there are no images: if (num_imgs == 0): return -1 # Error: # Return the only image in case of one image: elif (num_imgs == 1): return read_tomo(dset,0).astype(float32) # Do the median of all the images if there is more than one image: if num_imgs > 1: # Get first image: im = read_tomo(dset,0).astype(float32) # Read all the remaining files (if any) and save it in a volume: for i in range(1, num_imgs): # Read i-th image from input folder: #im = im + dset[i,:,:].astype(float32) im = im + read_tomo(dset,i).astype(float32) # Medianize volume along the third-dimension: im = im / num_imgs # Reshape output and return: return im.astype(float32)
def main(argv): """ Print dimensions of HDF5 file """ # # Get the parameters: # infile = argv[0] f = getHDF5(infile, 'r') if "/tomo" in f: dset = f['tomo'] else: dset = f['exchange/data'] print("Projections: " + tdf.get_nr_projs(dset)) print("Slices: " + tdf.get_nr_sinos(dset)) print("DetectorSize: " + tdf.get_det_size(dset))
def main(argv): """To do... """ lock = Lock() skip_flat = True first_done = False pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # Get full paths of input TDF and output TDF: infile = argv[2] outfile = argv[3] # Get the phase retrieval parameters: method = int(argv[4]) param1 = double(argv[5]) # e.g. regParam, or beta param2 = double(argv[6]) # e.g. thresh or delta energy = double(argv[7]) distance = double(argv[8]) pixsize = double(argv[9]) / 1000.0 # pixsixe from micron to mm: pad = True if argv[10] == "True" else False # Number of threads (actually processes) to use and logfile: nr_threads = int(argv[11]) logfilename = argv[12] # Log infos: log = open(logfilename,"w") log.write(linesep + "\tInput TDF file: %s" % (infile)) log.write(linesep + "\tOutput TDF file: %s" % (outfile)) log.write(linesep + "\t--------------") if (method == 0): log.write(linesep + "\tMethod: TIE-Hom (Paganin et al., 2002)") log.write(linesep + "\t--------------") log.write(linesep + "\tDelta/Beta: %0.1f" % ((param2/param1)) ) #else: # log.write(linesep + "\tMethod: Projected CTF (Moosmann et al., 2011)") # log.write(linesep + "\t--------------") # log.write(linesep + "\tDelta/Beta: %0.1f" % ((param2/param1)) ) log.write(linesep + "\tEnergy: %0.1f keV" % (energy)) log.write(linesep + "\tDistance: %0.1f mm" % (distance)) log.write(linesep + "\tPixel size: %0.3f micron" % (pixsize*1000)) log.write(linesep + "\t--------------") log.write(linesep + "\tBrowsing input files...") log.close() # Remove a previous copy of output: if exists(outfile): remove(outfile) # Open the HDF5 file: f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) if (num_proj == 0): log = open(logfilename,"a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() log = open(logfilename,"a") log.write(linesep + "\tInput files browsed correctly.") log.close() # Check extrema (int_to == -1 means all files): if ( (int_to >= num_proj) or (int_to == -1) ): int_to = num_proj - 1 if ( (int_from < 0) ): int_from = 0 # Prepare the plan: log = open(logfilename,"a") log.write(linesep + "\tPreparing the work plan...") log.close() im = tdf.read_tomo(dset,0).astype(float32) outshape = tdf.get_dset_shape(im.shape[1], im.shape[0], num_proj) f_out = getHDF5(outfile, 'w') f_out_dset = f_out.create_dataset('exchange/data', outshape, float32) f_out_dset.attrs['min'] = str(amin(im[:])) f_out_dset.attrs['max'] = str(amax(im[:])) f_out_dset.attrs['version'] = '1.0' f_out_dset.attrs['axes'] = "y:theta:x" f_in.close() f_out.close() if (method == 0): # Paganin's: plan = tiehom_plan (im, param1, param2, energy, distance, pixsize, pad) else: plan = phrt_plan (im, energy, distance, pixsize, param2, param1, method, pad) # Run several threads for independent computation without waiting for threads completion: for num in range(nr_threads): start = (num_proj / nr_threads)*num if (num == nr_threads - 1): end = num_proj - 1 else: end = (num_proj / nr_threads)*(num + 1) - 1 Process(target=_process, args=(lock, start, end, infile, outfile, outshape, float32, method, plan, logfilename)).start()
def dff_prepare_plan(white_dset, repetitions, dark): """ Prepare the Eigen Flat Fields (EFFs) and the filtered EFFs to be used for dynamic flat fielding. (Function to be called once before the actual filtering of each projection). Parameters ---------- white_dset : array_like 3D matrix where each flat field image is stacked along the 3rd dimension. repetitions: int Number of iterations to consider during parallel analysis. dark : array_like Single dark image (perhaps the average of a series) to be subtracted from each flat field image. If the images are already dark corrected or dark correction is not required (e.g. due to a photon counting detector) a matrix of the proper shape with zeros has to be passed. Return value ------------ EFF : array_like Eigen flat fields stacked along the 3rd dimension. filtEFF : array_like Filtered eigen flat fields stacked along the 3rd dimension. Note ---- In this implementation all the collected white field images have to be loaded into memory and an internal 32-bit copy of the white fields is created. Considering also that the method better performs with several (i.e. hundreds) flat field images, this function might raise memory errors. References ---------- V. Van Nieuwenhove, J. De Beenhouwer, F. De Carlo, L. Mancini, F. Marone, and J. Sijbers, "Dynamic intensity normalization using eigen flat fields in X-ray imaging", Optics Express, 23(11), 27975-27989, 2015. """ # Get dimensions of flat-field (or white-field) images: num_flats = get_nr_projs(white_dset) / 4 num_rows = get_nr_sinos(white_dset) num_cols = get_det_size(white_dset) # Create local copy of white-field dataset: tmp_dset = zeros((num_rows * num_cols, num_flats), dtype=float32) avg = zeros((num_rows * num_cols), dtype=float32) # For all the flat images: for i in range(0, tmp_dset.shape[1]): # Read i-th flat image and dark-correct: tmp_dset[:, i] = read_tomo( white_dset, i).astype(float32).flatten() - dark.astype(float32).flatten() # Sum the image: avg = avg + tmp_dset[:, i] # Compute the mean: avg = avg / num_flats # Subtract mean white-field: for i in range(0, tmp_dset.shape[1]): tmp_dset[:, i] = tmp_dset[:, i] - avg # Calculate the number of Eigen Flat Fields (EFF) to use: V, nrEFF = _parallelAnalysis(tmp_dset, repetitions) # Compute the EFFs (0-th image is the average "conventional" flat field): EFF = zeros((num_rows, num_cols, nrEFF + 1), dtype=float32) EFF[:, :, 0] = avg.reshape((num_rows, num_cols)) for i in range(0, nrEFF): EFF[:, :, i + 1] = dot(tmp_dset, V[:, num_flats - (i + 1)]).reshape( (num_rows, num_cols)) # Filter the EFFs: filtEFF = zeros((num_rows, num_cols, 1 + nrEFF), dtype=float32) for i in range(1, 1 + nrEFF): filtEFF[:, :, i] = median_filter(EFF[:, :, i], 3) return EFF, filtEFF
def main(argv): """Try to guess the center of rotation of the input CT dataset. Parameters ---------- infile : array_like HDF5 input dataset outfile : string Full path where the identified center of rotation will be written as output scale : int If sub-pixel precision is interesting, use e.g. 2.0 to get a center of rotation of .5 value. Use 1.0 if sub-pixel precision is not required angles : int Total number of angles of the input dataset proj_from : int Initial projections to consider for the assumed angles proj_to : int Final projections to consider for the assumed angles method : string (not implemented yet) tmppath : string Temporary path where look for cached flat/dark files """ # Get path: infile = argv[0] # The HDF5 file on the outfile = argv[1] # The txt file with the proposed center scale = float(argv[2]) angles = float(argv[3]) proj_from = int(argv[4]) proj_to = int(argv[5]) method = argv[6] tmppath = argv[7] if not tmppath.endswith(sep): tmppath += sep pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Create a silly temporary log: tmplog = tmppath + basename(infile) + str(time.time()) # Open the HDF5 file (take into account also older TDF versions): f_in = getHDF5( infile, 'r' ) if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Get flats and darks from cache or from file: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, tmplog) remove(tmplog) plan2cache(corrplan, infile, tmppath) # Get first and the 180 deg projections: im1 = tdf.read_tomo(dset,proj_from).astype(float32) idx = int(round( (proj_to - proj_from)/angles * pi)) + proj_from im2 = tdf.read_tomo(dset,idx).astype(float32) # Apply simple flat fielding (if applicable): if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)) : im1 = ((abs(im1 - corrplan['im_dark'])) / (abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps)).astype(float32) im2 = ((abs(im2 - corrplan['im_dark_after'])) / (abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps)).astype(float32) # Scale projections (if required) to get subpixel estimation: if ( abs(scale - 1.0) > finfo(float32).eps ): im1 = imresize(im1, (int(round(scale*im1.shape[0])), int(round(scale*im1.shape[1]))), interp='bicubic', mode='F'); im2 = imresize(im2, (int(round(scale*im2.shape[0])), int(round(scale*im2.shape[1]))), interp='bicubic', mode='F'); # Find the center (flipping left-right im2): cen = findcenter.usecorrelation(im1, im2[ :,::-1]) cen = cen / scale # Print center to output file: text_file = open(outfile, "w") text_file.write(str(int(cen))) text_file.close() # Close input HDF5: f_in.close()
def main(argv): """Try to guess the amount of overlap in the case of extended FOV CT. Parameters ---------- infile : array_like HDF5 input dataset outfile : string Full path where the identified overlap will be written as output scale : int If sub-pixel precision is interesting, use e.g. 2.0 to get an overlap of .5 value. Use 1.0 if sub-pixel precision is not required tmppath : int Temporary path where look for cached flat/dark files """ # Get path: infile = argv[0] # The HDF5 file on the SSD outfile = argv[1] # The txt file with the proposed center scale = float(argv[2]) tmppath = argv[3] if not tmppath.endswith(sep): tmppath += sep # Create a silly temporary log: tmplog = tmppath + basename(infile) + str(time.time()) # Open the HDF5 file: f_in = getHDF5( infile, 'r' ) if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) # Get first and 180 deg projections: im1 = tdf.read_tomo(dset,0).astype(float32) im2 = tdf.read_tomo(dset,num_proj/2).astype(float32) # Get flats and darks from cache or from file: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, tmplog) remove(tmplog) plan2cache(corrplan, infile, tmppath) # Apply simple flat fielding (if applicable): if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)) : im1 = ((abs(im1 - corrplan['im_dark'])) / (abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps)).astype(float32) im2 = ((abs(im2 - corrplan['im_dark_after'])) / (abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps)).astype(float32) # Scale projections (if required) to get subpixel estimation: if ( abs(scale - 1.0) > finfo(float32).eps ): im1 = imresize(im1, (int(round(scale*im1.shape[0])), int(round(scale*im1.shape[1]))), interp='bicubic', mode='F'); im2 = imresize(im2, (int(round(scale*im2.shape[0])), int(round(scale*im2.shape[1]))), interp='bicubic', mode='F'); # Find the center (flipping left-right im2): DISTINGUISH BETWEEN AIR ON THE RIGHT AND ON THE LEFT?????? cen = findcenter.usecorrelation(im1, im2[ :,::-1]) cen = (cen / scale)*2.0 # Print center to output file: text_file = open(outfile, "w") text_file.write(str(int(abs(cen)))) text_file.close() # Close input HDF5: f_in.close()
def main(argv): """To do... """ lock = Lock() skip_flat = True first_done = False pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Get the from and to number of files to process: idx = int(argv[0]) # Get full paths of input TDF and output TDF: infile = argv[1] outfile = argv[2] # Get the phase retrieval parameters: method = int(argv[3]) param1 = double(argv[4]) # param1( e.g. regParam, or beta) param2 = double(argv[5]) # param2( e.g. thresh or delta) energy = double(argv[6]) distance = double(argv[7]) pixsize = double(argv[8]) / 1000.0 # pixsixe from micron to mm: pad = True if argv[9] == "True" else False # Tmp path and log file: tmppath = argv[10] if not tmppath.endswith(sep): tmppath += sep logfilename = argv[11] # Open the HDF5 file and check it contains flat files: skipflat = False f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] if not "/flat" in f_in: skipflat = True else: dset = f_in['exchange/data'] if not "/exchange/data_white" in f_in: skipflat = True num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Check if the HDF5 makes sense: if (num_proj == 0): log = open(logfilename,"a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Get flats and darks from cache or from file: if not skipflat: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, logfilename) remove(logfilename) plan2cache(corrplan, infile, tmppath) # Read projection: im = tdf.read_tomo(dset,idx).astype(float32) f_in.close() # Apply simple flat fielding (if applicable): if not skipflat: if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)) : if (idx < num_proj/2): im = (im - corrplan['im_dark']) / (abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps) else: im = (im - corrplan['im_dark_after']) / (abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps) # Prepare plan: im = im.astype(float32) if (method == 0): # Paganin's: plan = tiehom_plan (im, param1, param2, energy, distance, pixsize, pad) im = tiehom(im, plan).astype(float32) else: plan = phrt_plan (im, energy, distance, pixsize, param2, param1, method, pad) im = phrt(im, plan, method).astype(float32) # Write down reconstructed preview file (file name modified with metadata): im = im.astype(float32) outfile = outfile + '_' + str(im.shape[1]) + 'x' + str(im.shape[0]) + '_' + str( nanmin(im)) + '$' + str( nanmax(im) ) im.tofile(outfile)
def main(argv): """To do... """ # Get the zero-order index of the sinogram to pre-process: idx = int(argv[0]) # Get paths: infile = argv[1] outfile = argv[2] # Normalization parameters: norm_sx = int(argv[3]) norm_dx = int(argv[4]) # Params for flat fielding with post flats/darks: flat_end = True if argv[5] == "True" else False half_half = True if argv[6] == "True" else False half_half_line = int(argv[7]) # Params for extended FOV: ext_fov = True if argv[8] == "True" else False ext_fov_rot_right = argv[9] if ext_fov_rot_right == "True": ext_fov_rot_right = True if (ext_fov): norm_sx = 0 else: ext_fov_rot_right = False if (ext_fov): norm_dx = 0 ext_fov_overlap = int(argv[10]) ext_fov_normalize = True if argv[11] == "True" else False ext_fov_average = True if argv[12] == "True" else False # Method and parameters coded into a string: ringrem = argv[13] # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[14] == "True" else False # Tmp path and log file: tmppath = argv[15] if not tmppath.endswith(sep): tmppath += sep logfilename = argv[16] # Open the HDF5 file: f_in = getHDF5(infile, 'r') try: if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] except: log = open(logfilename,"a") log.write(linesep + "\tError reading input dataset. Process will end.") log.close() exit() num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Check if the HDF5 makes sense: if (num_sinos == 0): log = open(logfilename,"a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Get flat and darks from cache or from file: skipflat = False skipdark = False if not dynamic_ff: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, flat_end, logfilename) if (isscalar(corrplan['im_flat']) and isscalar(corrplan['im_flat_after']) ): skipflat = True else: plan2cache(corrplan, infile, tmppath) else: # Dynamic flat fielding: if "/tomo" in f_in: if "/flat" in f_in: flat_dset = f_in['flat'] if "/dark" in f_in: im_dark = _medianize(f_in['dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case else: if "/exchange/data_white" in f_in: flat_dset = f_in['/exchange/data_white'] if "/exchange/data_dark" in f_in: im_dark = _medianize(f_in['/exchange/data_dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat: EFF, filtEFF = dff_prepare_plan(flat_dset, 16, im_dark) # Read input image: im = tdf.read_sino(dset,idx).astype(float32) f_in.close() # Perform pre-processing (flat fielding, extended FOV, ring removal): if not skipflat: if dynamic_ff: # Dynamic flat fielding with downsampling = 2: im = dynamic_flat_fielding(im, idx, EFF, filtEFF, 2, im_dark, norm_sx, norm_dx) else: im = flat_fielding(im, idx, corrplan, flat_end, half_half, half_half_line, norm_sx, norm_dx) if ext_fov: im = extfov_correction(im, ext_fov_rot_right, ext_fov_overlap, ext_fov_normalize, ext_fov_average) if not skipflat and not dynamic_ff: im = ring_correction (im, ringrem, flat_end, corrplan['skip_flat_after'], half_half, half_half_line, ext_fov) else: im = ring_correction (im, ringrem, False, False, half_half, half_half_line, ext_fov) # Write down reconstructed preview file (file name modified with metadata): im = im.astype(float32) outfile = outfile + '_' + str(im.shape[1]) + 'x' + str(im.shape[0]) + '_' + str( nanmin(im)) + '$' + str( nanmax(im) ) im.tofile(outfile)
def main(argv): """To do... """ # Get the zero-order index of the sinogram to pre-process: idx = int(argv[0]) # Get paths: infile = argv[1] outfile = argv[2] # Normalization parameters: norm_sx = int(argv[3]) norm_dx = int(argv[4]) # Params for flat fielding with post flats/darks: flat_end = True if argv[5] == "True" else False half_half = True if argv[6] == "True" else False half_half_line = int(argv[7]) # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[8] == "True" else False # Parameters for rotation: rotation = float(argv[9]) interp = argv[10] border = argv[11] # Tmp path and log file: tmppath = argv[12] if not tmppath.endswith(sep): tmppath += sep logfilename = argv[13] # Open the HDF5 file: f_in = getHDF5(infile, 'r') try: if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] except: log = open(logfilename, "a") log.write(linesep + "\tError reading input dataset. Process will end.") log.close() exit() num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Check if the HDF5 makes sense: if (num_sinos == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Get flat and darks from cache or from file: skipflat = False skipdark = False if not dynamic_ff: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, flat_end, logfilename) if (isscalar(corrplan['im_flat']) and isscalar(corrplan['im_flat_after'])): skipflat = True else: plan2cache(corrplan, infile, tmppath) else: # Dynamic flat fielding: if "/tomo" in f_in: if "/flat" in f_in: flat_dset = f_in['flat'] if "/dark" in f_in: im_dark = _medianize(f_in['dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case else: if "/exchange/data_white" in f_in: flat_dset = f_in['/exchange/data_white'] if "/exchange/data_dark" in f_in: im_dark = _medianize(f_in['/exchange/data_dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat: EFF, filtEFF = dff_prepare_plan(flat_dset, 16, im_dark) # Read input image: im = tdf.read_tomo(dset, idx).astype(float32) f_in.close() # Perform pre-processing (flat fielding, extended FOV, ring removal): if not skipflat: if dynamic_ff: # Dynamic flat fielding with downsampling = 2: im = dynamic_flat_fielding(im, EFF, filtEFF, 2, im_dark) else: im = flat_fielding(im, idx, corrplan, flat_end, half_half, half_half_line, norm_sx, norm_dx) # Rotate: rows, cols = im.shape M = cv2.getRotationMatrix2D((cols / 2, rows / 2), rotation, 1) if interp == 'nearest': interpflag = cv2.INTER_NEAREST elif interp == 'cubic': interpflag = cv2.INTER_CUBIC elif interp == 'lanczos': interpflag = cv2.INTER_LANCZOS4 else: interpflag = cv2.INTER_LINEAR if border == 'constant': borderflag = cv2.BORDER_CONSTANT else: borderflag = cv2.BORDER_REPLICATE im = cv2.warpAffine(im, M, (cols, rows), flags=interpflag, borderMode=borderflag) # Write down reconstructed preview file (file name modified with metadata): im = im.astype(float32) outfile2 = outfile + '_' + str(im.shape[1]) + 'x' + str( im.shape[0]) + '_' + str(nanmin(im)) + '$' + str( nanmax(im)) + '_after.raw' im.tofile(outfile2)
def dff_prepare_plan(white_dset, repetitions, dark): """ Prepare the Eigen Flat Fields (EFFs) and the filtered EFFs to be used for dynamic flat fielding. (Function to be called once before the actual filtering of each projection). Parameters ---------- white_dset : array_like 3D matrix where each flat field image is stacked along the 3rd dimension. repetitions: int Number of iterations to consider during parallel analysis. dark : array_like Single dark image (perhaps the average of a series) to be subtracted from each flat field image. If the images are already dark corrected or dark correction is not required (e.g. due to a photon counting detector) a matrix of the proper shape with zeros has to be passed. Return value ------------ EFF : array_like Eigen flat fields stacked along the 3rd dimension. filtEFF : array_like Filtered eigen flat fields stacked along the 3rd dimension. Note ---- In this implementation all the collected white field images have to be loaded into memory and an internal 32-bit copy of the white fields is created. Considering also that the method better performs with several (i.e. hundreds) flat field images, this function might raise memory errors. References ---------- V. Van Nieuwenhove, J. De Beenhouwer, F. De Carlo, L. Mancini, F. Marone, and J. Sijbers, "Dynamic intensity normalization using eigen flat fields in X-ray imaging", Optics Express, 23(11), 27975-27989, 2015. """ # Get dimensions of flat-field (or white-field) images: num_flats = get_nr_projs(white_dset)/4 num_rows = get_nr_sinos(white_dset) num_cols = get_det_size(white_dset) # Create local copy of white-field dataset: tmp_dset = zeros((num_rows * num_cols, num_flats), dtype=float32) avg = zeros((num_rows * num_cols), dtype=float32) # For all the flat images: for i in range(0, tmp_dset.shape[1]): # Read i-th flat image and dark-correct: tmp_dset[:,i] = read_tomo(white_dset,i).astype(float32).flatten() - dark.astype(float32).flatten() # Sum the image: avg = avg + tmp_dset[:,i] # Compute the mean: avg = avg / num_flats # Subtract mean white-field: for i in range(0, tmp_dset.shape[1]): tmp_dset[:,i] = tmp_dset[:,i] - avg # Calculate the number of Eigen Flat Fields (EFF) to use: V, nrEFF = _parallelAnalysis(tmp_dset, repetitions) # Compute the EFFs (0-th image is the average "conventional" flat field): EFF = zeros((num_rows, num_cols, nrEFF + 1), dtype=float32) EFF[:,:,0] = avg.reshape((num_rows, num_cols)) for i in range(0, nrEFF): EFF[:,:,i + 1] = dot(tmp_dset, V[:,num_flats - (i + 1)]).reshape((num_rows, num_cols)) # Filter the EFFs: filtEFF = zeros((num_rows, num_cols, 1 + nrEFF), dtype=float32) for i in range(1, 1 + nrEFF): filtEFF[:,:,i] = median_filter(EFF[:,:,i], 3) return EFF, filtEFF
def main(argv): """To do... Usage ----- Parameters --------- Example -------------------------- """ lock = Lock() # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # Get paths: infile_1 = argv[2] infile_2 = argv[3] infile_3 = argv[4] outfile_abs = argv[5] outfile_ref = argv[6] outfile_sca = argv[7] # Normalization parameters: norm_sx = int(argv[8]) norm_dx = int(argv[9]) # Params for flat fielding with post flats/darks: flat_end = True if argv[10] == "True" else False half_half = True if argv[11] == "True" else False half_half_line = int(argv[12]) # Params for extended FOV: ext_fov = True if argv[13] == "True" else False ext_fov_rot_right = argv[14] if ext_fov_rot_right == "True": ext_fov_rot_right = True if (ext_fov): norm_sx = 0 else: ext_fov_rot_right = False if (ext_fov): norm_dx = 0 ext_fov_overlap = int(argv[15]) ext_fov_normalize = True if argv[16] == "True" else False ext_fov_average = True if argv[17] == "True" else False # Method and parameters coded into a string: ringrem = argv[18] # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[19] == "True" else False # Shift parameters: shiftVert_1 = int(argv[20]) shiftHoriz_1 = int(argv[21]) shiftVert_2 = int(argv[22]) shiftHoriz_2 = int(argv[23]) shiftVert_3 = int(argv[24]) shiftHoriz_3 = int(argv[25]) # DEI coefficients: r1 = float(argv[26]) r2 = float(argv[27]) r3 = float(argv[28]) d1 = float(argv[29]) d2 = float(argv[30]) d3 = float(argv[31]) dd1 = float(argv[32]) dd2 = float(argv[33]) dd3 = float(argv[34]) # Nr of threads and log file: nr_threads = int(argv[35]) logfilename = argv[36] # Log input parameters: log = open(logfilename, "w") log.write(linesep + "\tInput TDF file #1: %s" % (infile_1)) log.write(linesep + "\tInput TDF file #2: %s" % (infile_2)) log.write(linesep + "\tInput TDF file #3: %s" % (infile_3)) log.write(linesep + "\tOutput TDF file for Absorption: %s" % (outfile_abs)) log.write(linesep + "\tOutput TDF file for Refraction: %s" % (outfile_ref)) log.write(linesep + "\tOutput TDF file for Scattering: %s" % (outfile_sca)) log.write(linesep + "\t--------------") log.write(linesep + "\tOpening input dataset...") log.close() # Remove a previous copy of output: #if exists(outfile): # remove(outfile) # Open the HDF5 files: f_in_1 = getHDF5(infile_1, 'r') f_in_2 = getHDF5(infile_2, 'r') f_in_3 = getHDF5(infile_3, 'r') if "/tomo" in f_in_1: dset_1 = f_in_1['tomo'] tomoprefix_1 = 'tomo' flatprefix_1 = 'flat' darkprefix_1 = 'dark' else: dset_1 = f_in_1['exchange/data'] if "/provenance/detector_output" in f_in_1: prov_dset_1 = f_in_1['provenance/detector_output'] tomoprefix_1 = prov_dset_1.attrs['tomo_prefix'] flatprefix_1 = prov_dset_1.attrs['flat_prefix'] darkprefix_1 = prov_dset_1.attrs['dark_prefix'] if "/tomo" in f_in_2: dset_2 = f_in_2['tomo'] tomoprefix_2 = 'tomo' flatprefix_2 = 'flat' darkprefix_2 = 'dark' else: dset_2 = f_in_2['exchange/data'] if "/provenance/detector_output" in f_in_2: prov_dset_2 = f_in_2['provenance/detector_output'] tomoprefix_2 = prov_dset_2.attrs['tomo_prefix'] flatprefix_2 = prov_dset_2.attrs['flat_prefix'] darkprefix_2 = prov_dset_2.attrs['dark_prefix'] if "/tomo" in f_in_3: dset_3 = f_in_3['tomo'] tomoprefix_3 = 'tomo' flatprefix_3 = 'flat' darkprefix_3 = 'dark' else: dset_3 = f_in_3['exchange/data'] if "/provenance/detector_output" in f_in_3: prov_dset_3 = f_in_1['provenance/detector_output'] tomoprefix_3 = prov_dset_3.attrs['tomo_prefix'] flatprefix_3 = prov_dset_3.attrs['flat_prefix'] darkprefix_3 = prov_dset_3.attrs['dark_prefix'] # Assuming that what works for the dataset #1 works for the other two: num_proj = tdf.get_nr_projs(dset_1) num_sinos = tdf.get_nr_sinos(dset_1) if (num_sinos == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Check extrema (int_to == -1 means all files): if ((int_to >= num_sinos) or (int_to == -1)): int_to = num_sinos - 1 # Prepare the work plan for flat and dark images: log = open(logfilename, "a") log.write(linesep + "\t--------------") log.write(linesep + "\tPreparing the work plan...") log.close() # Extract flat and darks: skipflat_1 = False skipdark_1 = False skipflat_2 = False skipdark_2 = False skipflat_3 = False skipdark_3 = False # Following variables make sense only for dynamic flat fielding: EFF_1 = -1 filtEFF_1 = -1 im_dark_1 = -1 EFF_2 = -1 filtEFF_2 = -1 im_dark_2 = -1 EFF_3 = -1 filtEFF_3 = -1 im_dark_3 = -1 # Following variable makes sense only for conventional flat fielding: plan_1 = -1 plan_2 = -1 plan_3 = -1 if not dynamic_ff: plan_1 = extract_flatdark(f_in_1, flat_end, logfilename) if (isscalar(plan_1['im_flat']) and isscalar(plan_1['im_flat_after'])): skipflat_1 = True else: skipflat_1 = False plan_2 = extract_flatdark(f_in_2, flat_end, logfilename) if (isscalar(plan_2['im_flat']) and isscalar(plan_2['im_flat_after'])): skipflat_2 = True else: skipflat_2 = False plan_3 = extract_flatdark(f_in_3, flat_end, logfilename) if (isscalar(plan_3['im_flat']) and isscalar(plan_3['im_flat_after'])): skipflat_3 = True else: skipflat_3 = False else: # Dynamic flat fielding: if "/tomo" in f_in_1: if "/flat" in f_in_1: flat_dset_1 = f_in_1['flat'] if "/dark" in f_in_1: im_dark_1 = _medianize(f_in_1['dark']) else: skipdark_1 = True else: skipflat_1 = True # Nothing to do in this case else: if "/exchange/data_white" in f_in_1: flat_dset_1 = f_in_1['/exchange/data_white'] if "/exchange/data_dark" in f_in_1: im_dark_1 = _medianize(f_in_1['/exchange/data_dark']) else: skipdark_1 = True else: skipflat_1 = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat_1: EFF_1, filtEFF_1 = dff_prepare_plan(flat_dset_1, 16, im_dark_1) # Dynamic flat fielding: if "/tomo" in f_in_2: if "/flat" in f_in_2: flat_dset_2 = f_in_2['flat'] if "/dark" in f_in_2: im_dark_2 = _medianize(f_in_2['dark']) else: skipdark_2 = True else: skipflat_2 = True # Nothing to do in this case else: if "/exchange/data_white" in f_in_2: flat_dset_2 = f_in_2['/exchange/data_white'] if "/exchange/data_dark" in f_in_2: im_dark_2 = _medianize(f_in_2['/exchange/data_dark']) else: skipdark_2 = True else: skipflat_2 = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat_2: EFF_2, filtEFF_2 = dff_prepare_plan(flat_dset_2, 16, im_dark_2) # Dynamic flat fielding: if "/tomo" in f_in_3: if "/flat" in f_in_3: flat_dset_3 = f_in_3['flat'] if "/dark" in f_in_3: im_dark_3 = _medianize(f_in_3['dark']) else: skipdark_3 = True else: skipflat_3 = True # Nothing to do in this case else: if "/exchange/data_white" in f_in_3: flat_dset_3 = f_in_3['/exchange/data_white'] if "/exchange/data_dark" in f_in_3: im_dark_3 = _medianize(f_in_3['/exchange/data_dark']) else: skipdark_3 = True else: skipflat_3 = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat_3: EFF_3, filtEFF_3 = dff_prepare_plan(flat_dset_3, 16, im_dark_3) # Outfile shape can be determined only after first processing in ext FOV mode: if (ext_fov): # Read input sino: idx = num_sinos / 2 im = tdf.read_sino(dset_1, idx).astype(float32) im = extfov_correction(im, ext_fov_rot_right, ext_fov_overlap, ext_fov_normalize, ext_fov_average) # Get the corrected outshape: outshape = tdf.get_dset_shape(im.shape[1], num_sinos, im.shape[0]) else: # Get the corrected outshape (in this case it's easy): im = tdf.read_tomo(dset_1, 0).astype(float32) outshape = tdf.get_dset_shape(im.shape[1], im.shape[0], num_proj) f_in_1.close() f_in_2.close() f_in_3.close() # Create the output HDF5 files: f_out_abs = getHDF5(outfile_abs, 'w') f_out_dset_abs = f_out_abs.create_dataset('exchange/data', outshape, float32) f_out_dset_abs.attrs['min'] = str(finfo(float32).max) f_out_dset_abs.attrs['max'] = str(finfo(float32).min) f_out_dset_abs.attrs['version'] = '1.0' f_out_dset_abs.attrs['axes'] = "y:theta:x" f_out_abs.close() f_out_ref = getHDF5(outfile_ref, 'w') f_out_dset_ref = f_out_ref.create_dataset('exchange/data', outshape, float32) f_out_dset_ref.attrs['min'] = str(finfo(float32).max) f_out_dset_ref.attrs['max'] = str(finfo(float32).min) f_out_dset_ref.attrs['version'] = '1.0' f_out_dset_ref.attrs['axes'] = "y:theta:x" f_out_ref.close() f_out_sca = getHDF5(outfile_sca, 'w') f_out_dset_sca = f_out_sca.create_dataset('exchange/data', outshape, float32) f_out_dset_sca.attrs['min'] = str(finfo(float32).max) f_out_dset_sca.attrs['max'] = str(finfo(float32).min) f_out_dset_sca.attrs['version'] = '1.0' f_out_dset_sca.attrs['axes'] = "y:theta:x" f_out_sca.close() # Log infos: log = open(logfilename, "a") log.write(linesep + "\tWork plan prepared correctly.") log.write(linesep + "\t--------------") log.write(linesep + "\tPerforming GDEI...") log.close() # Run several threads for independent computation without waiting for threads # completion: for num in range(nr_threads): start = (num_sinos / nr_threads) * num if (num == nr_threads - 1): end = num_sinos - 1 else: end = (num_sinos / nr_threads) * (num + 1) - 1 Process( target=_process, args=(lock, start, end, num_sinos, infile_1, infile_2, infile_3, outfile_abs, outfile_ref, outfile_sca, r1, r2, r3, d1, d2, d3, dd1, dd2, dd3, shiftVert_1, shiftHoriz_1, shiftVert_2, shiftHoriz_2, shiftVert_3, shiftHoriz_3, outshape, float32, skipflat_1, skipflat_2, skipflat_3, plan_1, plan_2, plan_3, norm_sx, norm_dx, flat_end, half_half, half_half_line, ext_fov, ext_fov_rot_right, ext_fov_overlap, ext_fov_normalize, ext_fov_average, ringrem, dynamic_ff, EFF_1, EFF_2, EFF_3, filtEFF_1, filtEFF_2, filtEFF_3, im_dark_1, im_dark_2, im_dark_3, logfilename)).start()
def main(argv): """ Converts a TDF file (HDF5 Tomo Data Format) into a sequence of TIFF (uncompressed) files. Parameters ---------- from : scalar, integer among all the projections (or sinogram) data, a subset of the volume can be specified, ranging from the parameter "from" to the parameter "to" (see next). In most cases, this parameter is 0. to : scalar, integer among all the projections (or sinogram) data, a subset of the volume can be specified, ranging from the parameter "from" (see previous parameter) to the parameter "to". If the value -1 is specified, all the projection (or sinogram) data will be considered. in_file : string path with filename of the TDF to read from (e.g. "Z:\\sample1.tdf"). out_path : string path that will contain the sequence of TIFF files (e.g. "Z:\\sample1\\tomo\\"). WARNING: the program does NOT automatically create non-existing folders and subfolders specified in the path. Moreover, if files with the same name already exist they will be automatically overwritten. file_prefix : string string to be assumed as the filename prefix of the TIFF files to create for the projection (or sinogram) data. E.g. "tomo" will create files having name "tomo_0001.tif", "tomo_0002.tif". flat_prefix : string string to be assumed as the filename prefix of the TIFF files to create for the flat (white field) data. E.g. "flat" will create files having name "flat_1.tif", "flat_2.tif". If dark or flat data have to be skipped the string "-" can be specified. dark_prefix : string string to be assumed as the filename prefix of the TIFF files to create for the dark (dark field) data. E.g. "dark" will create files having name "dark_1.tif", "dark_2.tif". If dark or flat data have to be skipped the string "-" can be specified. projection_order : boolean string specify the string "True" to create TIFF files for projections (the most common case), "False" for sinograms. TIFF_format : boolean string specify the string "True" to create TIFF files, "False" for RAW files. nr_threads : int number of multiple threads (actually processes) to consider to speed up the whole conversion process. log_file : string path with filename of a log file (e.g. "R:\\log.txt") where info about the conversion is reported. Returns ------- no return value Example ------- Example call to convert all the projections data to a sequence of tomo*.tif files: python tdf2tiff.py 0 -1 "C:\Temp\wet12T4part2.tdf" "C:\Temp\tomo" tomo flat dark True True 3 "C:\Temp\log.txt" Requirements ------- - Python 2.7 with the latest NumPy, SciPy, H5Py. - TIFFFile from C. Gohlke - tdf.py Tests ------- Tested with WinPython-64bit-2.7.6.3 (Windows) and Anaconda 2.1.0 (Linux 64-bit). """ lock = Lock() # To be used without flat fielding (just conversion): first_done = False # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # -1 means "all files" # Get paths: infile = argv[2] outpath = argv[3] fileprefix = argv[4] flatprefix = argv[5] darkprefix = argv[6] if (flatprefix == "-"): skipflat = True else: skipflat = False if (darkprefix == "-"): skipdark = True else: skipdark = False if (fileprefix == "-"): skiptomo = True else: skiptomo = False projorder = argv[7] if projorder == "True": projorder = True else: projorder = False TIFFFormat = argv[8] if TIFFFormat == "True": TIFFFormat = True else: TIFFFormat = False nr_threads = int(argv[9]) logfilename = argv[10] # Check prefixes and path: if not outpath.endswith(os.path.sep): outpath += os.path.sep # Init variables: num_files = 0 num_flats = 0 num_darks = 0 # Get the files in infile: log = open(logfilename,"w") log.write(os.linesep + "\tInput TDF: %s" % (infile)) if (TIFFFormat): log.write(os.linesep + "\tOutput path where TIFF files will be created: %s" % (outpath)) else: log.write(os.linesep + "\tOutput path where RAW files will be created: %s" % (outpath)) log.write(os.linesep + "\t--------------") log.write(os.linesep + "\tFile output prefix: %s" % (fileprefix)) log.write(os.linesep + "\tFlat images output prefix: %s" % (flatprefix)) log.write(os.linesep + "\tDark images output prefix: %s" % (darkprefix)) log.write(os.linesep + "\t--------------") if (not (skiptomo)): if (int_to != -1): log.write(os.linesep + "\tThe subset [%d,%d] of the data will be considered." % (int_from, int_to)) if (projorder): log.write(os.linesep + "\tProjection order assumed.") else: log.write(os.linesep + "\tSinogram order assumed.") log.write(os.linesep + "\t--------------") log.close() if not os.path.exists(infile): log = open(logfilename,"a") log.write(os.linesep + "\tError: input TDF file not found. Process will end.") log.close() exit() # Open the HDF5 file: f = getHDF5(infile, 'r') oldTDF = False try: dset = f['tomo'] oldTDF = True except Exception: pass if not oldTDF: #try: dset = f['exchange/data'] #except Exception: # log = open(logfilename,"a") # log.write(os.linesep + "\tError: invalid TDF format. Process will end.") # log.close() # exit() if projorder: num_files = tdf.get_nr_projs(dset) else: num_files = tdf.get_nr_sinos(dset) f.close() # Get attributes: try: f = getHDF5(infile, 'r') if ('version' in f.attrs) and (f.attrs['version'] == 'TDF 1.0'): log = open(logfilename,"a") log.write(os.linesep + "\tTDF version 1.0 found.") log.write(os.linesep + "\t--------------") log.close() f.close() except: log = open(logfilename,"a") log.write(os.linesep + "\tWarning: TDF version unknown. Some features will not be available.") log.write(os.linesep + "\t--------------") log.close() # Check extrema (int_to == -1 means all files): if ((int_to >= num_files) or (int_to == -1)): int_to = num_files - 1 # Spawn the process for the conversion of flat images: if not skipflat: f = getHDF5(infile, 'r') if oldTDF: dset_str = 'flat' else: dset_str = 'exchange/data_white' num_flats = tdf.get_nr_projs(f[dset_str]) f.close() if (num_flats > 0): Process(target=_process, args=(lock, 0, num_flats - 1, infile, dset_str, TIFFFormat, True, outpath, flatprefix, logfilename)).start() #_process(lock, 0, num_flats - 1, infile, dset_str, TIFFFormat, projorder, #outpath, flatprefix, logfilename) # Spawn the process for the conversion of dark images: if not skipdark: f = getHDF5(infile, 'r') if oldTDF: dset_str = 'dark' else: dset_str = 'exchange/data_dark' num_darks = tdf.get_nr_projs(f[dset_str]) f.close() if (num_darks > 0): Process(target=_process, args=(lock, 0, num_darks - 1, infile, dset_str, TIFFFormat, True, outpath, darkprefix, logfilename)).start() #_process(lock, 0, num_darks - 1, infile, dset_str, TIFFFormat, projorder, #outpath, darkprefix, logfilename) # Spawn the processes for the conversion of projection or sinogram images: if not skiptomo: if oldTDF: dset_str = 'tomo' else: dset_str = 'exchange/data' # Start the process for the conversion of the projections (or sinograms) in a # multi-threaded way: for num in range(nr_threads): start = ((int_to - int_from + 1) / nr_threads) * num + int_from if (num == nr_threads - 1): end = int_to else: end = ((int_to - int_from + 1) / nr_threads) * (num + 1) + int_from - 1 Process(target=_process, args=(lock, start, end, infile, dset_str, TIFFFormat, projorder, outpath, fileprefix, logfilename)).start()
def main(argv): """To do... """ # Get the zero-order index of the sinogram to pre-process: idx = int(argv[0]) # Get paths: infile = argv[1] outfile = argv[2] # Normalization parameters: norm_sx = int(argv[3]) norm_dx = int(argv[4]) # Params for flat fielding with post flats/darks: flat_end = True if argv[5] == "True" else False half_half = True if argv[6] == "True" else False half_half_line = int(argv[7]) # Params for extended FOV: ext_fov = True if argv[8] == "True" else False ext_fov_rot_right = argv[9] if ext_fov_rot_right == "True": ext_fov_rot_right = True if (ext_fov): norm_sx = 0 else: ext_fov_rot_right = False if (ext_fov): norm_dx = 0 ext_fov_overlap = int(argv[10]) ext_fov_normalize = True if argv[11] == "True" else False ext_fov_average = True if argv[12] == "True" else False # Method and parameters coded into a string: ringrem = argv[13] # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[14] == "True" else False # Tmp path and log file: tmppath = argv[15] if not tmppath.endswith(sep): tmppath += sep logfilename = argv[16] # Open the HDF5 file: f_in = getHDF5(infile, 'r') try: if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] except: log = open(logfilename, "a") log.write(linesep + "\tError reading input dataset. Process will end.") log.close() exit() num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Check if the HDF5 makes sense: if (num_sinos == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Get flat and darks from cache or from file: skipflat = False skipdark = False if not dynamic_ff: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, flat_end, logfilename) if (isscalar(corrplan['im_flat']) and isscalar(corrplan['im_flat_after'])): skipflat = True else: plan2cache(corrplan, infile, tmppath) else: # Dynamic flat fielding: if "/tomo" in f_in: if "/flat" in f_in: flat_dset = f_in['flat'] if "/dark" in f_in: im_dark = _medianize(f_in['dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case else: if "/exchange/data_white" in f_in: flat_dset = f_in['/exchange/data_white'] if "/exchange/data_dark" in f_in: im_dark = _medianize(f_in['/exchange/data_dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat: EFF, filtEFF = dff_prepare_plan(flat_dset, 16, im_dark) # Read input image: im = tdf.read_sino(dset, idx).astype(float32) f_in.close() # Perform pre-processing (flat fielding, extended FOV, ring removal): if not skipflat: if dynamic_ff: # Dynamic flat fielding with downsampling = 2: im = dynamic_flat_fielding(im, idx, EFF, filtEFF, 2, im_dark, norm_sx, norm_dx) else: im = flat_fielding(im, idx, corrplan, flat_end, half_half, half_half_line, norm_sx, norm_dx) if ext_fov: im = extfov_correction(im, ext_fov_rot_right, ext_fov_overlap, ext_fov_normalize, ext_fov_average) if not skipflat and not dynamic_ff: im = ring_correction(im, ringrem, flat_end, corrplan['skip_flat_after'], half_half, half_half_line, ext_fov) else: im = ring_correction(im, ringrem, False, False, half_half, half_half_line, ext_fov) # Write down reconstructed preview file (file name modified with metadata): im = im.astype(float32) outfile = outfile + '_' + str(im.shape[1]) + 'x' + str( im.shape[0]) + '_' + str(nanmin(im)) + '$' + str(nanmax(im)) im.tofile(outfile)
def main(argv): """To do... """ lock = Lock() skip_flat = True first_done = False pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # Get full paths of input TDF and output TDF: infile = argv[2] outfile = argv[3] # Get the phase retrieval parameters: method = int(argv[4]) param1 = double(argv[5]) # e.g. regParam, or beta param2 = double(argv[6]) # e.g. thresh or delta energy = double(argv[7]) distance = double(argv[8]) pixsize = double(argv[9]) / 1000.0 # pixsixe from micron to mm: pad = True if argv[10] == "True" else False # Number of threads (actually processes) to use and logfile: nr_threads = int(argv[11]) logfilename = argv[12] # Log infos: log = open(logfilename, "w") log.write(linesep + "\tInput TDF file: %s" % (infile)) log.write(linesep + "\tOutput TDF file: %s" % (outfile)) log.write(linesep + "\t--------------") if (method == 0): log.write(linesep + "\tMethod: TIE-Hom (Paganin et al., 2002)") log.write(linesep + "\t--------------") log.write(linesep + "\tDelta/Beta: %0.1f" % ((param2 / param1))) elif (method == 1): log.write(linesep + "\tMethod: Generalized TIE-Hom (Paganin et al., 2020)") log.write(linesep + "\t--------------") log.write(linesep + "\tDelta/Beta: %0.1f" % ((param2 / param1))) else: log.write(linesep + "\tMethod: Projected CTF (Moosmann et al., 2011)") log.write(linesep + "\t--------------") log.write(linesep + "\tRegularization: %0.3f" % (param2)) log.write(linesep + "\tThreshold: %0.3f" % (param1)) log.write(linesep + "\tEnergy: %0.1f keV" % (energy)) log.write(linesep + "\tDistance: %0.1f mm" % (distance)) log.write(linesep + "\tPixel size: %0.3f micron" % (pixsize * 1000)) log.write(linesep + "\t--------------") log.write(linesep + "\tBrowsing input files...") log.close() # Remove a previous copy of output: if exists(outfile): remove(outfile) # Open the HDF5 file: f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) if (num_proj == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() log = open(logfilename, "a") log.write(linesep + "\tInput files browsed correctly.") log.close() # Check extrema (int_to == -1 means all files): if ((int_to >= num_proj) or (int_to == -1)): int_to = num_proj - 1 if ((int_from < 0)): int_from = 0 # Prepare the plan: log = open(logfilename, "a") log.write(linesep + "\tPreparing the work plan...") log.close() im = tdf.read_tomo(dset, 0).astype(float32) outshape = tdf.get_dset_shape(im.shape[1], im.shape[0], num_proj) f_out = getHDF5(outfile, 'w') f_out_dset = f_out.create_dataset('exchange/data', outshape, float32) f_out_dset.attrs['min'] = str(amin(im[:])) f_out_dset.attrs['max'] = str(amax(im[:])) f_out_dset.attrs['version'] = '1.0' f_out_dset.attrs['axes'] = "y:theta:x" f_in.close() f_out.close() if (method == 0): # Paganin 2020: plan = tiehom_plan(im, param1, param2, energy, distance, pixsize, pad) elif (method == 1): # Paganin 2020: plan = tiehom_plan2020(im, param1, param2, energy, distance, pixsize, pad) else: plan = phrt_plan(im, energy, distance, pixsize, param2, param1, method, pad) # Run several threads for independent computation without waiting for threads completion: for num in range(nr_threads): start = (num_proj / nr_threads) * num if (num == nr_threads - 1): end = num_proj - 1 else: end = (num_proj / nr_threads) * (num + 1) - 1 Process(target=_process, args=(lock, start, end, infile, outfile, outshape, float32, method, plan, logfilename)).start()
def main(argv): """Try to guess the amount of overlap in the case of extended FOV CT. Parameters ---------- infile : array_like HDF5 input dataset outfile : string Full path where the identified overlap will be written as output scale : int If sub-pixel precision is interesting, use e.g. 2.0 to get an overlap of .5 value. Use 1.0 if sub-pixel precision is not required tmppath : int Temporary path where look for cached flat/dark files """ # Get path: infile = argv[0] # The HDF5 file on the SSD outfile = argv[1] # The txt file with the proposed center scale = float(argv[2]) tmppath = argv[3] if not tmppath.endswith(sep): tmppath += sep # Create a silly temporary log: tmplog = tmppath + basename(infile) + str(time.time()) # Open the HDF5 file: f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) # Get first and 180 deg projections: im1 = tdf.read_tomo(dset, 0).astype(float32) im2 = tdf.read_tomo(dset, num_proj / 2).astype(float32) # Get flats and darks from cache or from file: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, tmplog) remove(tmplog) plan2cache(corrplan, infile, tmppath) # Apply simple flat fielding (if applicable): if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)): im1 = ((abs(im1 - corrplan['im_dark'])) / (abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps)).astype(float32) im2 = ((abs(im2 - corrplan['im_dark_after'])) / (abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps)).astype(float32) # Scale projections (if required) to get subpixel estimation: if (abs(scale - 1.0) > finfo(float32).eps): im1 = imresize(im1, (int(round( scale * im1.shape[0])), int(round(scale * im1.shape[1]))), interp='bicubic', mode='F') im2 = imresize(im2, (int(round( scale * im2.shape[0])), int(round(scale * im2.shape[1]))), interp='bicubic', mode='F') # Find the center (flipping left-right im2): DISTINGUISH BETWEEN AIR ON THE RIGHT AND ON THE LEFT?????? cen = findcenter.usecorrelation(im1, im2[:, ::-1]) cen = (cen / scale) * 2.0 # Print center to output file: text_file = open(outfile, "w") text_file.write(str(int(abs(cen)))) text_file.close() # Close input HDF5: f_in.close()
def main(argv): """To do... Usage ----- Parameters --------- Example -------------------------- The following line processes the first ten TIFF files of input path "/home/in" and saves the processed files to "/home/out" with the application of the Boin and Haibel filter with smoothing via a Butterworth filter of order 4 and cutoff frequency 0.01: destripe /home/in /home/out 1 10 1 0.01 4 """ lock = Lock() rescale_factor = 10000.0 # For 16-bit floating point # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # Get paths: infile = argv[2] outfile = argv[3] # Params for flat fielding with post flats/darks: flat_end = True if argv[4] == "True" else False half_half = True if argv[5] == "True" else False half_half_line = int(argv[6]) # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[7] == "True" else False # Parameters for rotation: rotation = float(argv[8]) interp = argv[9] border = argv[10] # Nr of threads and log file: nr_threads = int(argv[11]) logfilename = argv[12] # Log input parameters: log = open(logfilename, "w") log.write(linesep + "\tInput TDF file: %s" % (infile)) log.write(linesep + "\tOutput TDF file: %s" % (outfile)) log.write(linesep + "\t--------------") log.write(linesep + "\tOpening input dataset...") log.close() # Remove a previous copy of output: if exists(outfile): remove(outfile) # Open the HDF5 file: f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] tomoprefix = 'tomo' flatprefix = 'flat' darkprefix = 'dark' else: dset = f_in['exchange/data'] if "/provenance/detector_output" in f_in: prov_dset = f_in['provenance/detector_output'] tomoprefix = prov_dset.attrs['tomo_prefix'] flatprefix = prov_dset.attrs['flat_prefix'] darkprefix = prov_dset.attrs['dark_prefix'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) if (num_sinos == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Check extrema (int_to == -1 means all files): if ((int_to >= num_proj) or (int_to == -1)): int_to = num_proj - 1 # Prepare the work plan for flat and dark images: log = open(logfilename, "a") log.write(linesep + "\t--------------") log.write(linesep + "\tPreparing the work plan...") log.close() # Extract flat and darks: skipflat = False skipdark = False # Following variables make sense only for dynamic flat fielding: EFF = -1 filtEFF = -1 im_dark = -1 # Following variable makes sense only for conventional flat fielding: plan = -1 if not dynamic_ff: plan = extract_flatdark(f_in, flat_end, logfilename) if (isscalar(plan['im_flat']) and isscalar(plan['im_flat_after'])): skipflat = True else: skipflat = False else: # Dynamic flat fielding: if "/tomo" in f_in: if "/flat" in f_in: flat_dset = f_in['flat'] if "/dark" in f_in: im_dark = _medianize(f_in['dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case else: if "/exchange/data_white" in f_in: flat_dset = f_in['/exchange/data_white'] if "/exchange/data_dark" in f_in: im_dark = _medianize(f_in['/exchange/data_dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat: EFF, filtEFF = dff_prepare_plan(flat_dset, 16, im_dark) # Get the corrected outshape (in this case it's easy): im = tdf.read_tomo(dset, 0).astype(float32) outshape = tdf.get_dset_shape(im.shape[1], im.shape[0], num_proj) # Create the output HDF5 file: f_out = getHDF5(outfile, 'w') #f_out_dset = f_out.create_dataset('exchange/data', outshape, im.dtype) f_out_dset = f_out.create_dataset('exchange/data', outshape, float16) f_out_dset.attrs['min'] = str(amin(im[:])) f_out_dset.attrs['max'] = str(amax(im[:])) f_out_dset.attrs['version'] = '1.0' f_out_dset.attrs['axes'] = "y:theta:x" f_out_dset.attrs['rescale_factor'] = str(rescale_factor) f_out.close() f_in.close() # Log infos: log = open(logfilename, "a") log.write(linesep + "\tWork plan prepared correctly.") log.write(linesep + "\t--------------") log.write(linesep + "\tPerforming pre processing...") log.close() # Run several threads for independent computation without waiting for threads # completion: for num in range(nr_threads): start = (num_proj / nr_threads) * num if (num == nr_threads - 1): end = num_proj - 1 else: end = (num_proj / nr_threads) * (num + 1) - 1 Process(target=_process, args=(lock, start, end, infile, outfile, outshape, float16, skipflat, plan, flat_end, half_half, half_half_line, dynamic_ff, EFF, filtEFF, im_dark, rotation, interp, border, rescale_factor, logfilename)).start()
def main(argv): """To do... """ lock = Lock() skip_flat = True first_done = False pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Get the from and to number of files to process: idx = int(argv[0]) # Get full paths of input TDF and output TDF: infile = argv[1] outfile = argv[2] # Get the phase retrieval parameters: method = int(argv[3]) param1 = double(argv[4]) # param1( e.g. regParam, or beta) param2 = double(argv[5]) # param2( e.g. thresh or delta) energy = double(argv[6]) distance = double(argv[7]) pixsize = double(argv[8]) / 1000.0 # pixsixe from micron to mm: pad = True if argv[9] == "True" else False # Tmp path and log file: tmppath = argv[10] if not tmppath.endswith(sep): tmppath += sep logfilename = argv[11] # Open the HDF5 file and check it contains flat files: skipflat = False f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] if not "/flat" in f_in: skipflat = True else: dset = f_in['exchange/data'] if not "/exchange/data_white" in f_in: skipflat = True num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Check if the HDF5 makes sense: if (num_proj == 0): log = open(logfilename, "a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Get flats and darks from cache or from file: if not skipflat: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, logfilename) remove(logfilename) plan2cache(corrplan, infile, tmppath) # Read projection: im = tdf.read_tomo(dset, idx).astype(float32) f_in.close() # Apply simple flat fielding (if applicable): if not skipflat: if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)): if (idx < num_proj / 2): im = (im - corrplan['im_dark']) / ( abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps) else: im = (im - corrplan['im_dark_after']) / ( abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps) # Prepare plan: im = im.astype(float32) if (method == 0): # Paganin 2002: plan = tiehom_plan(im, param1, param2, energy, distance, pixsize, pad) im = tiehom(im, plan).astype(float32) elif (method == 1): # Paganin 2020: plan = tiehom_plan2020(im, param1, param2, energy, distance, pixsize, pad) im = tiehom2020(im, plan).astype(float32) else: plan = phrt_plan(im, energy, distance, pixsize, param2, param1, method, pad) im = phrt(im, plan, method).astype(float32) # Write down reconstructed preview file (file name modified with metadata): im = im.astype(float32) outfile = outfile + '_' + str(im.shape[1]) + 'x' + str( im.shape[0]) + '_' + str(nanmin(im)) + '$' + str(nanmax(im)) im.tofile(outfile)
def main(argv): """To do... Usage ----- Parameters --------- Example -------------------------- The following line processes the first ten TIFF files of input path "/home/in" and saves the processed files to "/home/out" with the application of the Boin and Haibel filter with smoothing via a Butterworth filter of order 4 and cutoff frequency 0.01: destripe /home/in /home/out 1 10 1 0.01 4 """ lock = Lock() rescale_factor = 10000.0 # For 16-bit floating point # Get the from and to number of files to process: int_from = int(argv[0]) int_to = int(argv[1]) # Get paths: infile = argv[2] outfile = argv[3] # Params for flat fielding with post flats/darks: flat_end = True if argv[4] == "True" else False half_half = True if argv[5] == "True" else False half_half_line = int(argv[6]) # Flat fielding method (conventional or dynamic): dynamic_ff = True if argv[7] == "True" else False # Parameters for rotation: rotation = float(argv[8]) interp = argv[9] border = argv[10] # Nr of threads and log file: nr_threads = int(argv[11]) logfilename = argv[12] # Log input parameters: log = open(logfilename,"w") log.write(linesep + "\tInput TDF file: %s" % (infile)) log.write(linesep + "\tOutput TDF file: %s" % (outfile)) log.write(linesep + "\t--------------") log.write(linesep + "\tOpening input dataset...") log.close() # Remove a previous copy of output: if exists(outfile): remove(outfile) # Open the HDF5 file: f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] tomoprefix = 'tomo' flatprefix = 'flat' darkprefix = 'dark' else: dset = f_in['exchange/data'] if "/provenance/detector_output" in f_in: prov_dset = f_in['provenance/detector_output'] tomoprefix = prov_dset.attrs['tomo_prefix'] flatprefix = prov_dset.attrs['flat_prefix'] darkprefix = prov_dset.attrs['dark_prefix'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) if (num_sinos == 0): log = open(logfilename,"a") log.write(linesep + "\tNo projections found. Process will end.") log.close() exit() # Check extrema (int_to == -1 means all files): if ((int_to >= num_proj) or (int_to == -1)): int_to = num_proj - 1 # Prepare the work plan for flat and dark images: log = open(logfilename,"a") log.write(linesep + "\t--------------") log.write(linesep + "\tPreparing the work plan...") log.close() # Extract flat and darks: skipflat = False skipdark = False # Following variables make sense only for dynamic flat fielding: EFF = -1 filtEFF = -1 im_dark = -1 # Following variable makes sense only for conventional flat fielding: plan = -1 if not dynamic_ff: plan = extract_flatdark(f_in, flat_end, logfilename) if (isscalar(plan['im_flat']) and isscalar(plan['im_flat_after'])): skipflat = True else: skipflat = False else: # Dynamic flat fielding: if "/tomo" in f_in: if "/flat" in f_in: flat_dset = f_in['flat'] if "/dark" in f_in: im_dark = _medianize(f_in['dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case else: if "/exchange/data_white" in f_in: flat_dset = f_in['/exchange/data_white'] if "/exchange/data_dark" in f_in: im_dark = _medianize(f_in['/exchange/data_dark']) else: skipdark = True else: skipflat = True # Nothing to do in this case # Prepare plan for dynamic flat fielding with 16 repetitions: if not skipflat: EFF, filtEFF = dff_prepare_plan(flat_dset, 16, im_dark) # Get the corrected outshape (in this case it's easy): im = tdf.read_tomo(dset,0).astype(float32) outshape = tdf.get_dset_shape(im.shape[1], im.shape[0], num_proj) # Create the output HDF5 file: f_out = getHDF5(outfile, 'w') #f_out_dset = f_out.create_dataset('exchange/data', outshape, im.dtype) f_out_dset = f_out.create_dataset('exchange/data', outshape, float16) f_out_dset.attrs['min'] = str(amin(im[:])) f_out_dset.attrs['max'] = str(amax(im[:])) f_out_dset.attrs['version'] = '1.0' f_out_dset.attrs['axes'] = "y:theta:x" f_out_dset.attrs['rescale_factor'] = str(rescale_factor) f_out.close() f_in.close() # Log infos: log = open(logfilename,"a") log.write(linesep + "\tWork plan prepared correctly.") log.write(linesep + "\t--------------") log.write(linesep + "\tPerforming pre processing...") log.close() # Run several threads for independent computation without waiting for threads # completion: for num in range(nr_threads): start = (num_proj / nr_threads) * num if (num == nr_threads - 1): end = num_proj - 1 else: end = (num_proj / nr_threads) * (num + 1) - 1 Process(target=_process, args=(lock, start, end, infile, outfile, outshape, float16, skipflat, plan, flat_end, half_half, half_half_line, dynamic_ff, EFF, filtEFF, im_dark, rotation, interp, border, rescale_factor, logfilename)).start()
def main(argv): """Try to guess the center of rotation of the input CT dataset. Parameters ---------- infile : array_like HDF5 input dataset outfile : string Full path where the identified center of rotation will be written as output scale : int If sub-pixel precision is interesting, use e.g. 2.0 to get a center of rotation of .5 value. Use 1.0 if sub-pixel precision is not required angles : int Total number of angles of the input dataset proj_from : int Initial projections to consider for the assumed angles proj_to : int Final projections to consider for the assumed angles method : string (not implemented yet) tmppath : string Temporary path where look for cached flat/dark files """ # Get path: infile = argv[0] # The HDF5 file on the outfile = argv[1] # The txt file with the proposed center scale = float(argv[2]) angles = float(argv[3]) proj_from = int(argv[4]) proj_to = int(argv[5]) method = argv[6] tmppath = argv[7] if not tmppath.endswith(sep): tmppath += sep pyfftw_cache_disable() pyfftw_cache_enable() pyfftw_set_keepalive_time(1800) # Create a silly temporary log: tmplog = tmppath + basename(infile) + str(time.time()) # Open the HDF5 file (take into account also older TDF versions): f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] num_proj = tdf.get_nr_projs(dset) num_sinos = tdf.get_nr_sinos(dset) # Get flats and darks from cache or from file: try: corrplan = cache2plan(infile, tmppath) except Exception as e: #print "Error(s) when reading from cache" corrplan = extract_flatdark(f_in, True, tmplog) remove(tmplog) plan2cache(corrplan, infile, tmppath) # Get first and the 180 deg projections: im1 = tdf.read_tomo(dset, proj_from).astype(float32) idx = int(round((proj_to - proj_from) / angles * pi)) + proj_from im2 = tdf.read_tomo(dset, idx).astype(float32) # Apply simple flat fielding (if applicable): if (isinstance(corrplan['im_flat_after'], ndarray) and isinstance(corrplan['im_flat'], ndarray) and isinstance(corrplan['im_dark'], ndarray) and isinstance(corrplan['im_dark_after'], ndarray)): im1 = ((abs(im1 - corrplan['im_dark'])) / (abs(corrplan['im_flat'] - corrplan['im_dark']) + finfo(float32).eps)).astype(float32) im2 = ((abs(im2 - corrplan['im_dark_after'])) / (abs(corrplan['im_flat_after'] - corrplan['im_dark_after']) + finfo(float32).eps)).astype(float32) # Scale projections (if required) to get subpixel estimation: if (abs(scale - 1.0) > finfo(float32).eps): im1 = imresize(im1, (int(round( scale * im1.shape[0])), int(round(scale * im1.shape[1]))), interp='bicubic', mode='F') im2 = imresize(im2, (int(round( scale * im2.shape[0])), int(round(scale * im2.shape[1]))), interp='bicubic', mode='F') # Find the center (flipping left-right im2): cen = findcenter.usecorrelation(im1, im2[:, ::-1]) cen = cen / scale # Print center to output file: text_file = open(outfile, "w") text_file.write(str(int(cen))) text_file.close() # Close input HDF5: f_in.close()