def run(self): if self.movdir.is_file(): moving_imgs = [self.movdir] else: moving_imgs = common.get_file_paths( self.movdir, ignore_folder=RESOLUTION_IMG_FOLDER ) # This breaks if not ran from config dir if len(moving_imgs) < 1: raise common.LamaDataException("No volumes in {}".format( self.movdir)) for mov in moving_imgs: mov_basename = mov.stem outdir = self.stagedir / mov_basename outdir.mkdir(parents=True) cmd = { 'mov': str(mov), 'fixed': str(self.fixed), 'outdir': str(outdir), 'elxparam_file': str(self.elxparam_file), 'threads': self.threads, 'fixed': str(self.fixed) } if self.fixed_mask is not None: cmd['fixed_mask'] = str(self.fixed_mask) run_elastix(cmd) # Rename the registered output. elx_outfile = outdir / f'result.0.{self.filetype}' new_out_name = outdir / f'{mov_basename}.{self.filetype}' try: shutil.move(elx_outfile, new_out_name) except IOError: logging.error( 'Cannot find elastix output. Ensure the following is not set: (WriteResultImage "false")' ) raise move_intemediate_volumes(outdir) # add registration metadata reg_metadata_path = outdir / common.INDV_REG_METADATA fixed_vol_relative = relpath(self.fixed, outdir) reg_metadata = {'fixed_vol': fixed_vol_relative} with open(reg_metadata_path, 'w') as fh: fh.write(yaml.dump(reg_metadata, default_flow_style=False))
def pad_volumes(indirs: Iterable[Path], max_dims: Tuple, outdir: Path, clobber: bool, filetype: str = 'nrrd'): """ Pad volumes, masks, labels. Output files will have same name as original, but be in a new output folder Parameters ---------- indirs one or more directories containing volumes to pad (Will search subdirectories for volumes) max_dims dimensions to pad to (z, y, x) outdir path to output dir """ if clobber and outdir: print('Specifiy either --clobber or an output dir (-o)') return if not clobber and not outdir: print('Specifiy either --clobber or an output dir (-o)') return if not max_dims: max_dims = get_largest_dimensions(indirs) print(f'Zero padding to {max_dims}') outdir = outdir for dir_ in indirs: dir_ = Path(dir_) if clobber: result_dir = dir_ else: result_dir = outdir / dir_.name result_dir.mkdir(exist_ok=True, parents=True) volpaths = common.get_file_paths(dir_) # print('Padding to {} - {} volumes/masks:'.format(str(max_dims), str(len(volpaths)))) # pad_info = Dict() for path in volpaths: if clobber: outpath = path else: outpath = result_dir / path.name loader = common.LoadImage(path) vol = loader.img if not vol: logging.error('error loading image for padding: {}'.format( loader.error_msg)) sys.exit() vol_dims = vol.GetSize() # The voxel differences between the vol dims and the max dims diffs = [m - v for m, v in zip(max_dims, vol_dims)] # How many pixels to add to the upper bounds of each dimension, divide by two and round down to nearest int upper_extend = [d // 2 for d in diffs] # In case of differnces that cannot be /2. Get the remainder to add to the lower bound remainders = [d % 2 for d in diffs] # Add the remainders to the upper bound extension to get the lower bound extension lower_extend = [u + r for u, r in zip(upper_extend, remainders)] # if any values are negative, stop. We need all volumes to be the same size for ex_val in zip(lower_extend, upper_extend): if ex_val[0] < 0 or ex_val[1] < 0: msg = ( "\ncan't pad images\n" "{} is larger than the specified volume size\n" "Current vol size:{},\n" "Max vol size: {}" "\nCheck the 'pad_dims' in the config file\n".format( basename(path), str(vol_dims), str(max_dims))) logging.error(msg) raise common.LamaDataException(msg) # Pad the volume. New pixels set to zero padded_vol = sitk.ConstantPad(vol, upper_extend, lower_extend, 0) padded_vol.SetOrigin((0, 0, 0)) padded_vol.SetSpacing((1, 1, 1)) sitk.WriteImage(padded_vol, str(outpath), True) # pad_info['data'][input_basename]['pad'] = [upper_extend, lower_extend] print('Finished padding')
def run(self): # If inputs_vols is a file get the specified root and paths from it if isdir(self.movdir): movlist = common.get_file_paths(self.movdir) else: movlist = common.get_inputs_from_file_list(self.movdir, self.config_dir) if len(movlist) < 1: raise common.LamaDataException("No volumes in {}".format( self.movdir)) for fixed in movlist: # Todo: change variable name fixed to moving tp_file_paths = defaultdict(list) full_tp_file_paths = [] fixed_basename = splitext(basename(fixed))[0] fixed_dir = self.paths.make(join(self.stagedir, fixed_basename), 'f') for moving in movlist: if basename(fixed) == basename(moving): continue moving_basename = splitext(basename(moving))[0] outdir = join(fixed_dir, moving_basename) common.mkdir_force(outdir) run_elastix({ 'mov': moving, 'fixed': fixed, 'outdir': outdir, 'elxparam_file': self.elxparam_file, 'threads': self.threads, 'fixed': fixed }) # Get the resolution tforms tforms = list( sorted([ x for x in os.listdir(outdir) if x.startswith(REOLSUTION_TP_PREFIX) ])) # get the full tform that spans all resolutions full_tp_file_paths.append(join(outdir, FULL_STAGE_TP_FILENAME)) # Add the tforms to a resolution-specific list so we can generate deformations from any range # of deformations later for i, tform in enumerate(tforms): tp_file_paths[i].append(join(outdir, tform)) # add registration metadata reg_metadata_path = join(outdir, common.INDV_REG_METADATA) fixed_vol_relative = relpath(fixed, outdir) reg_metadata = {'fixed_vol': fixed_vol_relative} with open(reg_metadata_path, 'w') as fh: fh.write(yaml.dump(reg_metadata, default_flow_style=False)) for i, files_ in tp_file_paths.items(): mean_tfom_name = "{}{}.txt".format(REOLSUTION_TP_PREFIX, i) self.generate_mean_tranform(files_, fixed, fixed_dir, mean_tfom_name, self.filetype) self.generate_mean_tranform(full_tp_file_paths, fixed, fixed_dir, FULL_STAGE_TP_FILENAME, self.filetype)
def run(self): if self.movdir.is_file(): moving_imgs = [self.movdir] else: moving_imgs = common.get_file_paths( self.movdir, ignore_folders=[RESOLUTION_IMGS_DIR, IMG_PYRAMID_DIR ]) # This breaks if not ran from config dir if len(moving_imgs) < 1: raise common.LamaDataException("No volumes in {}".format( self.movdir)) for mov in moving_imgs: mov_basename = mov.stem outdir = self.stagedir / mov_basename outdir.mkdir(parents=True) cmd = { 'mov': str(mov), 'fixed': str(self.fixed), 'outdir': str(outdir), 'elxparam_file': str(self.elxparam_file), 'threads': self.threads, 'fixed': str(self.fixed) } if self.fixed_mask is not None: cmd['fixed_mask'] = str(self.fixed_mask) run_elastix(cmd) # Rename the registered output. if self.rename_output: elx_outfile = outdir / f'result.0.{self.filetype}' new_out_name = outdir / f'{mov_basename}.{self.filetype}' try: shutil.move(elx_outfile, new_out_name) except IOError: logging.error( 'Cannot find elastix output. Ensure the following is not set: (WriteResultImage "false")' ) raise move_intemediate_volumes(outdir) # add registration metadata reg_metadata_path = outdir / common.INDV_REG_METADATA fixed_vol_relative = relpath(self.fixed, outdir) reg_metadata = {'fixed_vol': fixed_vol_relative} with open(reg_metadata_path, 'w') as fh: fh.write(yaml.dump(reg_metadata, default_flow_style=False)) if self.fix_folding: # Remove any folds folds in the Bsplines, overwtite inplace tform_param_file = outdir / ELX_TRANSFORM_NAME unfold_bsplines(tform_param_file, tform_param_file) # Retransform the moving image with corrected tform file cmd = [ 'transformix', '-in', str(mov), '-out', str(outdir), '-tp', tform_param_file ] subprocess.call(cmd) unfolded_moving_img = outdir / 'result.nrrd' new_out_name.unlink() shutil.move(unfolded_moving_img, new_out_name)