def assert_compare_nifti(nifti_file_1, nifti_file_2): logging.info("%s %s" % (nifti_file_1, nifti_file_2)) work_dir = tempfile.mkdtemp() try: tmp_nifti_file_1 = os.path.join(work_dir, os.path.basename(nifti_file_1)) tmp_nifti_file_2 = os.path.join(work_dir, os.path.basename(nifti_file_2)) image_reorientation.reorient_image(nifti_file_1, tmp_nifti_file_1) image_reorientation.reorient_image(nifti_file_2, tmp_nifti_file_2) nifti_1 = nibabel.load(tmp_nifti_file_1) nifti_2 = nibabel.load(tmp_nifti_file_2) # check the affine if not numpy.allclose(nifti_1.affine, nifti_2.affine): raise Exception('affine mismatch') # check the data if nifti_1.get_data_dtype() != nifti_2.get_data_dtype(): raise Exception('dtype mismatch') if not numpy.allclose(get_nifti_data(nifti_1), get_nifti_data(nifti_2), rtol=0.01, atol=1): difference = get_nifti_data(nifti_1) - get_nifti_data(nifti_2) raise Exception('data mismatch %s ' % numpy.max(numpy.abs(difference))) except: shutil.rmtree(work_dir) raise
def __init__(self, nifti_image): self.nifti = nifti_image # assert that it is a 3D image self.nifti_data = get_nifti_data(self.nifti) assert self.nifti_data.squeeze().ndim >= 3 # do some basic processing like setting dimensions and min/max values self.dimensions = self.nifti_data.shape self.axial_orientation = None self.coronal_orientation = None self.sagittal_orientation = None self.__calculate_slice_orientation__()
def _fix_diffusion_images(bvals, bvecs, nifti, nifti_file): """ This function will remove the last timepoint from the nifti, bvals and bvecs if the last vector is 0,0,0 This is sometimes added at the end by philips """ # if all zero continue of if the last bvec is not all zero continue if numpy.count_nonzero(bvecs) == 0 or not numpy.count_nonzero( bvals[-1]) == 0: # nothing needs to be done here return nifti, bvals, bvecs # remove last elements from bvals and bvecs bvals = bvals[:-1] bvecs = bvecs[:-1] # remove last elements from the nifti new_nifti = nibabel.Nifti1Image( common.get_nifti_data(nifti)[:, :, :, :-1].squeeze(), nifti.affine) new_nifti.to_filename(nifti_file) return new_nifti, bvals, bvecs
def resample_nifti_images(nifti_images, voxel_size=None): """ In this function we will create an orthogonal image and resample the original images to this space In this calculation we work in 3 spaces / coordinate systems - original image coordinates - world coordinates - "projected" coordinates This last one is a new rotated "orthogonal" coordinates system in mm where x and y are perpendicular with the x and y or the image We do the following steps - calculate a new "projection" coordinate system - calculate the world coordinates of all corners of the image in world coordinates - project the world coordinates of the corners on the projection coordinate system - calculate the min and max corners to get the orthogonal bounding box of the image in projected space - translate the origin back to world coordinages We now have the new xyz axis, origin and size and can create the new affine used for resampling """ # get the smallest voxelsize and use that if voxel_size is None: voxel_size = nifti_images[0].header.get_zooms() for nifti_image in nifti_images[1:]: voxel_size = numpy.minimum(voxel_size, nifti_image.header.get_zooms()) x_axis_world = numpy.transpose( numpy.dot(nifti_images[0].affine, [[1], [0], [0], [0]]))[0, :3] y_axis_world = numpy.transpose( numpy.dot(nifti_images[0].affine, [[0], [1], [0], [0]]))[0, :3] x_axis_world /= numpy.linalg.norm(x_axis_world) # normalization y_axis_world /= numpy.linalg.norm(y_axis_world) # normalization z_axis_world = numpy.cross(y_axis_world, x_axis_world) z_axis_world /= numpy.linalg.norm(z_axis_world) # calculate new z y_axis_world = numpy.cross( x_axis_world, z_axis_world) # recalculate y in case x and y where not perpendicular y_axis_world /= numpy.linalg.norm(y_axis_world) points_world = [] for nifti_image in nifti_images: original_size = nifti_image.shape points_image = [[0, 0, 0], [original_size[0] - 1, 0, 0], [0, original_size[1] - 1, 0], [original_size[0] - 1, original_size[1] - 1, 0], [0, 0, original_size[2] - 1], [original_size[0] - 1, 0, original_size[2] - 1], [0, original_size[1] - 1, original_size[2] - 1], [ original_size[0] - 1, original_size[1] - 1, original_size[2] - 1 ]] for point in points_image: points_world.append( numpy.transpose( numpy.dot( nifti_image.affine, [[point[0]], [point[1]], [point[2]], [1]]))[0, :3]) projections = [] for point in points_world: projection = [ numpy.dot(point, x_axis_world), numpy.dot(point, y_axis_world), numpy.dot(point, z_axis_world) ] projections.append(projection) projections = numpy.array(projections) min_projected = numpy.amin(projections, axis=0) max_projected = numpy.amax(projections, axis=0) new_size_mm = max_projected - min_projected origin = min_projected[0] * x_axis_world + \ min_projected[1] * y_axis_world + \ min_projected[2] * z_axis_world new_voxelsize = voxel_size new_shape = numpy.ceil(new_size_mm / new_voxelsize).astype(numpy.int16) + 1 new_affine = _create_affine(x_axis_world, y_axis_world, z_axis_world, origin, voxel_size) # Resample each image combined_image_data = numpy.full(new_shape, settings.resample_padding, dtype=get_nifti_data( nifti_images[0]).dtype) for nifti_image in nifti_images: image_affine = nifti_image.affine combined_affine = numpy.linalg.inv(new_affine).dot(image_affine) matrix, offset = nibabel.affines.to_matvec( numpy.linalg.inv(combined_affine)) resampled_image = scipy.ndimage.affine_transform( get_nifti_data(nifti_image), matrix=matrix, offset=offset, output_shape=new_shape, output=get_nifti_data(nifti_image).dtype, order=settings.resample_spline_interpolation_order, mode='constant', cval=settings.resample_padding, prefilter=False) combined_image_data[combined_image_data == settings.resample_padding] = \ resampled_image[combined_image_data == settings.resample_padding] return nibabel.Nifti1Image(combined_image_data.squeeze(), new_affine)