def flipAndSaveToRAS(filename): #Recover the image object imageObj = nib.load(filename) #Get the current orientation CurrentOrientation = nib.aff2axcodes(imageObj.affine) print("The current orientation is : ", CurrentOrientation) #Check if the current orientation is already RAS+ if CurrentOrientation == ('R', 'A', 'S'): print( "Image already recorded into the RAS+ orientation, nothing to do") return filename else: #Flip the image to RAS flippedImage = nib.as_closest_canonical(imageObj) ##Check the new orientation NewOrientation = nib.aff2axcodes(flippedImage.affine) #Set Qcode to 1 that the Qform matrix can be used into the further processing flippedImage.header['qform_code'] = 1 #Save the flipped image nib.save(flippedImage, RASFile) print("The new orientation is now : ", NewOrientation) return RASFile
def reorient_images(self): if (self.reorient_flag): print( "Reorient flag is set to true, Hence reorienting both images to Right Anterior Superior" ) canonical_img_1 = nb.as_closest_canonical(self.orig_nii_stationary) print(" ============= ============== ===================") print("orientation changed t1 affine: {}".format( canonical_img_1.affine)) print(" ============= ============== ===================") print("orientation changed t1 : {}".format( nb.aff2axcodes(canonical_img_1.affine))) print(" ============= ============== ===================") canonical_img_2 = nb.as_closest_canonical(self.orig_nii_moving) print(" ============= ============== ===================") print("orientation changed t2 affine: {}".format( canonical_img_2.affine)) print(" ============= ============== ===================") print("orientation changed t1 : {}".format( nb.aff2axcodes(canonical_img_2.affine))) print(" ============= ============== ===================") self.canonical_img_1 = canonical_img_1 self.canonical_img_2 = canonical_img_2 return self.canonical_img_1, self.canonical_img_2 else: print(" ============= ============== ===================") print("Not reorienting the images as reorient flag is false") print(" ============= ============== ===================") self.canonical_img_1 = orig_nii_stationary self.canonical_img_2 = orig_nii_moving return self.canonical_img_1, self.canonical_img_2
def _reorient_image(img, *, target_img=None, orientation=None): """ Coerce an image to a target orientation. .. note:: Only RAS -> LAS conversion is currently supported Parameters ---------- img : :obj:`SpatialImage` image to be reoriented target_img : :obj:`SpatialImage`, optional target in desired orientation orientation : :obj:`str` or :obj:`tuple`, optional desired orientation, if no target image is provided .. testsetup:: >>> img = nb.load(Path(test_data) / 'testRobustMNINormalizationRPTMovingWarpedImage.nii.gz') >>> las_img = img.as_reoriented([[0, -1], [1, 1], [2, 1]]) Examples -------- >>> nimg = _reorient_image(img, target_img=img) >>> nb.aff2axcodes(nimg.affine) ('R', 'A', 'S') >>> nimg = _reorient_image(img, target_img=las_img) >>> nb.aff2axcodes(nimg.affine) ('L', 'A', 'S') >>> nimg = _reorient_image(img, orientation='LAS') >>> nb.aff2axcodes(nimg.affine) ('L', 'A', 'S') >>> _reorient_image(img, orientation='LPI') Traceback (most recent call last): ... NotImplementedError: Cannot reorient ... >>> _reorient_image(img) Traceback (most recent call last): ... RuntimeError: No orientation ... """ orient0 = nb.aff2axcodes(img.affine) if target_img is not None: orient1 = nb.aff2axcodes(target_img.affine) elif orientation is not None: orient1 = tuple(orientation) else: raise RuntimeError("No orientation to reorient to!") if orient0 == orient1: # already in desired orientation return img elif orient0 == tuple("RAS") and orient1 == tuple("LAS"): # RAS -> LAS return img.as_reoriented([[0, -1], [1, 1], [2, 1]]) else: raise NotImplementedError("Cannot reorient {0} to {1}.".format( orient0, orient1))
def _run_interface(self, runtime): dsi_studio_file = self.inputs.dsi_studio_nifti new_file = fname_presuffix(dsi_studio_file, suffix="fixhdr", newpath=runtime.cwd) dsi_img = nb.load(dsi_studio_file) correct_img = nb.load(self.inputs.correct_header_nifti) new_axcodes = nb.aff2axcodes(correct_img.affine) input_axcodes = nb.aff2axcodes(dsi_img.affine) # Is the input image oriented how we want? if not input_axcodes == new_axcodes: # Re-orient input_orientation = nb.orientations.axcodes2ornt(input_axcodes) desired_orientation = nb.orientations.axcodes2ornt(new_axcodes) transform_orientation = nb.orientations.ornt_transform( input_orientation, desired_orientation) reoriented_img = dsi_img.as_reoriented(transform_orientation) else: reoriented_img = dsi_img # No matter what, still use the correct affine nb.Nifti1Image(reoriented_img.get_data(), correct_img.affine).to_filename(new_file) self._results['out_file'] = new_file return runtime
def read_input_images(self): orig_nii_stationary = nb.load(self.stationary_image_file_path) orig_nii_moving = nb.load(self.moving_image_file_path) orig_nii_stationary_voxel_dim = orig_nii_stationary.header["pixdim"][1:4] orig_nii_moving_voxel_dim = orig_nii_moving.header["pixdim"][1:4] orig_nii_stationary_centre = [float(orig_nii_stationary.header["qoffset_x"]), float(orig_nii_stationary.header["qoffset_y"]), float(orig_nii_stationary.header["qoffset_z"])] orig_nii_moving_centre = [float(orig_nii_moving.header["qoffset_x"]), float(orig_nii_moving.header["qoffset_y"]), float(orig_nii_moving.header["qoffset_z"])] print(" ============= ============== ===================") print("Image 1 voxel resolution before resampling: {}".format(orig_nii_stationary_voxel_dim)) print(" ============= ============== ===================") print("Image 2 voxel resolution before resampling: {}".format(orig_nii_moving_voxel_dim)) print(" ============= ============== ===================") print("Image 1 centre before resampling: {}".format(orig_nii_stationary_centre)) print(" ============= ============== ===================") print("Image 2 centre before resampling: {}".format(orig_nii_moving_centre)) print(" ============= ============== ===================") print("original t1 affine: {}".format(orig_nii_stationary.affine)) print(" ============= ============== ===================") print("original t2 affine: {}".format(orig_nii_moving.affine)) print(" ============= ============== ===================") print("original t1 Orientation: {}".format(nb.aff2axcodes(orig_nii_stationary.affine))) print(" ============= ============== ===================") print("original t2 Orientation: {}".format(nb.aff2axcodes(orig_nii_moving.affine))) print(" ============= ============== ===================") self.orig_nii_stationary = orig_nii_stationary self.orig_nii_moving = orig_nii_moving return self.orig_nii_stationary, self.orig_nii_moving;
def test_MNI_reorient(): # load up the image with the incorrect orientation bad_img = nib.load(bad_orientation_file) # get the affine information from the image bad_affine = bad_img.affine # get the orientation code from the affine information bad_orientation = nib.aff2axcodes(bad_affine) # run the reorientation on the file with the bad orientation to create # a file with the correct orientation #if isfile(out_file_name): # os.remove(out_file_name) # MNI_reorient(bad_orientation_file, out_file_name) # load up the image data of the out file created in the previous step out_file_img = nib.load(out_file_name) # get the affine information from the out file image out_file_affine = out_file_img.affine # get the orientation code from the affine information out_file_orientation = nib.aff2axcodes(out_file_affine) # assert that the original image with the incorrect orientation actually does # have a different orientation than what is desired assert (bad_orientation != MNI_axis_codes) # assert that the newly created out file has had its orientation swapped # to the desired orientation assert (out_file_orientation == MNI_axis_codes)
def getAxesForTransform(startingDicomFile, cfg): """ Load one example file """ nifti_object = nib.load(cfg.ref_BOLD) target_orientation = nib.aff2axcodes(nifti_object.affine) dicom_object = getLocalDicomData(cfg, startingDicomFile) dicom_object = dicomreaders.mosaic_to_nii(dicom_object) dicom_orientation = nib.aff2axcodes(dicom_object.affine) return target_orientation, dicom_orientation # from here you can save and load it so getTransform is hard coded --you only need to run this once
def get_ornt(self): """Returns current orientation based on the affine and coordinate system""" if self.coord_sys == 'nib': ornt_tup = aff2axcodes(self.affine) elif self.coord_sys == 'itk': ornt_tup = inv_axcodes(aff2axcodes(convert_affine(self.affine))) else: raise ValueError(f'Invalid coord_sys: "{self.coord_sys}"') ornt_str = ''.join(ornt_tup) return ornt_str
def print_orien(example_file): img = nib.load(example_file) # Here is the affine (to two digits decimal precision): np.set_printoptions(precision=2, suppress=True) # print(f"img.affine={img.affine}") # What are the orientations of the voxel axes here? # Nibabel has a routine to tell you, called aff2axcodes. orientation = nib.aff2axcodes(img.affine) print(f"orientation of {example_file} = {orientation}") return nib.aff2axcodes(img.affine)
def main(): parser = _build_args_parser() args = parser.parse_args() assert_inputs_exist(parser, args.input, args.ref) assert_outputs_exist(parser, args, args.output) if args.enforce_dimensions and not args.ref: parser.error("Cannot enforce dimensions without a reference image") if args.verbose: logging.basicConfig(level=logging.DEBUG) logging.debug('Loading Raw data from %s', args.input) img = nib.load(args.input) data = img.get_data() affine = img.get_affine() original_zooms = img.get_header().get_zooms()[:3] if args.ref: ref_img = nib.load(args.ref) new_zooms = ref_img.header.get_zooms()[:3] elif args.resolution: new_zooms = [args.resolution] * 3 elif args.iso_min: min_zoom = min(original_zooms) new_zooms = (min_zoom, min_zoom, min_zoom) logging.debug('Data shape: %s', data.shape) logging.debug('Data affine: %s', affine) logging.debug('Data affine setup: %s', nib.aff2axcodes(affine)) logging.debug('Resampling data to %s with mode %s', new_zooms, args.interp) data2, affine2 = reslice(data, affine, original_zooms, new_zooms, interp_code_to_order(args.interp)) logging.debug('Resampled data shape: %s', data2.shape) logging.debug('Resampled data affine: %s', affine2) logging.debug('Resampled data affine setup: %s', nib.aff2axcodes(affine2)) logging.debug('Saving resampled data to %s', args.output) if args.enforce_dimensions: computed_dims = data2.shape ref_dims = ref_img.shape[:3] if computed_dims != ref_dims: fix_dim_volume = np.zeros(ref_dims) x_dim = min(computed_dims[0], ref_dims[0]) y_dim = min(computed_dims[1], ref_dims[1]) z_dim = min(computed_dims[2], ref_dims[2]) fix_dim_volume[:x_dim, :y_dim, :z_dim] = \ data2[:x_dim, :y_dim, :z_dim] data2 = fix_dim_volume nib.save(nib.Nifti1Image(data2, affine2), args.output)
def reorient_image(input_path): input_image = nib.load(input_path) print(nib.aff2axcodes(input_image.affine)) output_image = nib.as_closest_canonical(input_image) output_path = input_path.split('.')[0] + '_reoriented.nii.gz' print(output_path) print(nib.aff2axcodes(output_image.affine)) nib.save(output_image, output_path)
def _resample(mask, target_affine, target_shape): if target_affine is not None and target_shape is not None: mask = image.resample_img(mask, target_affine=target_affine, target_shape=target_shape, interpolation='nearest') # check orientations orient_data = ''.join(nib.aff2axcodes(target_affine)) orient_roi = ''.join(nib.aff2axcodes(mask.affine)) if not orient_roi == orient_data: msg = 'Orientation of mask and data are not the same: ' + \ orient_roi + ' (mask) vs. ' + orient_data + ' (data)' logger.error(msg) raise ValueError(msg) return mask
def test_orntd_2d(self): data = { "seg": np.ones((2, 1, 3)), "img": np.ones((2, 1, 3)), "seg.affine": np.eye(4), "img.affine": np.eye(4) } ornt = Orientationd(keys=("img", "seg"), axcodes="PLI") res = ornt(data) np.testing.assert_allclose(res["img"].shape, (2, 3, 1)) code = nib.aff2axcodes(res["seg.affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("P", "L", "S")) code = nib.aff2axcodes(res["img.affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("P", "L", "S"))
def test_orntd_1d(self): data = { "seg": np.ones((2, 3)), "img": np.ones((2, 3)), "seg_meta_dict": {"affine": np.eye(4)}, "img_meta_dict": {"affine": np.eye(4)}, } ornt = Orientationd(keys=("img", "seg"), axcodes="L") res = ornt(data) np.testing.assert_allclose(res["img"].shape, (2, 3)) code = nib.aff2axcodes(res["seg_meta_dict"]["affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("L", "A", "S")) code = nib.aff2axcodes(res["img_meta_dict"]["affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("L", "A", "S"))
def test_orntd_1d(self): data = { 'seg': np.ones((2, 3)), 'img': np.ones((2, 3)), 'seg.affine': np.eye(4), 'img.affine': np.eye(4) } ornt = Orientationd(keys=('img', 'seg'), axcodes='L') res = ornt(data) np.testing.assert_allclose(res['img'].shape, (2, 3)) code = nib.aff2axcodes(res['seg.affine'], ornt.ornt_transform.labels) self.assertEqual(code, ('L', 'A', 'S')) code = nib.aff2axcodes(res['img.affine'], ornt.ornt_transform.labels) self.assertEqual(code, ('L', 'A', 'S'))
def test_orntd_canonical(self): data = { "seg": np.ones((2, 1, 2, 3)), "img": np.ones((2, 1, 2, 3)), "seg.affine": np.eye(4), "img.affine": np.eye(4), } ornt = Orientationd(keys=("img", "seg"), as_closest_canonical=True) res = ornt(data) np.testing.assert_allclose(res["img"].shape, (2, 1, 2, 3)) np.testing.assert_allclose(res["seg"].shape, (2, 1, 2, 3)) code = nib.aff2axcodes(res["seg.affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("R", "A", "S")) code = nib.aff2axcodes(res["img.affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("R", "A", "S"))
def resampleNiftifile(self, ): for root, dirs, files in os.walk(self.resampling_folder): print() print("========= ============ =========") for fl in files: if (fl.endswith(".nii.gz")): basename = fl[0:-7] img_nb = nb.load(os.path.join(self.resampling_folder, fl)) img_np = img_nb.dataobj target_shape = np.array((256, 256, 256)) new_resolution = [ 0.5, ] * 3 new_affine = np.zeros((4, 4)) new_affine[:3, :3] = np.diag(new_resolution) new_affine[:3, 3] = target_shape * new_resolution / 2. * -1 new_affine[3, 3] = 1.0 new_affine interim_nb = nl.image.resample_img( img_nb, target_affine=new_affine, target_shape=target_shape, interpolation='nearest') print("======== Before ==========") print("Shape and max intensity of img is {} and {}".format( img_np.shape, np.max(img_np))) print("Voxel resolution: {}".format( img_nb.header["pixdim"][1:4])) print("Orientation: {}".format( nb.aff2axcodes(img_nb.affine))) print("Affine: {}".format(img_nb.affine)) interim_nb.to_filename( os.path.join(self.resampling_folder, basename + "_upsampled.nii.gz")) tmp_nb = nb.load( os.path.join(self.resampling_folder, basename + "_upsampled.nii.gz")) tmp_np = tmp_nb.dataobj print("========= After ===========") print() print("Shape and max intensity of img is {} and {}".format( tmp_np.shape, np.max(tmp_np))) print("Voxel resolution: {}".format( tmp_nb.header["pixdim"][1:4])) print("Orientation: {}".format( nb.aff2axcodes(tmp_nb.affine))) print("Affine: {}".format(tmp_nb.affine)) print()
def load_nifti(filepath): """Load a Nifti file. # Arguments filepath: The file path of the Nifti image to load. # Returns A four dimensional array where the last dimension are the color channels (rgb). If the Nifti only contains gray values then all channels have the same value for one voxel.""" img = nib.load(filepath) img_data = img.get_data() # make sure volume orientation is LPS (DICOM default) orientation = ''.join(nib.aff2axcodes(img.affine)) if not orientation == 'LPS': if orientation == 'LAS': img_data = np.flip(img_data, 1) elif orientation == 'RAS': img_data = np.flip(img_data, 0) img_data = np.flip(img_data, 1) else: raise ValueError('Unsupported orientation of Nifti file: ' + orientation) # add a channels dimension (if not already present) if len(img_data.shape) < 4: img_data.shape += (1,) return img_data
def orientation(self): """tuple[str]: Image orientation in standard orientation format. See orientation.py for more information on conventions. """ nib_orientation = nib.aff2axcodes(self._affine) return stdo.orientation_nib_to_standard(nib_orientation)
def read(path='', b_reorient=False, orientation=(('R', 'L'), ('P', 'A'), ('I', 'S'))): """ Read the nifti file and switch to a given orientation orientation defaults to std LAS (radiological) - RAS (neurological) """ if not os.path.isfile(path): raise ValueError('Provided path is not a valid file') image_nii = nib.load(path) if b_reorient: # switch to given orientation (http://nipy.org/nibabel/image_orientation.html) axcodes = nib.aff2axcodes(image_nii.affine) orientations = nib.orientations.axcodes2ornt(axcodes, orientation) image = image_nii.get_data() image = nib.apply_orientation(image, orientations) header = image_nii.header img_shape = image.shape else: image = image_nii.get_data() img_shape = image.shape header = image_nii.header print(f'preprocessed data shape={img_shape}') return image, header, img_shape
def _format_volume_to_header(volume: MedicalVolume) -> MedicalVolume: """Reformats the volume according to its header. Args: volume (MedicalVolume): The volume to reformat. Must be 3D and have headers of shape (1, 1, volume.shape[2]). Returns: MedicalVolume: The reformatted volume. """ headers = volume.headers() assert headers.shape == (1, 1, volume.shape[2]) affine = to_RAS_affine(headers.flatten()) orientation = stdo.orientation_nib_to_standard(nib.aff2axcodes(affine)) # Currently do not support mismatch in scanner_origin. if tuple(affine[:3, 3]) != volume.scanner_origin: raise ValueError( "Scanner origin mismatch. " "Currently we do not handle mismatch in scanner origin " "(i.e. cannot flip across axis)") volume = volume.reformat(orientation) assert volume.headers().shape == (1, 1, volume.shape[2]) return volume
def _get_mgdm_orientation(affine, mgdm): ''' Transforms nibabel affine information into orientation and slice order that MGDM understands ''' orientation = nb.aff2axcodes(affine) # set mgdm slice order if orientation[-1] == "I" or orientation[-1] == "S": sliceorder = mgdm.AXIAL elif orientation[-1] == "L" or orientation[-1] == "R": sliceorder = mgdm.SAGITTAL else: sliceorder = mgdm.CORONAL # set mgdm orientations if "L" in orientation: LR = mgdm.R2L elif "R" in orientation: LR = mgdm.L2R # flipLR = True if "A" in orientation: AP = mgdm.P2A # flipAP = True elif "P" in orientation: AP = mgdm.A2P if "I" in orientation: IS = mgdm.S2I # flipIS = True elif "S" in orientation: IS = mgdm.I2S return sliceorder, LR, AP, IS
def read_nifti_series(filename): proxy_img = nib.load(filename) # less efficent get image data into memory all at once # image_data = proxy_img.get_fdata() hdr = proxy_img.header image_shape = hdr.get_data_shape() image_dim = len(image_shape) num_images = 1 if image_dim >= 3: num_images = image_shape[2] (m, b) = hdr.get_slope_inter() axcodes = nib.aff2axcodes(proxy_img.affine) # TODO-- There does not seem to be a good NIfti method to obtain the input volume's labels? if ((axcodes != ('R', 'A', 'S')) and (axcodes != ('L', 'A', 'S')) and (axcodes != ('L', 'P', 'S'))): print( "Input NIfti series is in unsupported orientation. Please convert to RAS, LAS, or LPS orientation:" + filename) sys.exit(1) # specifiy LPS for DICOM # https://nipy.org/nibabel/dicom/dicom_orientation.html, if we want to apply the formula above to array indices in pixel_array, we first have to apply a column / row flip to the indices. codes = ('L', 'P', 'S') labels = (('A', 'P'), ('R', 'L'), ('I', 'S')) orients = orientations.axcodes2ornt(codes, labels) img_reorient = proxy_img.as_reoriented(orients) hdr = img_reorient.header # We reset m and b here ourselves for downstream rescale/slope b = 0 m = 1 return img_reorient, hdr, num_images, b, m, axcodes
def read_nii_from_path(config, path=None): """ Read nii file from the path :param config: type dict: config parameter :param path: path to nii.file :return: img_arr : type ndarray: 3D array from nii file :return: img.header: type nibabel.nifti1.Nifti1Header: header of nifti image :return: img.affine: type ndarray, affine info of nifti image """ print(path) img = nib.load(path) axcodes = tuple(nib.aff2axcodes(img.affine)) img_arr = img.get_fdata() if config['new_orientation']: img_arr = nifti_reorientation( np.array(img_arr), axcodes, tuple(config['new_orientation'])) #('P','L','S') if config['rescale']: slope = config['rescale'] / (np.max(img_arr) + 1e-16) img_arr = img_arr / (np.max(img_arr) + 1e-16) * config['rescale'] img.header.set_slope_inter(slope, inter=0) elif config['scale']: print(config['scale']) img_arr = img_arr * config['scale'] else: pass return img_arr, img.header, img.affine
def _resample(mask, target_affine, target_shape): if target_affine is not None and target_shape is not None: mask = image.resample_img( mask, target_affine=target_affine, target_shape=target_shape, interpolation="nearest", ) # check orientations orient_data = "".join(nib.aff2axcodes(target_affine)) orient_roi = "".join(nib.aff2axcodes(mask.affine)) if not orient_roi == orient_data: logger.error( "Orientation of mask and data are not the same: " + orient_roi + " (mask) vs. " + orient_data + " (data)") return mask
def vtk_to_trk_converter(tract_in, tract_out, reference_volume=None): if not tract_in.endswith('vtk'): raise ValueError("Sorry, we only work with vtk files as input") if not tract_out.endswith('trk'): raise ValueError("Sorry, we only work with trk files as output") tractography = tractography_from_vtk_file(tract_in) # ADD metadata to the TRK format hdr_dict = None if not (reference_volume is None): ref = nibabel.load(reference_volume) hdr_dict = {'dimensions': ref.shape[:3], 'voxel_sizes': ref.header.get_zooms()[:3], 'voxel_to_rasmm': ref.affine, 'voxel_order': "".join(nibabel.aff2axcodes(ref.affine))} tract = nibabel.streamlines.Tractogram(tractography.tracts(), affine_to_rasmm=np.eye(4)) trk_file = nibabel.streamlines.TrkFile(tract, hdr_dict) trk_file.save(tract_out)
def orientation(self): """ Get the closest orientation in standard orientation coordinates :return: a tuple of standard orientation coordinates (see orientation.py for more information on format) """ nib_orientation = nib.aff2axcodes(self._affine) return stdo.orientation_nib_to_standard(nib_orientation)
def test_orntd_no_metadata(self): data = {"seg": np.ones((2, 1, 2, 3))} ornt = Orientationd(keys="seg", axcodes="RAS") res = ornt(data) np.testing.assert_allclose(res["seg"].shape, (2, 1, 2, 3)) code = nib.aff2axcodes(res["seg_meta_dict"]["affine"], ornt.ornt_transform.labels) self.assertEqual(code, ("R", "A", "S"))
def __call__(self, data): """ :param data: Data dictionary to be processed by this transform :type data: dict :return: Updated data dictionary :rtype: dict """ for field in self.fields: complete_file_path = os.path.join(self.data_dir, data[field]) assert complete_file_path[0:5] == 's3://' filename = get_file_from_s3(self.s3_client, complete_file_path, self.cache) img = nib.load(filename) if self.canonical: img = nib.as_closest_canonical(img) data[field] = img data[field + '_affines'] = img.affine data[field + '_orientations'] = nib.aff2axcodes(img.affine) return data
def split_seg_sides(in_bin_seg_file, out_seg_file): """ Split segmentation into Right/Left :param in_bin_seg_file: input binary segmentation :param out_seg_file: output segmentation with both sides """ in_bin_seg = nib.load(in_bin_seg_file) mid = int(in_bin_seg.shape[0] / 2) out_seg = in_bin_seg.get_data().copy() seg_ort = nib.aff2axcodes(in_bin_seg.affine) r_orient_nii = ('R', 'A', 'S') l_orient_nii = ('L', 'A', 'S') if seg_ort == l_orient_nii: # new = in_bin_seg.get_data()[mid:-1, :, :] # new[new == 1] = 2 # out_seg[mid:-1, :, :] = 2 out_seg[0:mid, :, :] = 0 out_seg = out_seg + in_bin_seg.get_data() elif seg_ort == r_orient_nii: # new = in_bin_seg.get_data()[0:mid, :, :] # new[new == 1] = 2 # out_seg[0:mid, :, :] = 2 out_seg[mid:-1, :, :] = 0 out_seg = out_seg + in_bin_seg.get_data() print(out_seg.max()) out_seg_nii = nib.Nifti1Image(out_seg, in_bin_seg.affine) nib.save(out_seg_nii, out_seg_file)
def spikes_mask(in_file, in_mask=None, out_file=None): """ Utility function to calculate a mask in which check for :abbr:`EM (electromagnetic)` spikes. """ import os.path as op import nibabel as nb import numpy as np from nilearn.image import mean_img from nilearn.plotting import plot_roi from scipy import ndimage as nd if out_file is None: fname, ext = op.splitext(op.basename(in_file)) if ext == '.gz': fname, ext2 = op.splitext(fname) ext = ext2 + ext out_file = op.abspath('{}_spmask{}'.format(fname, ext)) out_plot = op.abspath('{}_spmask.pdf'.format(fname)) in_4d_nii = nb.load(in_file) orientation = nb.aff2axcodes(in_4d_nii.affine) if in_mask: mask_data = nb.load(in_mask).get_data() a = np.where(mask_data != 0) bbox = np.max(a[0]) - np.min(a[0]), np.max(a[1]) - \ np.min(a[1]), np.max(a[2]) - np.min(a[2]) longest_axis = np.argmax(bbox) # Input here is a binarized and intersected mask data from previous section dil_mask = nd.binary_dilation( mask_data, iterations=int(mask_data.shape[longest_axis] / 9)) rep = list(mask_data.shape) rep[longest_axis] = -1 new_mask_2d = dil_mask.max(axis=longest_axis).reshape(rep) rep = [1, 1, 1] rep[longest_axis] = mask_data.shape[longest_axis] new_mask_3d = np.logical_not(np.tile(new_mask_2d, rep)) else: new_mask_3d = np.zeros(in_4d_nii.shape[:3]) == 1 if orientation[0] in ['L', 'R']: new_mask_3d[0:2, :, :] = True new_mask_3d[-3:-1, :, :] = True else: new_mask_3d[:, 0:2, :] = True new_mask_3d[:, -3:-1, :] = True mask_nii = nb.Nifti1Image(new_mask_3d.astype(np.uint8), in_4d_nii.get_affine(), in_4d_nii.get_header()) mask_nii.to_filename(out_file) plot_roi(mask_nii, mean_img(in_4d_nii), output_file=out_plot) return out_file, out_plot
def get_axcodes(self): """Get codes for voxel axis derived from affine. i.e., ('R', 'A', 'S') """ if isinstance(self._affine, np.ndarray): return aff2axcodes(self._affine) else: return None
def get_affine_orientation_slice(a): # get the orientation of the affine, and the slice order import nibabel as nb ori=nb.aff2axcodes(a) if ori[-1] == "I" or ori[-1] == "S": slc = "AXIAL" elif ori[-1] == "L" or ori[-1] == "R": slc="SAGITTAL" else: slc="CORONAL" return ori, slc
def load_nifti(fname, verbose=False): img = nib.load(fname) data = img.get_data() affine = img.get_affine() if verbose: print(fname) print(data.shape) print(affine) print(img.get_header().get_zooms()[:3]) print(nib.aff2axcodes(affine)) print return data, affine
def original_axcodes(self): """ axcodes info from the image header more info: http://nipy.org/nibabel/image_orientation.html :return: a tuple of axcodes, with each element as axcodes of an image file """ try: return tuple(nib.aff2axcodes(affine) for affine in self.original_affine) except IndexError: tf.logging.fatal('unknown affine in header %s: %s', self.file_path, self.original_affine) raise
def load_nifti(fname, return_img=False, return_voxsize=False, return_coords=False): img = nib.load(fname) data = img.get_data() vox_size = img.header.get_zooms()[:3] ret_val = [data, img.affine] if return_img: ret_val.append(img) if return_voxsize: ret_val.append(vox_size) if return_coords: ret_val.append(nib.aff2axcodes(img.affine)) return tuple(ret_val)
def get_header_from_anat(anat_file, hdr={}): if anat_file is None: if len(hdr) == 0: # Defaults hdr[Header.VOXEL_SIZES] = (0, 0, 0) hdr[Header.DIMENSIONS] = (1, 1, 1) return hdr anat = nib.load(anat_file) hdr[Header.VOXEL_SIZES] = tuple(anat.get_header().get_zooms())[:3] hdr[Header.DIMENSIONS] = tuple(anat.get_header().get_data_shape())[:3] hdr[Header.VOXEL_TO_WORLD] = anat.get_header().get_best_affine() # We can guess the voxel order from the affine if there is no 0 on the diagonal. if not np.any(np.diag(hdr[Header.VOXEL_TO_WORLD]) == 0): hdr[Header.VOXEL_ORDER] = ''.join(nib.aff2axcodes(hdr[Header.VOXEL_TO_WORLD])) return hdr
affine = img.get_affine() zooms = img.get_header().get_zooms()[:3] bvals, bvecs = read_bvals_bvecs(fbvals, fbvecs) from dipy.core.gradients import gradient_table gtab = gradient_table(bvals, bvecs, b0_threshold=10) b0_index = np.where(gtab.b0s_mask == True)[0] mask = nib.load(fmask).get_data() print(data.shape) print(affine) print(nib.aff2axcodes(affine)) print('>>> Resample data to 1x1x1 mm^3...') from dipy.align.aniso2iso import resample data2, affine2 = resample(data, affine, zooms=zooms, new_zooms=(1., 1., 1.)) mask2, affine2 = resample(mask, affine, zooms=zooms, new_zooms=(1., 1., 1.)) mask2[mask2 > 0] = 1
print(">>> Warp T1 to S0 using ANTS...") fT1 = join(dname, "T1w_acpc_dc_restore_brain.nii.gz") fT1_flirt = join(dname, "t1_flirt.nii.gz") fmat = join(dname, "flirt_affine.mat") fS0 = join(dname, "dwi_S0_1x1x1.nii.gz") fFA = join(dname, "dwi_fa_1x1x1.nii.gz") fT1wS0 = join(dname, "t1_warped_S0.nii.gz") fdef = join(dname, "MultiVarNew") img_T1 = nib.load(fT1) print(img_T1.get_data().shape) print(img_T1.get_affine()) print(nib.aff2axcodes(img_T1.get_affine())) del img_T1 flirt_cmd = "flirt -in " + fT1 + " -ref " + fFA + " -out " + fT1_flirt + " -omat " + fmat print(flirt_cmd) pipe(flirt_cmd) br1 = "[" + fS0 + ", " + fT1_flirt + ", 1, 4]" br2 = "[" + fFA + ", " + fT1_flirt + ", 1.5, 4]" ants_cmd1 = "ANTS 3 -m CC" + br1 + " -m CC" + br2 + " -o " + fdef + " -i 75x75x10 -r Gauss[3,0] -t SyN[0.25]" ants_cmd2 = ( "WarpImageMultiTransform 3 " + fT1_flirt + " "
def main(): np.random.seed(int(time.time())) parser = buildArgsParser() args = parser.parse_args() param = {} if args.algo not in ["det", "prob"]: parser.error("--algo has wrong value. See the help (-h).") if args.basis not in ["mrtrix", "dipy", "fibernav"]: parser.error("--basis has wrong value. See the help (-h).") #if np.all([args.nt is None, args.npv is None, args.ns is None]): # args.npv = 1 if args.theta is not None: theta = gm.math.radians(args.theta) elif args.curvature > 0: theta = get_max_angle_from_curvature(args.curvature, args.step_size) elif args.algo == 'prob': theta = gm.math.radians(20) else: theta = gm.math.radians(45) if args.mask_interp == 'nn': mask_interpolation = 'nearest' elif args.mask_interp == 'tl': mask_interpolation = 'trilinear' else: parser.error("--mask_interp has wrong value. See the help (-h).") return if args.field_interp == 'nn': field_interpolation = 'nearest' elif args.field_interp == 'tl': field_interpolation = 'trilinear' else: parser.error("--sh_interp has wrong value. See the help (-h).") return param['algo'] = args.algo param['mask_interp'] = mask_interpolation param['field_interp'] = field_interpolation param['theta'] = theta param['sf_threshold'] = args.sf_threshold param['sf_threshold_init'] = args.sf_threshold_init param['step_size'] = args.step_size param['max_length'] = args.max_length param['min_length'] = args.min_length param['is_single_direction'] = False param['nbr_seeds'] = 0 param['nbr_seeds_voxel'] = 0 param['nbr_streamlines'] = 0 param['max_no_dir'] = int(math.ceil(args.maxL_no_dir / param['step_size'])) param['is_all'] = False param['isVerbose'] = args.isVerbose if param['isVerbose']: logging.basicConfig(level=logging.DEBUG) if param['isVerbose']: logging.info('Tractography parameters:\n{0}'.format(param)) if os.path.isfile(args.output_file): if args.isForce: logging.info('Overwriting "{0}".'.format(args.output_file)) else: parser.error( '"{0}" already exists! Use -f to overwrite it.' .format(args.output_file)) nib_mask = nib.load(args.mask_file) mask = BinaryMask( Dataset(nib_mask, param['mask_interp'])) dataset = Dataset(nib.load(args.sh_file), param['field_interp']) field = SphericalHarmonicField( dataset, args.basis, param['sf_threshold'], param['sf_threshold_init'], param['theta']) if args.algo == 'det': tracker = deterministicMaximaTracker(field, param['step_size']) elif args.algo == 'prob': tracker = probabilisticTracker(field, param['step_size']) else: parser.error("--algo has wrong value. See the help (-h).") return start = time.time() # Etienne St-Onge #load and transfo *** todo test with rotation and scaling seed_points = np.load(args.seed_points) seed_dirs = np.load(args.seed_dir) rotation = nib_mask.get_affine()[:3,:3] inv_rotation = np.linalg.inv(rotation) translation = nib_mask.get_affine()[:3,3] scale = np.array(nib_mask.get_header().get_zooms()) voxel_space = nib.aff2axcodes(nib_mask.get_affine()) print voxel_space # seed points transfo # LPS -> voxel_space if voxel_space[0] != 'L': print "flip X" seed_points[:,0] = -seed_points[:,0] if voxel_space[1] != 'P': print "flip Y" seed_points[:,1] = -seed_points[:,1] if voxel_space[2] != 'S': print "flip Z" seed_points[:,2] = -seed_points[:,2] # other transfo seed_points = seed_points - translation seed_points = seed_points.dot(inv_rotation) seed_points = seed_points * scale # seed dir transfo seed_dirs[:,0:2] = -seed_dirs[:,0:2] seed_dirs = seed_dirs.dot(inv_rotation) seed_dirs = seed_dirs * scale if args.inv_seed_dir: seed_dirs = seed_dirs * -1.0 # Compute tractography nb_seeds = len(seed_dirs) if args.test is not None and args.test < nb_seeds: nb_seeds = args.test print args.algo," nb seeds: ", nb_seeds streamlines = [] for i in range(nb_seeds): s = generate_streamline(tracker, mask, seed_points[i], seed_dirs[i], pft_tracker=None, param=param) streamlines.append(s) stdout.write("\r %d%%" % (i*101//nb_seeds)) stdout.flush() stdout.write("\n done") stdout.flush() # transform back for i in range(len(streamlines)): streamlines[i] = streamlines[i] / scale streamlines[i] = streamlines[i].dot(rotation) streamlines[i] = streamlines[i] + translation # voxel_space -> LPS if voxel_space[0] != 'L': streamlines[i][:,0] = -streamlines[i][:,0] if voxel_space[1] != 'P': streamlines[i][:,1] = -streamlines[i][:,1] if voxel_space[2] != 'S': streamlines[i][:,2] = -streamlines[i][:,2] lines_polydata = lines_to_vtk_polydata(streamlines, None, np.float32) save_polydata(lines_polydata, args.output_file , True) lengths = [len(s) for s in streamlines] if nb_seeds > 0: ave_length = (sum(lengths) / nb_seeds) * param['step_size'] else: ave_length = 0 str_ave_length = "%.2f" % ave_length str_time = "%.2f" % (time.time() - start) print(str(nb_seeds) + " streamlines, with an average length of " + str_ave_length + " mm, done in " + str_time + " seconds.")
def get_nifti_voxel_space(nii): return nib.aff2axcodes(nii.get_affine())
def main(): parser = buildArgsParser() args = parser.parse_args() param = {} if args.pft_theta is None and args.pft_curvature is None: args.pft_theta = 20 if not np.any([args.nt, args.npv, args.ns]): args.npv = 1 if args.theta is not None: theta = gm.math.radians(args.theta) elif args.curvature > 0: theta = get_max_angle_from_curvature(args.curvature, args.step_size) elif args.algo == 'prob': theta = gm.math.radians(20) else: theta = gm.math.radians(45) if args.pft_curvature is not None: pft_theta = get_max_angle_from_curvature(args.pft_curvature, args.step_size) else: pft_theta = gm.math.radians(args.pft_theta) if args.mask_interp == 'nn': mask_interpolation = 'nearest' elif args.mask_interp == 'tl': mask_interpolation = 'trilinear' else: parser.error("--mask_interp has wrong value. See the help (-h).") return if args.field_interp == 'nn': field_interpolation = 'nearest' elif args.field_interp == 'tl': field_interpolation = 'trilinear' else: parser.error("--sh_interp has wrong value. See the help (-h).") return param['random'] = args.random param['skip'] = args.skip param['algo'] = args.algo param['mask_interp'] = mask_interpolation param['field_interp'] = field_interpolation param['theta'] = theta param['sf_threshold'] = args.sf_threshold param['pft_sf_threshold'] = args.pft_sf_threshold if args.pft_sf_threshold is not None else args.sf_threshold param['sf_threshold_init'] = args.sf_threshold_init param['step_size'] = args.step_size param['max_length'] = args.max_length param['min_length'] = args.min_length param['is_single_direction'] = args.is_single_direction param['nbr_seeds'] = args.nt if args.nt is not None else 0 param['nbr_seeds_voxel'] = args.npv if args.npv is not None else 0 param['nbr_streamlines'] = args.ns if args.ns is not None else 0 param['max_no_dir'] = int(math.ceil(args.maxL_no_dir / param['step_size'])) param['is_all'] = args.is_all param['is_act'] = args.is_act param['theta_pft'] = pft_theta if args.not_is_pft: param['nbr_particles'] = 0 param['back_tracking'] = 0 param['front_tracking'] = 0 else: param['nbr_particles'] = args.nbr_particles param['back_tracking'] = int( math.ceil(args.back_tracking / args.step_size)) param['front_tracking'] = int( math.ceil(args.front_tracking / args.step_size)) param['nbr_iter'] = param['back_tracking'] + param['front_tracking'] param['mmap_mode'] = None if args.isLoadData else 'r' if args.isVerbose: logging.basicConfig(level=logging.DEBUG) logging.debug('Tractography parameters:\n{0}'.format(param)) if os.path.isfile(args.output_file): if args.isForce: logging.info('Overwriting "{0}".'.format(args.output_file)) else: parser.error( '"{0}" already exists! Use -f to overwrite it.' .format(args.output_file)) include_dataset = Dataset( nib.load(args.map_include_file), param['mask_interp']) exclude_dataset = Dataset( nib.load(args.map_exclude_file), param['mask_interp']) if param['is_act']: mask = ACT(include_dataset, exclude_dataset, param['step_size'] / include_dataset.size[0]) else: mask = CMC(include_dataset, exclude_dataset, param['step_size'] / include_dataset.size[0]) dataset = Dataset(nib.load(args.sh_file), param['field_interp']) field = SphericalHarmonicField( dataset, args.basis, param['sf_threshold'], param['sf_threshold_init'], param['theta']) if args.algo == 'det': tracker = deterministicMaximaTracker(field, param['step_size']) elif args.algo == 'prob': tracker = probabilisticTracker(field, param['step_size']) else: parser.error("--algo has wrong value. See the help (-h).") return pft_field = SphericalHarmonicField( dataset, args.basis, param['pft_sf_threshold'], param['sf_threshold_init'], param['theta_pft']) pft_tracker = probabilisticTracker(pft_field, param['step_size']) # ADD Seed input # modify ESO nib_mask = nib.load(args.map_include_file) seed_points = np.load(args.seed_points) seed_dirs = np.load(args.seed_dir) rotation = nib_mask.get_affine()[:3,:3] inv_rotation = np.linalg.inv(rotation) translation = nib_mask.get_affine()[:3,3] scale = np.array(nib_mask.get_header().get_zooms()) voxel_space = nib.aff2axcodes(nib_mask.get_affine()) print voxel_space # seed points transfo # LPS -> voxel_space print scale if voxel_space[0] != 'L': print "flip X" seed_points[:,0] = -seed_points[:,0] if voxel_space[1] != 'P': print "flip Y" seed_points[:,1] = -seed_points[:,1] if voxel_space[2] != 'S': print "flip Z" seed_points[:,2] = -seed_points[:,2] # other transfo seed_points = seed_points - translation seed_points = seed_points.dot(inv_rotation) seed_points = seed_points * scale # seed dir transfo seed_dirs[:,0:2] = -seed_dirs[:,0:2] seed_dirs = seed_dirs.dot(inv_rotation) seed_dirs = seed_dirs * scale if args.inv_seed_dir: seed_dirs = seed_dirs * -1.0 # Compute tractography nb_seeds = len(seed_dirs) if args.test is not None and args.test < nb_seeds: nb_seeds = args.test # end modify ESO # tracker to modify # modify ESO start = time.time() streamlines = [] for i in range(nb_seeds): s = generate_streamline(tracker, mask, seed_points[i], seed_dirs[i], pft_tracker=pft_tracker, param=param) streamlines.append(s) stdout.write("\r %d%%" % (i*101//nb_seeds)) stdout.flush() stdout.write("\n done") stdout.flush() stop = time.time() # end modify ESO # ADD save fiber output # modify ESO for i in range(len(streamlines)): streamlines[i] = streamlines[i] / scale streamlines[i] = streamlines[i].dot(rotation) streamlines[i] = streamlines[i] + translation # voxel_space -> LPS if voxel_space[0] != 'L': streamlines[i][:,0] = -streamlines[i][:,0] if voxel_space[1] != 'P': streamlines[i][:,1] = -streamlines[i][:,1] if voxel_space[2] != 'S': streamlines[i][:,2] = -streamlines[i][:,2] lines_polydata = lines_to_vtk_polydata(streamlines, None, np.float32) save_polydata(lines_polydata, args.output_file , True) # end modify ESO lengths = [len(s) for s in streamlines] if nb_seeds > 0: ave_length = (sum(lengths) / nb_seeds) * param['step_size'] else: ave_length = 0 str_ave_length = "%.2f" % ave_length str_time = "%.2f" % (stop - start) print(str(nb_seeds) + " streamlines, with an average length of " + str_ave_length + " mm, done in " + str_time + " seconds.")
# load volume mask_file = args.volume volume_nib = nib.load(mask_file) # load tracto init_streamlines_list = [] for filename in args.fibers: init_streamlines_list.append(get_streamlines(load_streamlines_poyldata(filename))) print filename, len(init_streamlines_list[-1]) # Transform tracto to Voxel space rotation = volume_nib.get_affine()[:3,:3] inv_rotation = np.linalg.inv(rotation) translation = volume_nib.get_affine()[:3,3] scale = np.array(volume_nib.get_header().get_zooms()) voxel_space = nib.aff2axcodes(volume_nib.get_affine()) print voxel_space # seed points transfo # LPS -> voxel_space vertices_list = [] dirs_list = [] for streamlines in init_streamlines_list: for streamline in streamlines: if voxel_space[0] != 'L': #print "flip X" streamline[:,0] = -streamline[:,0] if voxel_space[1] != 'P': #print "flip Y" streamline[:,1] = -streamline[:,1] if voxel_space[2] != 'S':
parser.add_argument('-tx', type=float, default=None, help='x translation') parser.add_argument('-ty', type=float, default=None, help='y translation') parser.add_argument('-tz', type=float, default=None, help='z translation') args = parser.parse_args() # get transform nib_mask = nib.load(args.mask) lines = get_streamlines(load_streamlines_poyldata(args.tract)) rotation = nib_mask.get_affine()[:3,:3] inv_rotation = np.linalg.inv(rotation) translation = nib_mask.get_affine()[:3,3] scale = np.array(nib_mask.get_header().get_zooms()) voxel_space = nib.aff2axcodes(nib_mask.get_affine()) shape = nib_mask.get_data().shape print shape # transform if not args.no_transfo: if args.lps_ras: print "LPS -> RAS" print "Not implemented" raise NotImplementedError() else: print "LPS ->", voxel_space, " mm" for i in range(len(lines)): if voxel_space[0] != 'L': lines[i][:,0] = -lines[i][:,0]