def test_anat_reg_report(self, execdir): subject_id = "subj01" data_dir = execdir.mkdir("data") mri_dir = data_dir.mkdir(subject_id).mkdir("mri") shape = (12, 8, 4) affine = np.eye(4) cost_file = "cost.txt" cost_array = np.random.uniform(0, 1, 5) np.savetxt(cost_file, cost_array) in_data = np.random.normal(100, 5, shape) in_file = "func.nii.gz" nib.save(nib.Nifti1Image(in_data, affine), in_file) wm_data = np.random.randint(0, 2, shape).astype("uint8") wm_file = mri_dir.join("wm.mgz") nib.save(nib.MGHImage(wm_data, affine), str(wm_file)) aseg_data = np.random.randint(0, 5, shape).astype("uint8") aseg_file = mri_dir.join("aseg.mgz") nib.save(nib.MGHImage(aseg_data, affine), str(aseg_file)) out = preproc.AnatRegReport( subject_id=subject_id, data_dir=data_dir, in_file=in_file, cost_file=cost_file, ).run().outputs assert out.out_file == execdir.join("reg.png") assert op.exists(out.out_file)
def save_weights_as_datasurface(self, weights, output_dir): import os import nibabel as nib import numpy as np if self._images is None: self.get_images() sample = nib.load(self._images[0][0]) infinite_norm = np.max(np.abs(weights)) left_hemi_data = np.atleast_3d( np.divide(weights[:np.int(weights.size / 2)], infinite_norm)) left_hemi_mgh = nib.MGHImage(left_hemi_data, affine=sample.affine, header=sample.header) nib.save(left_hemi_mgh, os.path.join(output_dir, "weights_lh.mgh")) right_hemi_data = np.atleast_3d( np.divide(weights[np.int(weights.size / 2):], infinite_norm)) right_hemi_mgh = nib.MGHImage(right_hemi_data, affine=sample.affine, header=sample.header) nib.save(right_hemi_mgh, os.path.join(output_dir, "weights_rh.mgh"))
def freesurfer(lyman_info): subject = "subj01" mri_dir = lyman_info["data_dir"].join(subject).join("mri") seed = sum(map(ord, "freesurfer")) rs = np.random.RandomState(seed) affine = np.eye(4) vol_shape = lyman_info["vol_shape"] mask = rs.choice([0, 1], vol_shape, p=[.2, .8]) norm_data = rs.randint(0, 110, vol_shape) * mask norm_file = str(mri_dir.join("norm.mgz")) nib.save(nib.MGHImage(norm_data.astype("uint8"), affine), norm_file) wmparc_vals = [1000, 10, 11, 16, 8, 3000, 5001, 7, 46, 4] wmparc_data = rs.choice(wmparc_vals, vol_shape) * mask wmparc_file = str(mri_dir.join("wmparc.mgz")) nib.save(nib.MGHImage(wmparc_data.astype("int16"), affine), wmparc_file) lyman_info.update( subject=subject, norm_file=norm_file, wmparc_file=wmparc_file, ) return lyman_info
def mric_solve(segmented, target, TR,TE, alpha, save , *args): import nibabel as nb import numpy as np #Flatten array fseg= nb.load(segmented).get_data().reshape(1,-1)[0] rI = np.zeros(len(fseg)) vox2ras = nb.load(target).get_header().get_vox2ras() init = nb.load(target).get_data().reshape(1,-1)[0].astype("float32") #init[init==0]=0.1 # To avoid warnings solver = np.vectorize(mric_brentq) G = np.zeros(len(fseg)) k1 =TR*3.2 k2 =TE*3.9 G[fseg>0] = np.exp(-TR/1.084) #white assume all white G[fseg>999] = np.exp(-TR/1.820) #grey G[fseg==4] = 0 # np.exp(-TR/20.000) G[fseg==43] = 0 # np.exp(-TR/20.000) #ve for j in range(len(args)): i = args[j] temp=nb.load(i).get_data().reshape(1,-1)[0].astype("float32") rI[fseg>0] = temp[fseg>0]/init[fseg>0] rI[np.isnan(rI)] = 1 # can be included temp2 = np.array(solver(k1,k2,G,alpha,rI)).reshape(256,256,256) img = nb.MGHImage(temp2.astype("float32"),vox2ras) nb.save(img,save+str(j)+".mgz") rI2 = temp/init rI2[np.isnan(rI2)] = 1 # temp3 = rI2.reshape(256,256,256) img2 = nb.MGHImage(temp3.astype("float32"),vox2ras) nb.save(img2,"testIR"+str(j)+".mgz")
def main(subject, bids_folder): fn = op.join(bids_folder, 'derivatives', 'freesurfer', '{fs_subject}', 'surf', '{hemi}.{label}.mgz') if subject == 'fsaverage': for hemi in ['lh', 'rh']: fs_subject = subject im = nb.load( fn.format(hemi=hemi, label='wang2015_atlas', fs_subject=fs_subject)) prob_mask = surface.load_surf_data( fn.format(hemi=hemi, label='wang2015_atlas', fs_subject=fs_subject)) # print(prob_mask, op.exists(prob_mask)) label_mask = np.in1d(prob_mask, range(18, 24)).astype(np.int16) new_im = nb.MGHImage(label_mask, im.affine, im.header) new_im.to_filename( fn.format(hemi=hemi, label='wang15_ips', fs_subject=fs_subject)) else: fs_subject = f'sub-{subject}' for hemi in ['lh', 'rh']: pts, poly = cortex.db.get_surf(f'sub-{subject}', 'pia', hemisphere=hemi) surf = cortex.polyutils.Surface(pts, poly) im = nb.load( fn.format(hemi=hemi, label='wang15_fplbl', fs_subject=fs_subject)) prob_mask = surface.load_surf_data( fn.format(hemi=hemi, label='wang15_fplbl', fs_subject=fs_subject)) # print(prob_mask, op.exists(prob_mask)) label_mask = (prob_mask[18:24] > 0.05).any(0).astype(np.int16) ix_mask = np.where(label_mask)[0] ss = surf.create_subsurface(label_mask.astype(np.bool)) label_mask = ss.subsurface_vertex_mask print(len(pts), len(label_mask)) new_im = nb.MGHImage(label_mask, im.affine, im.header) new_im.to_filename( fn.format(hemi=hemi, label='wang15_ips', fs_subject=fs_subject))
def _reorient_image(img, axcodes='RAS'): """Reorient an image to a given orientation. Parameters ---------- img : instance of SpatialImage The MRI image. axcodes : tuple | str The axis codes specifying the orientation, e.g. "RAS". See :func:`nibabel.orientations.aff2axcodes`. Returns ------- img_data : ndarray The reoriented image data. vox_ras_t : ndarray The new transform from the new voxels to surface RAS. Notes ----- .. versionadded:: 0.24 """ import nibabel as nib orig_data = np.array(img.dataobj).astype(np.float32) # reorient data to RAS ornt = nib.orientations.axcodes2ornt( nib.orientations.aff2axcodes(img.affine)).astype(int) ras_ornt = nib.orientations.axcodes2ornt(axcodes) ornt_trans = nib.orientations.ornt_transform(ornt, ras_ornt) img_data = nib.orientations.apply_orientation(orig_data, ornt_trans) orig_mgh = nib.MGHImage(orig_data, img.affine) aff_trans = nib.orientations.inv_ornt_aff(ornt_trans, img.shape) vox_ras_t = np.dot(orig_mgh.header.get_vox2ras_tkr(), aff_trans) return img_data, vox_ras_t
def save_image(img_array, affine_info, header_info, save_as): """ Save an image (nibabel MGHImage), according to the desired output file format. Supported formats are defined in supported_output_file_formats. :param numpy.ndarray img_array: an array containing image data :param numpy.ndarray affine_info: image affine information :param nibabel.freesurfer.mghformat.MGHHeader header_info: image header information :param str save_as: name under which to save prediction; this determines output file format :return None: saves predictions to save_as """ assert any(save_as.endswith(file_ext) for file_ext in supported_output_file_formats), \ 'Output filename does not contain a supported file format (' + ', '.join(file_ext for file_ext in supported_output_file_formats) + ')!' mgh_img = None if save_as.endswith('mgz'): mgh_img = nib.MGHImage(img_array, affine_info, header_info) elif any(save_as.endswith(file_ext) for file_ext in ['nii', 'nii.gz']): mgh_img = nib.nifti1.Nifti1Pair(img_array, affine_info, header_info) if any(save_as.endswith(file_ext) for file_ext in ['mgz', 'nii']): nib.save(mgh_img, save_as) elif save_as.endswith('nii.gz'): ## For correct outputs, nii.gz files should be saved using the nifti1 sub-module's save(): nib.nifti1.save(mgh_img, save_as)
def _fake_CT_coords(skull_size=5, contact_size=2): """Make somewhat realistic CT data with contacts.""" import nibabel as nib brain = nib.load(op.join(subjects_dir, subject, 'mri', 'brain.mgz')) verts = mne.read_surface( op.join(subjects_dir, subject, 'bem', 'outer_skull.surf'))[0] verts = apply_trans(np.linalg.inv(brain.header.get_vox2ras_tkr()), verts) x, y, z = np.array(brain.shape).astype(int) // 2 coords = [(x, y - 14, z), (x - 10, y - 15, z), (x - 20, y - 16, z + 1), (x - 30, y - 16, z + 1)] center = np.array(brain.shape) / 2 # make image np.random.seed(99) ct_data = np.random.random(brain.shape).astype(np.float32) * 100 # make skull for vert in verts: x, y, z = np.round(vert).astype(int) ct_data[slice(x - skull_size, x + skull_size + 1), slice(y - skull_size, y + skull_size + 1), slice(z - skull_size, z + skull_size + 1)] = 1000 # add electrode with contacts for (x, y, z) in coords: # make sure not in skull assert np.linalg.norm(center - np.array((x, y, z))) < 50 ct_data[slice(x - contact_size, x + contact_size + 1), slice(y - contact_size, y + contact_size + 1), slice(z - contact_size, z + contact_size + 1)] = \ 1000 - np.linalg.norm(np.array(np.meshgrid( *[range(-contact_size, contact_size + 1)] * 3)), axis=0) ct = nib.MGHImage(ct_data, brain.affine) coords = apply_trans(ct.header.get_vox2ras_tkr(), np.array(coords)) return ct, coords
def epi_to_surf_xfm(epi_fname, reg_fname): """Obtain a transformation from epi voxels -> Freesurfer surf coords. Parameters ---------- epi_fname : string Filename pointing at image defining the epi space. reg_fname : string Filename pointing at registration file (from bbregister) that maps ``epi_img_fname`` to the Freesurfer anatomy. Returns ------- xfm : 4 x 4 numpy array Transformation matrix that can be applied to surf coords. """ # Load the Freesurfer "tkreg" style transform file # Confusingly, this file actually encodes the anat-to-func transform anat2func_xfm = np.genfromtxt(reg_fname, skip_header=4, skip_footer=1) func2anat_xfm = np.linalg.inv(anat2func_xfm) # Get a tkreg-compatibile mapping from IJK to RAS epi_img = nib.load(epi_fname) mgh_img = nib.MGHImage(np.zeros(epi_img.shape[:3]), epi_img.get_affine(), epi_img.get_header()) vox2ras_tkr = mgh_img.get_header().get_vox2ras_tkr() # Combine the two transformations xfm = np.dot(func2anat_xfm, vox2ras_tkr) return xfm
def asmgh(infile): outfile = op.basename(fslimage.removeExt(infile)) outfile = outfile + '.mgh' inimg = fslimage.Image(infile) outimg = nib.MGHImage(inimg.data, inimg.voxToWorldMat) outimg.to_filename(outfile) return outfile
def test_slice_browser_io(_slice_browser): """Test the input/output of the slice browser GUI.""" import nibabel as nib with pytest.raises(ValueError, match='Base image is not aligned to MRI'): _slice_browser(nib.MGHImage( np.ones((96, 96, 96), dtype=np.float32), np.eye(4)), subject=subject, subjects_dir=subjects_dir)
def mgh_from_sitk(sitk_img, orig_mgh_header=None): if orig_mgh_header: h1 = MGHHeader.from_header(orig_mgh_header) else: h1 = MGHHeader() # get voxels sizes and set zooms (=delta in h1 header) spacing = sitk_img.GetSpacing() h1.set_zooms(np.asarray(spacing)) # Get direction cosines from sitk image, reshape to 3x3 Matrix direction = np.asarray(sitk_img.GetDirection()).reshape( 3, 3, order="F") * [-1, -1, 1] h1["Mdc"] = direction # compute affine origin = np.asarray(sitk_img.GetOrigin()).reshape(3, 1) * [[-1], [-1], [1]] affine = np.vstack( [np.hstack([h1['Mdc'].T * h1["delta"], origin]), [0, 0, 0, 1]]) # get dims and calculate and set new image center in world coords dims = np.array(sitk_img.GetSize()) if dims.size == 3: dims = np.hstack((dims, [1])) h1['dims'] = dims h1['Pxyz_c'] = affine.dot(np.hstack((dims[:3] / 2.0, [1])))[:3] # swap axes as data is stored differently between sITK and Nibabel data = np.swapaxes(sitk.GetArrayFromImage(sitk_img), 0, 2) # assemble MGHImage from header, image data and affine mgh_img = nib.MGHImage(data, affine, h1) return mgh_img
def mric_RI(save, *args): import numpy as np import nibabel as nb target = args[0][0] vox2ras = nb.load(target).get_header().get_vox2ras() idata = nb.load(target).get_data() init = idata.reshape(1, -1)[0].astype("float32") for j in range(1, len(args[0])): i = args[0][j] temp = nb.load(i).get_data().reshape(1, -1)[0].astype("float32") rI2 = temp / init rI2[np.isnan(rI2)] = 1 # temp3 = rI2.reshape(idata.shape) img2 = nb.MGHImage(temp3.astype("float32"), vox2ras) print save + "/" + str(i).split("/")[-1] nb.save(img2, save + "/" + str(i).split("/")[-1])
def write(self, outfile): log.info('Writing output to ' + outfile) if outfile.endswith('.nii') or outfile.endswith('.nii.gz'): img = nib.Nifti1Image(self.out, self.m_rcs2ras) if outfile.endswith('.mgh') or outfile.endswith('.mgz'): self.out = self.out.astype(np.float32) img = nib.MGHImage(self.out, self.m_rcs2ras) nib.save(img, outfile)
def save_mgh(filename, array, demo): """ save mgh file using nibabel and imported demo mgh file""" mmap = np.memmap('/tmp/tmp', dtype='float32', mode='w+', shape=demo.get_data().shape) mmap[:, 0, 0] = array[:] output = nb.MGHImage(mmap, demo.affine, demo.header) nb.save(output, filename)
def test_ieeg_elec_locate_gui_io(_locate_ieeg): """Test the input/output of the intracranial location GUI.""" import nibabel as nib info = mne.create_info([], 1000) aligned_ct = nib.MGHImage(np.zeros((256, 256, 256), dtype=np.float32), np.eye(4)) trans = mne.transforms.Transform('head', 'mri') with pytest.raises(ValueError, match='No channels found in `info` to locate'): _locate_ieeg(info, trans, aligned_ct, subject, subjects_dir)
def freesurfer(lyman_info): subject = "subj01" mri_dir = lyman_info["data_dir"].join(subject).join("mri") label_dir = lyman_info["data_dir"].join(subject).join("label") seed = sum(map(ord, "freesurfer")) rs = np.random.RandomState(seed) affine = np.eye(4) vol_shape = lyman_info["vol_shape"] mask = rs.choice([0, 1], vol_shape, p=[.2, .8]) norm_data = rs.randint(0, 110, vol_shape) * mask norm_file = str(mri_dir.join("norm.mgz")) nib.save(nib.MGHImage(norm_data.astype("uint8"), affine), norm_file) orig_file = str(mri_dir.join("orig.mgz")) nib.save(nib.MGHImage(norm_data.astype("uint8"), affine), orig_file) wmparc_vals = [1000, 10, 11, 16, 8, 3000, 5001, 7, 46, 4] wmparc_data = rs.choice(wmparc_vals, vol_shape) * mask wmparc_file = str(mri_dir.join("wmparc.mgz")) nib.save(nib.MGHImage(wmparc_data.astype("int16"), affine), wmparc_file) n = 10 fmt = ["%d", "%.3f", "%.3f", "%.3f", "%.9f"] label_data = np.c_[np.arange(n), np.zeros((n, 4))] label_files = {} for hemi in ["lh", "rh"]: fname = str(label_dir.join("{}.cortex.label".format(hemi))) label_files[hemi] = fname np.savetxt(fname, label_data, fmt=fmt, header=str(n)) lyman_info.update( subject=subject, norm_file=norm_file, orig_file=orig_file, wmparc_file=wmparc_file, label_files=label_files, ) return lyman_info
def write(self, outfile): log.info('Writing output to ' + outfile) # if out datatype is float64 make it float32 if self.out.dtype == np.float64: self.out = self.out.astype(np.float32) if outfile.endswith('.nii') or outfile.endswith('.nii.gz'): img = nib.Nifti1Image(self.out, self.m_rcs2ras) if outfile.endswith('.mgh') or outfile.endswith('.mgz'): #self.out = self.out.astype(self.vol.dtype) img = nib.MGHImage(self.out, self.m_rcs2ras) nib.save(img, outfile)
def _ensure_image_in_surface_RAS(image, subject, subjects_dir): """Check if the image is in Freesurfer surface RAS space.""" import nibabel as nib if not isinstance(image, nib.spatialimages.SpatialImage): image = nib.load(image) image = nib.MGHImage(image.dataobj.astype(np.float32), image.affine) fs_img = nib.load(op.join(subjects_dir, subject, 'mri', 'brain.mgz')) if not np.allclose(image.affine, fs_img.affine, atol=1e-6): raise RuntimeError('The `image` is not aligned to Freesurfer ' 'surface RAS space. This space is required as ' 'it is the space where the anatomical ' 'segmentation and reconstructed surfaces are') return image # returns MGH image for header
def save_weights_as_datasurface(self, weights, output_dir): import numpy as np import nibabel as nib import os if self._images is None: self.get_images() sample = nib.load(self._images[0][0]) left_hemi_data = np.atleast_3d(weights[:weights.size / 2]) left_hemi_mgh = nib.MGHImage(left_hemi_data, affine=sample.affine, header=sample.header) nib.save(left_hemi_mgh, os.path.join(output_dir, 'weights_lh.mgh')) right_hemi_data = np.atleast_3d(weights[weights.size / 2:]) right_hemi_mgh = nib.MGHImage(right_hemi_data, affine=sample.affine, header=sample.header) nib.save(right_hemi_mgh, os.path.join(output_dir, 'weights_rh.mgh')) pass
def predict_segmentation(input_arr, model_name, header): batch_size = 10 count = 0 result = [] model = torch.load('api/pytorch_models/' + model_name + '.model') input_arr = input_arr.reshape( (-1, 1, input_arr.shape[-2], input_arr.shape[-1])) if model_name == "quicknat": input_arr = np.transpose(input_arr, [0, 1, 3, 2]) while count <= input_arr.shape[0]: last_index = count + batch_size - 1 if last_index > input_arr.shape[0]: last_index = input_arr.shape[0] out = model( Variable(torch.Tensor(input_arr[count:last_index]).cuda(), volatile=True)) result.append(out) count += batch_size - 1 result = torch.cat(result) result = F.softmax(result, dim=1) max_val, idx = torch.max(result, 1) idx = idx.data.cpu().numpy() color_map = [ label for label in SEG_LABELS_LIST[model_name] if label["id"] != 0 ] stats = {'color_map': color_map} if model_name == "quicknat": idx = np.transpose(idx, [0, 2, 1]) indexes, counts = np.unique(np.ravel(idx), return_counts=True) indexes = indexes[1:] counts = counts[1:] indexes = [str(i) for i in indexes] counts = [str(c) for c in counts] stats['volume_estimates'] = dict(zip(indexes, counts)) feature_matrix = np.loadtxt('api/age_estimation/feature_matrix.csv') predicted_age, uncertainty = estimate_age( np.expand_dims(feature_matrix[1], axis=0), 'api/age_estimation/gpr_model.sav', 'api/age_estimation/gpr_scaler.sav') stats['predicted_age'] = np.round(predicted_age[0], 2) stats['predicted_age_uncertainty'] = np.round(uncertainty[0], 2) # Create a new file nifti_img = nib.MGHImage(idx, np.eye(4), header=header) result = np.array([label_img_to_rgb(frame, model_name) for frame in idx]) return {'result': result, 'stats': stats, 'nifti_img': nifti_img}
def conform(img, order=1): """ Python version of mri_convert -c, which turns image intensity values into UCHAR, reslices images to standard position, fills up slices to standard 256x256x256 format and enforces 1 mm isotropic voxel sizes. Difference to mri_convert -c is that we first interpolate (float image), and then rescale to uchar. mri_convert is doing it the other way. However, we compute the scale factor from the input to be more similar again :param nibabel.MGHImage img: loaded source image :param int order: interpolation order (0=nearest,1=linear(default),2=quadratic,3=cubic) :return:nibabel.MGHImage new_img: conformed image """ from nibabel.freesurfer.mghformat import MGHHeader cwidth = 256 csize = 1 h1 = MGHHeader.from_header( img.header) # may copy some parameters if input was MGH format h1.set_data_shape([cwidth, cwidth, cwidth, 1]) h1.set_zooms([csize, csize, csize]) h1['Mdc'] = [[-1, 0, 0], [0, 0, -1], [0, 1, 0]] h1['fov'] = cwidth h1['Pxyz_c'] = img.affine.dot( np.hstack((np.array(img.shape[:3]) / 2.0, [1])))[:3] # from_header does not compute Pxyz_c (and probably others) when importing from nii # Pxyz is the center of the image in world coords # get scale for conversion on original input before mapping to be more similar to mri_convert src_min, scale = getscale(img.get_data(), 0, 255) mapped_data = map_image(img, h1.get_affine(), h1.get_data_shape(), order=order) # print("max: "+format(np.max(mapped_data))) if not img.get_data_dtype() == np.dtype(np.uint8): if np.max(mapped_data) > 255: mapped_data = scalecrop(mapped_data, 0, 255, src_min, scale) new_data = np.uint8(np.rint(mapped_data)) new_img = nib.MGHImage(new_data, h1.get_affine(), h1) # make sure we store uchar new_img.set_data_dtype(np.uint8) return new_img
def synthesize_image(self, in_img_file, out_img_filename, step_size): in_img = nib.load(in_img_file) (in_patches, in_indices, padded_img_size) = self.feature_generator.extract_patches(in_img_file, intensity_threshold=0, step_size=step_size, is_label_img=False, indices=None) out_patches = self.model.predict(in_patches) patch_crop_size = [1, 1, 1] # should be filter_size/2 out_img_data, count_img_data = self.feature_generator.build_image_from_patches(out_patches, in_indices, padded_img_size, patch_crop_size) out_img_data = intensity_standardize_utils.wm_peak_normalize(out_img_data) out_img_data[out_img_data > 255] = 255 out_img = nib.MGHImage(out_img_data, in_img.affine, in_img.header) nib.save(out_img, out_img_filename)
def avgerage_brainimg_pr(projectdir, sessidlist, funcname, analysis_name, runlist, savepath, outfmt="mgz"): """Average result per run after doing zscore, doing to all sessions. Parameters ---------- projectdir: name of where your session data placed, type: str. sessidlist: list of sessid, type: list[str]. funcname: name of your func, under sessid dir. analysis_name: analysis dir name in mkanalysis-sess. runlist: list of runid. savepath: dir of where to put average result file. outfmt: suffix of out file. """ for runid in runlist: prid = "pr%s" % runid check_dir(savepath) result_name = "mean_res_%s.%s" % (runid, outfmt) result_path = os.path.join(savepath, result_name) data = [] for sessid in sessidlist: fileroot = os.path.join(projectdir, sessid, funcname, analysis_name, prid, "res") filename = "res-%s.nii.gz" % runid filepath = os.path.join(fileroot, filename) print("loading %s" % filepath) result_run = nib.load(filepath) result_data = stats.zscore(result_run.get_data()[:, 0, 0, :], axis=1) # doing zscore before average. data.append(result_data) print("Shape of img: {}: ".format(np.shape(data))) avg_data = np.mean(data, axis=0) print("Shape of avg_data: {}: ".format(np.shape(avg_data))) avg_data = np.reshape(avg_data, result_run.shape) data_file = nib.MGHImage(avg_data, None, result_run.get_header()) nib.save(data_file, result_path) print("Saving %s" % result_path) print("===" * 10)
def test_lossless_slice_noscaling(tmp_path): fname = tmp_path / 'image.mgh' img = nb.MGHImage(np.random.uniform(-20000, 20000, (5, 5, 5, 5)).astype("float32"), affine=np.eye(4)) img.to_filename(fname) img1 = nb.load(fname) sliced_fname = tmp_path / 'sliced.mgh' lossless_slice( img1, (slice(None), slice(None), slice(2, 4))).to_filename(sliced_fname) img2 = nb.load(sliced_fname) assert np.array_equal(img1.get_fdata()[:, :, 2:4], img2.get_fdata()) assert np.array_equal(img1.dataobj.get_unscaled()[:, :, 2:4], img2.dataobj.get_unscaled()) assert img1.dataobj.slope == img2.dataobj.slope assert img1.dataobj.inter == img2.dataobj.inter
def save2mgh(fpath, data, affine=None, header=None): """ Save to a MGH/MGZ file The .mgh file format is used to store high-resolution structural data and other data which are to be overlaid on the high-resolution structural volume. A .mgz (or .mgh.gz) file is a .mgh file that has been compressed with ZLib. NOTE!!! MGH file format seemingly has 3D dimensions at least. As a result, it essentially regards the first dimensions as a volume and the forth dimension as the number of volumes. References: https://surfer.nmr.mgh.harvard.edu/fswiki/FsTutorial/MghFormat http://nipy.org/nibabel/reference/nibabel.freesurfer.html#nibabel.freesurfer.mghformat.MGHImage :param fpath: str The file path to output. valid_exts = ('.mgh', '.mgz') :param data: numpy array :param affine: numpy array :param header: MGHHeader """ img = nib.MGHImage(data, affine, header=header) nib.save(img, fpath)
def save_brainimg(imgpath, data, header): """ Save brain image identified by its suffix suffix now support Nifti: .nii.gz freesurfer: .mgz, .mgh cifti: .dscalar.nii, .dlabel.nii, .dtseries.nii Parameters: ------------ imgpath: brain image path to be saved data: brain image data matrix header: brain image header Returns: -------- """ imgname = os.path.basename(imgpath) imgsuffix = imgname.split('.')[1:] imgsuffix = '.'.join(imgsuffix) if imgsuffix == 'nii.gz': data = np.transpose(data, (1, 2, 3, 0)) outimg = nib.Nifti1Image(data, None, header) nib.save(outimg, imgpath) elif imgsuffix == 'mgz' or imgsuffix == 'mgh': data = np.transpose(data, (1, 2, 3, 0)) outimg = nib.MGHImage(data, None, header) nib.save(outimg, imgpath) elif imgsuffix == 'dscalar.nii' or imgsuffix == 'dlabel.nii' or imgsuffix == 'dtseries.nii': data = data[..., 0, 0] map_name = [''] * data.shape[0] bm_full = header[1] cifti.write(imgpath, data, (cifti.Scalar.from_names(map_names), bm_full)) else: raise Exception( 'Not support this format of brain image data, please contact with author to update this function.' )
def get_diff_data(editp, uneditp, vol, subnum, savediff, diffp): # Calculate difference image if vol == "brain.finalsurfs": edit_img = nib.load(path.join(editp, 'mri/%s.manedit.mgz') % (vol)) else: edit_img = nib.load(path.join(editp, 'mri/%s.mgz') % (vol)) edit_data = edit_img.get_fdata() unedit_img = nib.load( path.join(uneditp, 'sub-%s/mri/%s.mgz') % (subnum, vol)) unedit_data = unedit_img.get_fdata() diff_data = unedit_data - edit_data if savediff: diff_img = nib.MGHImage(diff_data.astype(np.int32), edit_img.affine) nib.save(diff_img, os.path.join(diffp, 'diff_%s.mgz') % (vol)) # Extract non-zero values from difference data and arrange in df out = pd.DataFrame(np.asarray( np.asarray(diff_data != 0).nonzero()).T).rename(columns={ 0: "Sag", 1: "Axe", 2: "Cor" }) out['diff_val'] = diff_data[np.where(diff_data != 0)] out['Action'] = np.where(out.diff_val > 0, "delete voxel", "add voxel") # When WM edits are not perfect it can look like voxel additions # For the clarity of the summary drop these if vol == "wm" or vol == "brainmask": out = out.query("diff_val != -1") out = out.drop(columns="diff_val") out['Vol'] = vol out = out.sort_values(by=['Cor']) out.reset_index(drop=True) return (out)
def main(subject, bids_folder): (pts_l, poly_l), (pts_r, poly_r) = cortex.db.get_surf(f'sub-{subject}', 'pia') surf_l = cortex.polyutils.Surface(pts_l, poly_l) surf_r = cortex.polyutils.Surface(pts_r, poly_r) for hemi, surf in [('lh', surf_l), ('rh', surf_r)]: im = nb.load(op.join(bids_folder, 'derivatives', 'freesurfer', f'sub-{subject}', 'surf', f'{hemi}.wang15_ips.mgz')) mask = np.squeeze(im.get_data().astype(bool)) print(mask.sum()) ss = surf.create_subsurface(mask) nlverts = len(ss.pts) dist_matrix = np.zeros((nlverts, nlverts)) for i in tqdm(range(len(dist_matrix))): dist_matrix[i] = ss.geodesic_distance(i) v1 = dist_matrix[np.triu_indices(nlverts, k = 1)] v2 = dist_matrix[np.tril_indices(nlverts, k = -1)] v = (v1 + v2) / 2. # see https://stackoverflow.com/questions/17527693/transform-the-upper-lower-triangular-part-of-a-symmetric-matrix-2d-array-into/58806626#58806626 dist_matrix_ = np.zeros((nlverts,nlverts)) dist_matrix_[np.triu_indices(nlverts, k = 1)] = v dist_matrix_ = dist_matrix_ + dist_matrix_.T print(dist_matrix - dist_matrix_) print(np.array_equal(dist_matrix, dist_matrix_)) # im = gifti.GiftiImage(darrays=[gifti.GiftiDataArray(v)]) # im.to_filename(op.join(bids_folder, 'derivatives', 'freesurfer', f'sub-{subject}', 'surf', f'{hemi}.wang15_ips_distance.gii')) new_im = nb.MGHImage(v, im.affine, im.header) new_im.to_filename(op.join(bids_folder, 'derivatives', 'freesurfer', f'sub-{subject}', 'surf', f'{hemi}.wang15_ips_distance.mgz'))
def test_inject_skullstrip(tmp_path): t1_mgz = tmp_path / "sub-01" / "mri" / "T1.mgz" t1_mgz.parent.mkdir(parents=True) # T1.mgz images are uint8 nb.MGHImage(np.ones((5, 5, 5), dtype=np.uint8), np.eye(4)).to_filename(str(t1_mgz)) mask_nii = tmp_path / "mask.nii.gz" # Masks may be in a different space (and need resampling), but should be boolean, # or uint8 in NIfTI nb.Nifti1Image(np.ones((6, 6, 6), dtype=np.uint8), np.eye(4)).to_filename( str(mask_nii) ) FSInjectBrainExtracted( subjects_dir=str(tmp_path), subject_id="sub-01", in_brain=str(mask_nii) ).run() assert Path.exists(tmp_path / "sub-01" / "mri" / "brainmask.auto.mgz") assert Path.exists(tmp_path / "sub-01" / "mri" / "brainmask.mgz") # Run a second time to hit "already exists" condition FSInjectBrainExtracted( subjects_dir=str(tmp_path), subject_id="sub-01", in_brain=str(mask_nii) ).run()