def coil_combine(in_filepaths, out_filepaths, method='block_adaptive_iter', method_kws=None, compression='compress_svd', compression_kws=None, coil_axis=-1, split_axis=None, q_filepath=None, force=False, verbose=D_VERB_LVL): in_mag_filepath, in_phs_filepath = in_filepaths out_mag_filepath, out_phs_filepath = out_filepaths msg('Input-MAG: {}'.format(in_mag_filepath)) msg('Input-PHS: {}'.format(in_phs_filepath)) msg('Output-MAG: {}'.format(out_mag_filepath)) msg('Output-PHS: {}'.format(out_phs_filepath)) msg('Method: {}'.format(method)) msg('Compression: {}'.format(compression)) msg('Quality: {}'.format(q_filepath)) # in_filepaths = [in_mag_filepath, in_phs_filepath] # out_filepaths = [out_mag_filepath, out_phs_filepath] if fc.check_redo(in_filepaths, out_filepaths, force): mag_coils_arr, meta = mrt.input_output.load(in_mag_filepath, meta=True) phs_coils_arr = mrt.input_output.load(in_phs_filepath) coils_arr = fcn.polar2complex(mag_coils_arr, phs_coils_arr) del mag_coils_arr, phs_coils_arr arr = coils.combine(coils_arr, method=method, method_kws=method_kws, compression=compression, compression_kws=compression_kws, coil_axis=coil_axis, split_axis=split_axis, verbose=verbose) mag_arr, phs_arr = fc.complex2polar(arr) mrt.input_output.save(out_mag_filepath, mag_arr, **meta) mrt.input_output.save(out_phs_filepath, phs_arr, **meta) if fc.check_redo(out_filepaths, q_filepath): q_arr = coils.quality(coils_arr, arr, coil_axis=coil_axis, verbose=verbose) mrt.input_output.save(q_filepath, q_arr)
def calc_nii(in_dirpath, compress=True, force=False, verbose=D_VERB_LVL): """ Reconstruct MRI image from Bruker dataset with standard parameters. """ data_filepath = os.path.join(in_dirpath, 'fid') in_filename_list = 'method', 'acqp' in_filepath_list = [ os.path.join(in_dirpath, in_filename) for in_filename in in_filename_list ] out_dirpath = os.path.join(in_dirpath, 'pdata/1') out_filename_list = 'bildabs.nii.gz', 'bildphs.nii.gz' out_filepath_list = [ os.path.join(out_dirpath, out_filename) for out_filename in out_filename_list ] if os.path.exists(data_filepath): if fc.check_redo(in_filepath_list, out_filepath_list, force): # remove files checked by matlab reco to avoid new folders matlab_output = os.path.join(out_dirpath, 'bildabs.mat') if os.path.exists(matlab_output): os.remove(matlab_output) if verbose > VERB_LVL['none']: print('Target:\t{}'.format(in_dirpath)) cmd = [ 'matlab', '-nodesktop', '-nosplash', '-nojvm', '-r "calc_nii(\'{}\'); quit;"'.format(in_dirpath) ] cwd = os.path.expanduser('~') subprocess.call(cmd, cwd=cwd) if compress: for out_filepath in out_filepath_list: uncompressed = out_filepath[:-len('.gz')] if os.path.exists(uncompressed): subprocess.call(['gzip', '-f', uncompressed]) return out_filepath_list
def sample2d( arr, axis=None, start=None, stop=None, step=None, duration=10000, title=None, array_interval=None, ticks_limit=None, orientation=None, flip_ud=False, flip_lr=False, cmap=None, cbar_kws=None, cbar_txt=None, text_color=None, resolution=None, size_info=None, more_texts=None, more_elements=None, ax=None, save_filepath=None, save_kws=None, force=False, verbose=D_VERB_LVL): """ Plot a 2D sample image of a 3D array. Parameters ========== arr : ndarray The original 3D array. axis : int (optional) The slicing axis. If None, use the shortest one. step : int (optional) The slicing index. Must be 1 or more. title : str (optional) The title of the plot. array_interval : 2-tuple (optional) The (min, max) values interval. cmap : MatPlotLib ColorMap (optional) The colormap to be used for displaying the histogram. use_new_figure : bool (optional) Plot the histogram in a new figure. close_figure : bool (optional) Close the figure after saving (useful for batch processing). save_filepath : str (optional) The path to which the plot is to be saved. If unset, no output. Returns ======= sample : ndarray The sliced (N-1)D-array. plot : matplotlib.pyplot.Figure The figure object containing the plot. """ if arr.ndim != 3: raise IndexError('3D array required') fig, ax = mrt.plot._ensure_fig_ax(ax) n_frames = arr.shape[axis] if start is None: start = 0 if stop is None: stop = n_frames if step is None: step = 1 # prepare data sample = fcn.ndim_slice(arr, axis, start) if title: ax.set_title(title) if array_interval is None: array_interval = fcn.minmax(arr) if not text_color: text_color = 'k' ax.set_aspect('equal') mrt.plot._manage_ticks_limit(ticks_limit, ax) plots = [] datas = [] for i in range(start, stop, step): data = mrt.plot._reorient_2d( fcn.ndim_slice(arr, axis, i), orientation, flip_ud, flip_lr) pax = ax.imshow( data, cmap=cmap, vmin=array_interval[0], vmax=array_interval[1], animated=True) # include additional text if more_texts is not None: for text_kws in more_texts: ax.text(**dict(text_kws)) datas.append(data) if len(plots) <= 0: mrt.plot._manage_colorbar(cbar_kws, cbar_txt, ax, pax) plots.append([pax]) # print resolution information and draw a ruler mrt.plot._manage_resolution_info( size_info, resolution, data.shape, text_color, ax) mrt.plot._more_texts(more_texts, ax) mrt.plot._more_elements(more_elements, ax) mov = mpl.animation.ArtistAnimation(fig, plots, blit=False) if save_filepath and fc.check_redo(None, [save_filepath], force): fig.tight_layout() save_kws = {'fps': n_frames / step / duration / MSEC_IN_SEC} if save_kws is None: save_kws = {} save_kws.update(save_kws) mov.save(save_filepath, **dict(save_kws)) msg('Anim: {}'.format(save_filepath, verbose, VERB_LVL['medium'])) plt.close(fig) return datas, fig, mov
def trajectory_2d( trajectory, duration=10000, last_frame_duration=3000, support_intervals=None, plot_kws=(('marker', 'o'), ('linewidth', 1)), ticks_limit=None, title=None, more_texts=None, more_elements=None, ax=None, save_filepath=None, save_kws=None, force=False, verbose=D_VERB_LVL): n_dims, n_points = trajectory.shape if n_dims != 2: raise IndexError('2D trajectory required') if ax is None: fig = plt.figure() ax = fig.gca() else: fig = plt.gcf() if title: ax.set_title(title) if support_intervals is None: support_intervals = ( fcn.minmax(trajectory[0]), fcn.minmax(trajectory[1])) n_frames = int(n_points * (1 + last_frame_duration / duration)) data = trajectory if plot_kws is None: plot_kws = {} line, = ax.plot([], [], **dict(plot_kws)) # points = ax.scatter([], []) ax.grid() x_data, y_data = [], [] def data_gen(): for i in range(n_points): yield trajectory[0, i], trajectory[1, i] for i in range(n_frames - n_points): yield None, None def init(): xlim_size = np.ptp(support_intervals[0]) ylim_size = np.ptp(support_intervals[1]) ax.set_xlim( (support_intervals[0][0] - 0.1 * xlim_size, support_intervals[0][1] + 0.1 * xlim_size)) ax.set_ylim( (support_intervals[1][0] - 0.1 * ylim_size, support_intervals[1][1] + 0.1 * ylim_size)) del x_data[:] del y_data[:] line.set_data(x_data, y_data) # points.set_offsets(np.c_[x_data, y_data]) return line, # points def run(data_generator): # update the data x, y = data_generator x_data.append(x) y_data.append(y) line.set_data(x_data, y_data) # points.set_offsets(np.c_[x_data, y_data]) return line, # points mrt.plot._more_texts(more_texts, ax) mrt.plot._more_elements(more_elements, ax) mov = mpl.animation.FuncAnimation( fig, run, data_gen, init_func=init, save_count=n_frames, blit=False, repeat=False, repeat_delay=None, interval=duration / n_frames) if save_filepath and fc.check_redo(None, [save_filepath], force): fig.tight_layout() save_kws = dict( fps=n_frames / duration / MSEC_IN_SEC, save_count=n_frames) if save_kws is None: save_kws = {} save_kws.update(save_kws) mov.save(save_filepath, **dict(save_kws)) msg('Anim: {}'.format(save_filepath, verbose, VERB_LVL['medium'])) # plt.close(fig) return trajectory, fig, mov
def compute_generic(sources, out_dirpath, params=None, opts=None, force=False, verbose=D_VERB_LVL): """ Perform the specified computation on source files. Args: sources (list[str]): Directory containing data files. out_dirpath (str): Directory containing metadata files. params (dict): Parameters associated with the sources. opts (dict): Accepted options: - types (list[str]): List of image types to use for results. - mask: (Iterable[Iterable[int]): Slicing for each dimension. - adapt_mask (bool): adapt over- or under-sized mask. - dtype (str): data type to be used for the target images. - compute_func (str): function used for the computation. compute_func(images, params, compute_args, compute_kwargs) -> img_list, img_type_list - compute_args (list): additional positional parameters for compute_func - compute_kwargs (dict): additional keyword parameters for compute_func - affine_func (str): name of the function for affine computation: affine_func(affines, affine_args...) -> affine - affine_args (list): additional parameters for affine_func force (bool): Force calculation of output. verbose (int): Set level of verbosity. Returns: targets (): See Also: pymrt.computation.sources_generic, pymrt.computation.compute, pymrt.computation.D_OPTS """ # TODO: implement affine_func, affine_args, affine_kwargs? # get the num, name and seq from first source file opts = fc.join_(D_OPTS, opts) if params is None: params = {} if opts is None: opts = {} targets = [] info = mrt.naming.parse_filename(sources[0]) if 'ProtocolName' in params: info['name'] = params['ProtocolName'] for image_type in opts['types']: info['type'] = image_type targets.append(os.path.join(out_dirpath, mrt.naming.to_filename(info))) # perform the calculation if fc.check_redo(sources, targets, force): if verbose > VERB_LVL['none']: print('{}:\t{}'.format('Object', os.path.basename(info['name']))) if verbose >= VERB_LVL['medium']: print('Opts:\t{}'.format(json.dumps(opts))) images, affines = [], [] mask = tuple((slice(*dim) if dim is not None else slice(None)) for dim in opts['mask']) for source in sources: if verbose > VERB_LVL['none']: print('Source:\t{}'.format(os.path.basename(source))) if verbose > VERB_LVL['none']: print('Params:\t{}'.format(params)) image, affine, header = mrt.input_output.load(source, meta=True) # fix mask if shapes are different if opts['adapt_mask']: mask = tuple((mask[i] if i < len(mask) else slice(None)) for i in range(len(image.shape))) images.append(image[mask]) affines.append(affine) if 'compute_func' in opts: compute_func = eval(opts['compute_func']) if 'compute_args' not in opts: opts['compute_args'] = [] if 'compute_kwargs' not in opts: opts['compute_kwargs'] = {} img_list, aff_list, img_type_list, params_list = compute_func( images, affines, params, *opts['compute_args'], **opts['compute_kwargs']) else: img_list, aff_list, img_type_list = zip( *[(img, aff, img_type) for img, aff, img_type in zip( images, affines, itertools.cycle(opts['types']))]) params_list = ({}, ) * len(img_list) for target, target_type in zip(targets, opts['types']): for img, aff, img_type, params in \ zip(img_list, aff_list, img_type_list, params_list): if img_type == target_type: if 'dtype' in opts: img = img.astype(opts['dtype']) if params: for key, val in params.items(): target = mrt.naming.change_param_val( target, key, val) if verbose > VERB_LVL['none']: print('Target:\t{}'.format(os.path.basename(target))) mrt.input_output.save(target, img, affine=aff) break return targets
def batch_extract( dirpath, out_filename='niz/{scan_num}__{acq_method}_{scan_name}_{reco_flag}', out_dirpath=None, custom_reco=None, custom_reco_kws=None, fid_name='fid', dseq_name='2dseq', acqp_name='acqp', method_name='method', reco_name='reco', allowed_ext=('', 'gz'), force=False, verbose=D_VERB_LVL): """ Extract images from experiment folder. EXPERIMENTAL! Args: dirpath (str): out_filename (str|None): out_dirpath (str|None): custom_reco (str|None): Determines how results will be saved. Accepted values are: - 'mag_phs': saves magnitude and phase. - 're_im': saves real and imaginary parts. - 'cx': saves the complex data. custom_reco_kws (Mappable|None): fid_name (): dseq_name (): acqp_name (): method_name (): reco_name (): allowed_ext (): force (): verbose (): Returns: """ text = '\n'.join( ('EXPERIMENTAL!', 'Use at your own risk!', 'Known issues:', ' - orientation not adjusted to method (i.e. 0->RO, 1->PE, 2->SL)', ' - FOV is centered out', ' - voxel size is not set', '')) warnings.warn(text) if allowed_ext is None: allowed_ext = '' elif isinstance(allowed_ext, str): allowed_ext = (allowed_ext, ) fid_filepaths = sorted( fc.flistdir(_to_patterns(fid_name, allowed_ext), dirpath)) for fid_filepath in sorted(fid_filepaths): msg('FID: {}'.format(fid_filepath), verbose, D_VERB_LVL) fid_dirpath = os.path.dirname(fid_filepath) if out_dirpath is None: out_dirpath = dirpath out_filepath = os.path.join(out_dirpath, out_filename) acqp_filepath = _get_single(fid_dirpath, acqp_name, allowed_ext) method_filepath = _get_single(fid_dirpath, method_name, allowed_ext) dseq_filepaths = sorted( fc.flistdir(_to_patterns(dseq_name, allowed_ext), fid_dirpath)) reco_filepaths = sorted( fc.flistdir(_to_patterns(reco_name, allowed_ext), fid_dirpath)) acqp_s, acqp, acqp_c = jcampdx.read(acqp_filepath) method_s, method, method_c = jcampdx.read(method_filepath) scan_num, sample_id = _get_scan_num_sample_id(acqp_c) scan_name = fc.safe_filename(acqp['ACQ_scan_name']) acq_method = fc.safe_filename(acqp['ACQ_method']) reco_flag = mrt.naming.NEW_RECO_ID if custom_reco: load_info = _get_load_bin_info_fid(acqp, method) if custom_reco == 'cx': reco_flag = mrt.naming.ITYPES['cx'] cx_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(cx_filepath)): os.makedirs(os.path.dirname(cx_filepath)) if fc.check_redo( [fid_filepath, acqp_filepath, method_filepath], [cx_filepath], force): arr = _load_bin(fid_filepath, **load_info) arr = _reco_from_fid(arr, acqp, method, verbose=verbose) mrt.input_output.save(cx_filepath, arr) msg('CX: {}'.format(os.path.basename(cx_filepath)), verbose, D_VERB_LVL) elif custom_reco == 'mag_phs': reco_flag = mrt.naming.ITYPES['mag'] mag_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(mag_filepath)): os.makedirs(os.path.dirname(mag_filepath)) reco_flag = mrt.naming.ITYPES['phs'] phs_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(phs_filepath)): os.makedirs(os.path.dirname(phs_filepath)) if fc.check_redo( [fid_filepath, acqp_filepath, method_filepath], [mag_filepath, phs_filepath], force): reco_flag = mrt.naming.ITYPES['mag'] arr = _load_bin(fid_filepath, **load_info) arr = _reco_from_fid(arr, acqp, method, verbose=verbose) mrt.input_output.save(mag_filepath, np.abs(arr)) msg('MAG: {}'.format(os.path.basename(mag_filepath)), verbose, D_VERB_LVL) mrt.input_output.save(phs_filepath, np.angle(arr)) msg('PHS: {}'.format(os.path.basename(phs_filepath)), verbose, D_VERB_LVL) elif custom_reco == 're_im': reco_flag = mrt.naming.ITYPES['re'] re_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(re_filepath)): os.makedirs(os.path.dirname(re_filepath)) reco_flag = mrt.naming.ITYPES['im'] im_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(im_filepath)): os.makedirs(os.path.dirname(im_filepath)) if fc.check_redo( [fid_filepath, acqp_filepath, method_filepath], [re_filepath, im_filepath], force): arr = _load_bin(fid_filepath, **load_info) arr = _reco_from_fid(arr, acqp, method, verbose=verbose) mrt.input_output.save(re_filepath, np.abs(arr)) msg('RE: {}'.format(os.path.basename(re_filepath)), verbose, D_VERB_LVL) mrt.input_output.save(im_filepath, np.angle(arr)) msg('IM: {}'.format(os.path.basename(im_filepath)), verbose, D_VERB_LVL) else: text = 'Voxel data and shapes may be incorrect.' warnings.warn(text) for dseq_filepath, reco_filepath \ in zip(dseq_filepaths, reco_filepaths): reco_s, reco, reco_c = jcampdx.read(reco_filepath) reco_flag = _get_reco_num(reco_c) cx_filepath = fc.change_ext(fmtm(out_filepath), mrt.util.EXT['niz']) if not os.path.isdir(os.path.dirname(cx_filepath)): os.makedirs(os.path.dirname(cx_filepath)) load_info = _get_load_bin_info_reco(reco, method) if fc.check_redo([dseq_filepath, reco_filepath], [cx_filepath], force): arr = _load_bin(dseq_filepath, **load_info) arr = _reco_from_bin(arr, reco, method, verbose=verbose) mrt.input_output.save(cx_filepath, arr) msg('NIZ: {}'.format(os.path.basename(cx_filepath)), verbose, D_VERB_LVL)
def wip(): # one-step QSM.. need for bias field removal? # convert input angles to radians # theta = np.deg2rad(theta) # phi = np.deg2rad(phi) # # k_x, k_y, k_z = coord(arr_cx.shape) # k_2 = (k_x ** 2 + k_y ** 2 + k_z ** 2) # cc = (k_z * np.cos(theta) * np.cos(phi) - # k_y * np.sin(theta) * np.cos(phi) + # k_x * np.sin(phi)) ** 2 # dd = 1 / (k_2 - cc) # dd = subst(dd) # chi_arr = np.abs(idftn(3 * k_2 * dd * dftn(phs_arr))) import os import datetime import pymrt.input_output begin_time = datetime.datetime.now() force = False base_path = '/home/raid1/metere/hd3/cache/qsm_coil_reco/COIL_RECO/' \ 'HJJT161103_nifti/0091_as_gre_nifti_TE17ms' mag_filepath = os.path.join(base_path, 'bai_mag.nii.gz') phs_filepath = os.path.join(base_path, 'bai_phs.nii.gz') msk_filepath = os.path.join(base_path, 'mask.nii.gz') mag_arr, meta = mrt.input_output.load(mag_filepath, meta=True) phs_arr = mrt.input_output.load(phs_filepath) msk_arr = mrt.input_output.load(msk_filepath).astype(bool) uphs_filepath = os.path.join(base_path, 'bai_uphs.nii.gz') if fc.check_redo(phs_filepath, uphs_filepath, force): from pymrt.recipes import phs uphs_arr = phs.unwrap(phs_arr) mrt.input_output.save(uphs_filepath, uphs_arr) else: uphs_arr = mrt.input_output.load(uphs_filepath) dphs_filepath = os.path.join(base_path, 'bai_dphs.nii.gz') if fc.check_redo(phs_filepath, dphs_filepath, force): from pymrt.recipes import phs dphs_arr = phs.phs_to_dphs(phs_arr, 20.0) mrt.input_output.save(dphs_filepath, uphs_arr) else: dphs_arr = mrt.input_output.load(dphs_filepath) db0_filepath = os.path.join(base_path, 'bai_db0.nii.gz') if fc.check_redo(dphs_filepath, db0_filepath, force): from pymrt.recipes import db0 db0_arr = db0.dphs_to_db0(dphs_arr, b0=2.89362) mrt.input_output.save(db0_filepath, db0_arr) else: db0_arr = mrt.input_output.load(db0_filepath) # milf_filepath = os.path.join(base_path, 'bai_db0i_milf.nii.gz') # if fc.check_redo(db0_filepath, milf_filepath, force): # from pymrt.recipes import phs # # milf_arr = qsm_remove_background_milf(uphs_arr, msk_arr) # mrt.input_output.save(milf_filepath, milf_arr) # msg('MILF') # else: # milf_arr = mrt.input_output.load(milf_filepath) # sharp_filepath = os.path.join(base_path, 'bai_db0i_sharp.nii.gz') # if fc.check_redo(uphs_filepath, sharp_filepath, force): # from pymrt.recipes import phs # import scipy.ndimage # # radius = 5 # mask_arr = sp.ndimage.binary_erosion(msk_arr, iterations=radius * 4) # sharp_arr = qsm_remove_background_sharp( # uphs_arr, mask_arr, radius, rel_radius=False) # mrt.input_output.save(sharp_filepath, sharp_arr) # msg('SHARP') # else: # sharp_arr = mrt.input_output.load(sharp_filepath) chi_filepath = os.path.join(base_path, 'bai_chi_ptfi_minres_i0128.nii.gz') if fc.check_redo(db0_filepath, chi_filepath, force): from pymrt.recipes import db0 mask = mag_arr > 0.5 w_arr = mag_arr**2 # 1 / (chi_x / chi_water) # non-water is assumed to be air pc_arr = np.full(mag_arr.shape, abs(CHI_V['water'] / CHI_V['air'])) # mask is assumed to be mostly water pc_arr[mask] = abs(CHI_V['water'] / CHI_V['water']) chi_arr = qsm_total_field_inversion(db0_arr, w_arr, msk_arr, pc_arr, linsolve_iter_kws=dict( method='minres', max_iter=128)) mrt.input_output.save(chi_filepath, chi_arr) else: chi_arr = mrt.input_output.load(chi_filepath) # chi_filepath = os.path.join(base_path, 'bai_chi_tfi_lsmr.nii.gz') # if fc.check_redo(db0_filepath, chi_filepath, force): # from pymrt.recipes import db0 # # chi_arr = qsm_total_field_inversion( # db0_arr, mag_arr, msk_arr, # linsolve_iter_kws=dict(method='lsmr', max_iter=256)) # mrt.input_output.save(chi_filepath, chi_arr) # else: # chi_arr = mrt.input_output.load(chi_filepath) msg('TotTime: {}'.format(datetime.datetime.now() - begin_time))