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 _process(lock, int_from, int_to, infile, outfile, outshape, outtype, method, plan, logfilename): # Process the required subset of images: for i in range(int_from, int_to + 1): # Read input image: t0 = time() f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] im = tdf.read_tomo(dset,i).astype(float32) f_in.close() t1 = time() # Perform phase retrieval (first time also PyFFTW prepares a plan): if (method == 0): im = tiehom(im, plan).astype(float32) else: im = phrt(im, plan, method).astype(float32) t2 = time() # Save processed image to HDF5 file (atomic procedure - lock used): _write_data(lock, im, i, outfile, outshape, outtype, logfilename, t2 - t1, t1 - t0)
def _process(lock, int_from, int_to, infile, outfile, outshape, outtype, method, plan, logfilename): # Process the required subset of images: for i in range(int_from, int_to + 1): # Read input image: t0 = time() f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] im = tdf.read_tomo(dset, i).astype(float32) f_in.close() t1 = time() # Perform phase retrieval (first time also PyFFTW prepares a plan): if (method == 0): im = tiehom(im, plan).astype(float32) elif (method == 1): im = tiehom2020(im, plan).astype(float32) else: im = phrt(im, plan, method).astype(float32) t2 = time() # Save processed image to HDF5 file (atomic procedure - lock used): _write_data(lock, im, i, outfile, outshape, outtype, logfilename, t2 - t1, t1 - t0)
def _process(lock, int_from, int_to, infile, outfile, outshape, outtype, skipflat, plan, flat_end, half_half, half_half_line, dynamic_ff, EFF, filtEFF, im_dark, rotation, interp, border, rescale_factor, logfilename): # Process the required subset of images: for i in range(int_from, int_to + 1): # Read input image: t0 = time() f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] im = tdf.read_tomo(dset,i).astype(float32) f_in.close() t1 = time() # 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, i, plan, flat_end, half_half, half_half_line, norm_sx, norm_dx) t2 = time() # Rotate: rows, cols = im.shape #if (cols > rows): # angle = - arctan(2.0 / cols) * (rows / 2.0) / 2.0 #else: # angle = - arctan(2.0 / rows) * (cols / 2.0) / 2.0 #print(angle) 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) # Save processed image to HDF5 file (atomic procedure - lock used): _write_data(lock, im, i, outfile, outshape, outtype, rescale_factor, logfilename, t2 - t1, t1 - t0)
def _process(lock, int_from, int_to, infile, dset_str, TIFFFormat, projorder, outpath, outprefix, logfilename): """To do... """ try: f = getHDF5(infile, 'r') dset = f[dset_str] # Process the required subset of images: for i in range(int_from, int_to + 1): # Read input image: t0 = time.time() if projorder: im = tdf.read_tomo(dset, i) else: im = tdf.read_sino(dset, i) # Cast type (if required but it should never occur): if (((im.dtype).type is float64) or ((im.dtype).type is float16)): im = im.astype(float32, copy=False) if (TIFFFormat): fname = outpath + outprefix + '_' + str(i).zfill(4) + '.tif' imsave(fname, im) else: fname = outpath + outprefix + '_' + str(i).zfill(4) + '_' + str(im.shape[1]) + \ 'x' + str(im.shape[0]) + '_' + str(im.dtype) + '.raw' im.tofile(fname) t1 = time.time() # Print out execution time: _write_log(lock, fname, logfilename, t1 - t0) f.close() except Exception: pass
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... """ 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): """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 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 _medianize_withprovenance(dset, provenance_dset, tomoprefix, darkorflatprefix, flagafter): # Get minimum and max timestamps for projection min_t = maxint max_t = -1 for i in range(0, provenance_dset.shape[0]): if provenance_dset["filename", i].startswith(tomoprefix): t = int(mktime(datetime.strptime(provenance_dset["timestamp", i], "%Y-%m-%d %H:%M:%S.%f").timetuple())) if (t < min_t): min_t = t if (t > max_t): max_t = t flag_first = False ct = 0 im = read_tomo(dset,0).astype(float32) for i in range(0, provenance_dset.shape[0]): if provenance_dset["filename", i].startswith(darkorflatprefix): t = int(mktime(datetime.strptime(provenance_dset["timestamp", i], "%Y-%m-%d %H:%M:%S.%f").timetuple())) if flagafter: if (t > max_t): # Get "angle": name = splitext(provenance_dset["filename", i])[0] idx = int(name[-4:]) idx = idx - int(provenance_dset.attrs['first_index']) # Get image and sum it to the series: if not flag_first: flag_first = True im = read_tomo(dset,idx).astype(float32) ct = ct + 1 else: im = im + read_tomo(dset,idx).astype(float32) ct = ct + 1 else: if (t <= min_t): # Get "angle": name = splitext(provenance_dset["filename", i])[0] idx = int(name[-4:]) idx = idx - int(provenance_dset.attrs['first_index']) # Get image and sum it to the series: if not flag_first: flag_first = True im = read_tomo(dset,idx).astype(float32) else: im = im + read_tomo(dset,idx).astype(float32) ct = ct + 1 if ( ct > 0 ): im = im / ct return im.astype(float32) else: return -1 # Error:
def main(argv): """Extract a 2D image (projection or sinogram) from the input TDF file (DataExchange HDF5) and creates a 32-bit RAW file to disk. Parameters ---------- argv[0] : string The absolute path of the input TDF. argv[1] : int The relative position of the image within the dataset. argv[2] : string One of the following options: 'tomo', 'sino', 'flat', 'dark'. argv[3] : string The absolute path of the output 32-bit RAW image file. Filename will be modified by adding image width, image height, minimum and maximum value of the input TDF dataset. Example ------- tools_extractdata "S:\\dataset.tdf" 128 tomo "R:\\proj" """ try: # # Get input parameters: # infile = argv[0] index = int(argv[1]) imtype = argv[2] outfile = argv[3] # # Body # # Check if file exists: 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') if (imtype == 'sino'): if "/tomo" in f: dset = f['tomo'] else: dset = f['exchange/data'] im = tdf.read_sino(dset, index) elif (imtype == 'dark'): if "/dark" in f: dset = f['dark'] else: dset = f['exchange/data_dark'] im = tdf.read_tomo(dset, index) elif (imtype == 'flat'): if "/flat" in f: dset = f['flat'] else: dset = f['exchange/data_white'] im = tdf.read_tomo(dset, index) else: if "/tomo" in f: dset = f['tomo'] else: dset = f['exchange/data'] im = tdf.read_tomo(dset, index) # Remove Infs e NaNs tmp = im[:].astype(numpy.float32) tmp = tmp[numpy.nonzero(numpy.isfinite(tmp))] # Sort the gray levels: tmp = numpy.sort(tmp) # Return as minimum the value the skip 0.30% of "black" tail and 0.05% of "white" tail: low_idx = int(tmp.shape[0] * 0.0030) high_idx = int(tmp.shape[0] * 0.9995) min = tmp[low_idx] max = tmp[high_idx] # Modify file name: outfile = outfile + '_' + str(im.shape[1]) + 'x' + str( im.shape[0]) + '_' + str(min) + '$' + str(max) # Cast type: im = im.astype(float32) # Write RAW data to disk: im.tofile(outfile) except: exit()
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): """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... 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 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 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... """ # 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 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 _process(lock, int_from, int_to, infile, outfile, outshape, outtype, skipflat, plan, flat_end, half_half, half_half_line, dynamic_ff, EFF, filtEFF, im_dark, rotation, interp, border, rescale_factor, logfilename): # Process the required subset of images: for i in range(int_from, int_to + 1): # Read input image: t0 = time() f_in = getHDF5(infile, 'r') if "/tomo" in f_in: dset = f_in['tomo'] else: dset = f_in['exchange/data'] im = tdf.read_tomo(dset, i).astype(float32) f_in.close() t1 = time() # 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, i, plan, flat_end, half_half, half_half_line, norm_sx, norm_dx) t2 = time() # Rotate: rows, cols = im.shape #if (cols > rows): # angle = - arctan(2.0 / cols) * (rows / 2.0) / 2.0 #else: # angle = - arctan(2.0 / rows) * (cols / 2.0) / 2.0 #print(angle) 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) # Save processed image to HDF5 file (atomic procedure - lock used): _write_data(lock, im, i, outfile, outshape, outtype, rescale_factor, logfilename, t2 - t1, t1 - t0)
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): """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): """Extract a 2D image (projection or sinogram) from the input TDF file (DataExchange HDF5) and creates a 32-bit RAW file to disk. Parameters ---------- argv[0] : string The absolute path of the input TDF. argv[1] : int The relative position of the image within the dataset. argv[2] : string One of the following options: 'tomo', 'sino', 'flat', 'dark'. argv[3] : string The absolute path of the output 32-bit RAW image file. Filename will be modified by adding image width, image height, minimum and maximum value of the input TDF dataset. Example ------- tools_extractdata "S:\\dataset.tdf" 128 tomo "R:\\proj" """ try: # # Get input parameters: # infile = argv[0] index = int(argv[1]) imtype = argv[2] outfile = argv[3] # # Body # # Check if file exists: 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' ) if (imtype == 'sino'): if "/tomo" in f: dset = f['tomo'] else: dset = f['exchange/data'] im = tdf.read_sino( dset, index ) elif (imtype == 'dark'): if "/dark" in f: dset = f['dark'] else: dset = f['exchange/data_dark'] im = tdf.read_tomo( dset, index ) elif (imtype == 'flat'): if "/flat" in f: dset = f['flat'] else: dset = f['exchange/data_white'] im = tdf.read_tomo( dset, index ) else: if "/tomo" in f: dset = f['tomo'] else: dset = f['exchange/data'] im = tdf.read_tomo( dset, index ) # Remove Infs e NaNs tmp = im[:].astype(numpy.float32) tmp = tmp[numpy.nonzero(numpy.isfinite(tmp))] # Sort the gray levels: tmp = numpy.sort(tmp) # Return as minimum the value the skip 0.30% of "black" tail and 0.05% of "white" tail: low_idx = int(tmp.shape[0] * 0.0030) high_idx = int(tmp.shape[0] * 0.9995) min = tmp[low_idx] max = tmp[high_idx] # Modify file name: outfile = outfile + '_' + str(im.shape[1]) + 'x' + str(im.shape[0]) + '_' + str(min) + '$' + str(max) # Cast type: im = im.astype(float32) # Write RAW data to disk: im.tofile(outfile) except: exit()