def __init__(self, param=None, hdr=None, orientation=None, absolutepath="", verbose=1): from numpy import zeros, ndarray, generic from sct_utils import extract_fname from nibabel import AnalyzeHeader # initialization of all parameters self.verbose = verbose self.data = None self.absolutepath = "" self.path = "" self.file_name = "" self.ext = "" self.orientation = None if hdr == None: hdr = AnalyzeHeader() self.hdr = AnalyzeHeader() #an empty header else: self.hdr = hdr self.dim = None self.verbose = verbose # load an image from file if type(param) is str: self.loadFromPath(param, verbose) # copy constructor elif isinstance(param, type(self)): self.copy(param) # create an empty image (full of zero) of dimension [dim]. dim must be [x,y,z] or (x,y,z). No header. elif type(param) is list: self.data = zeros(param) self.dim = param self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) # create a copy of im_ref elif isinstance(param, (ndarray, generic)): self.data = param self.dim = self.data.shape self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) else: raise TypeError(' Image constructor takes at least one argument.')
def __init__(self, param=None, hdr=None, orientation=None, absolutepath="", verbose=1): from numpy import zeros, ndarray, generic from sct_utils import extract_fname from nibabel import AnalyzeHeader # initialization of all parameters self.verbose = verbose self.data = None self.absolutepath = "" self.path = "" self.file_name = "" self.ext = "" self.orientation = None if hdr == None: hdr = AnalyzeHeader() self.hdr = AnalyzeHeader() # an empty header else: self.hdr = hdr self.dim = None self.verbose = verbose # load an image from file if type(param) is str: self.loadFromPath(param, verbose) # copy constructor elif isinstance(param, type(self)): self.copy(param) # create an empty image (full of zero) of dimension [dim]. dim must be [x,y,z] or (x,y,z). No header. elif type(param) is list: self.data = zeros(param) self.dim = param self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) # create a copy of im_ref elif isinstance(param, (ndarray, generic)): self.data = param self.dim = self.data.shape self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) else: raise TypeError(" Image constructor takes at least one argument.")
def ReadAnalyze(filename): print "Reading analyze file:", filename # Reading info from analyze header header_file = open(filename) header = AnalyzeHeader.from_fileobj(header_file) xf, yf, zf = header.get_data_shape()[:3] data_type = header.get_data_dtype().name pixel_spacing = header.get_zooms()[:3] # Mapping from numpy type to vtk type. anlz_2_vtk_type = { 'int16': 'SetDataScalarTypeToShort', 'uint16': 'SetDataScalarTypeToUnsignedShort', 'float32': 'SetDataScalarTypeToFloat' } print header reader = vtk.vtkImageReader() reader.SetFileName(filename[:-3] + 'img') # Setting the endiannes based on the analyze header. if header.endianness == '<': reader.SetDataByteOrderToLittleEndian() elif header.endianness == '>': reader.SetDataByteOrderToBigEndian() reader.SetFileDimensionality(3) reader.SetDataExtent(0, xf-1, 0, yf-1, 0, zf-1) reader.SetDataSpacing(pixel_spacing) reader.SetHeaderSize(0) # reader.SetTransform(transform) getattr(reader, anlz_2_vtk_type[data_type])() reader.Update() return reader.GetOutput()
class Image(object): """ """ def __init__(self, param=None, hdr=None, orientation=None, absolutepath="", verbose=1): from numpy import zeros, ndarray, generic from sct_utils import extract_fname from nibabel import AnalyzeHeader # initialization of all parameters self.verbose = verbose self.data = None self.absolutepath = "" self.path = "" self.file_name = "" self.ext = "" self.orientation = None if hdr == None: hdr = AnalyzeHeader() self.hdr = AnalyzeHeader() #an empty header else: self.hdr = hdr self.dim = None self.verbose = verbose # load an image from file if type(param) is str: self.loadFromPath(param, verbose) # copy constructor elif isinstance(param, type(self)): self.copy(param) # create an empty image (full of zero) of dimension [dim]. dim must be [x,y,z] or (x,y,z). No header. elif type(param) is list: self.data = zeros(param) self.dim = param self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) # create a copy of im_ref elif isinstance(param, (ndarray, generic)): self.data = param self.dim = self.data.shape self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) else: raise TypeError(' Image constructor takes at least one argument.') def __deepcopy__(self, memo): from copy import deepcopy return type(self)(deepcopy(self.data, memo), deepcopy(self.hdr, memo), deepcopy(self.orientation, memo), deepcopy(self.absolutepath, memo)) def copy(self, image=None): from copy import deepcopy from sct_utils import extract_fname if image is not None: self.data = deepcopy(image.data) self.dim = deepcopy(image.dim) self.hdr = deepcopy(image.hdr) self.orientation = deepcopy(image.orientation) self.absolutepath = deepcopy(image.absolutepath) self.path, self.file_name, self.ext = extract_fname( self.absolutepath) else: return deepcopy(self) def loadFromPath(self, path, verbose): """ This function load an image from an absolute path using nibabel library :param path: path of the file from which the image will be loaded :return: """ from nibabel import load, spatialimages from sct_utils import check_file_exist, printv, extract_fname, get_dimension from sct_orientation import get_orientation check_file_exist(path, verbose=verbose) try: im_file = load(path) except spatialimages.ImageFileError: printv('Error: make sure ' + path + ' is an image.', 1, 'error') self.orientation = get_orientation(path) self.data = im_file.get_data() self.hdr = im_file.get_header() self.absolutepath = path self.path, self.file_name, self.ext = extract_fname(path) nx, ny, nz, nt, px, py, pz, pt = get_dimension(path) self.dim = [nx, ny, nz] def setFileName(self, filename): from sct_utils import extract_fname self.absolutepath = filename self.path, self.file_name, self.ext = extract_fname(filename) def changeType(self, type=''): from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64, float32, float64 """ Change the voxel type of the image :param type: if not set, the image is saved in standard type if 'minimize', image space is minimize if 'minimize_int', image space is minimize and values are approximated to integers (2, 'uint8', np.uint8, "NIFTI_TYPE_UINT8"), (4, 'int16', np.int16, "NIFTI_TYPE_INT16"), (8, 'int32', np.int32, "NIFTI_TYPE_INT32"), (16, 'float32', np.float32, "NIFTI_TYPE_FLOAT32"), (32, 'complex64', np.complex64, "NIFTI_TYPE_COMPLEX64"), (64, 'float64', np.float64, "NIFTI_TYPE_FLOAT64"), (256, 'int8', np.int8, "NIFTI_TYPE_INT8"), (512, 'uint16', np.uint16, "NIFTI_TYPE_UINT16"), (768, 'uint32', np.uint32, "NIFTI_TYPE_UINT32"), (1024,'int64', np.int64, "NIFTI_TYPE_INT64"), (1280, 'uint64', np.uint64, "NIFTI_TYPE_UINT64"), (1536, 'float128', _float128t, "NIFTI_TYPE_FLOAT128"), (1792, 'complex128', np.complex128, "NIFTI_TYPE_COMPLEX128"), (2048, 'complex256', _complex256t, "NIFTI_TYPE_COMPLEX256"), :return: """ if type == '': type = self.hdr.get_data_dtype() if type == 'minimize' or type == 'minimize_int': from numpy import nanmax, nanmin # compute max value in the image and choose the best pixel type to represent all the pixels within smallest memory space # warning: does not take intensity resolution into account, neither complex voxels max_vox = nanmax(self.data) min_vox = nanmin(self.data) # check if voxel values are real or integer isInteger = True if type == 'minimize': for vox in self.data.flatten(): if int(vox) != vox: isInteger = False break if isInteger: from numpy import iinfo, uint8, uint16, uint32, uint64 if min_vox >= 0: # unsigned if max_vox <= iinfo(uint8).max: type = 'uint8' elif max_vox <= iinfo(uint16): type = 'uint16' elif max_vox <= iinfo(uint32).max: type = 'uint32' elif max_vox <= iinfo(uint64).max: type = 'uint64' else: raise ValueError( "Maximum value of the image is to big to be represented." ) else: if max_vox <= iinfo(int8).max and min_vox >= iinfo( int8).min: type = 'int8' elif max_vox <= iinfo(int16).max and min_vox >= iinfo( int16).min: type = 'int16' elif max_vox <= iinfo(int32).max and min_vox >= iinfo( int32).min: type = 'int32' elif max_vox <= iinfo(int64).max and min_vox >= iinfo( int64).min: type = 'int64' else: raise ValueError( "Maximum value of the image is to big to be represented." ) else: from numpy import finfo, float32, float64 # if max_vox <= np.finfo(np.float16).max and min_vox >= np.finfo(np.float16).min: # type = 'np.float16' # not supported by nibabel if max_vox <= finfo(float32).max and min_vox >= finfo( float32).min: type = 'float32' elif max_vox <= finfo(float64).max and min_vox >= finfo( float64).min: type = 'float64' # print "The image has been set to "+type+" (previously "+str(self.hdr.get_data_dtype())+")" # change type of data in both numpy array and nifti header type_build = eval(type) self.data = type_build(self.data) self.hdr.set_data_dtype(type) def save(self, type=''): """ Write an image in a nifti file :param type: if not set, the image is saved in standard type if 'minimize', image space is minimize (2, 'uint8', np.uint8, "NIFTI_TYPE_UINT8"), (4, 'int16', np.int16, "NIFTI_TYPE_INT16"), (8, 'int32', np.int32, "NIFTI_TYPE_INT32"), (16, 'float32', np.float32, "NIFTI_TYPE_FLOAT32"), (32, 'complex64', np.complex64, "NIFTI_TYPE_COMPLEX64"), (64, 'float64', np.float64, "NIFTI_TYPE_FLOAT64"), (256, 'int8', np.int8, "NIFTI_TYPE_INT8"), (512, 'uint16', np.uint16, "NIFTI_TYPE_UINT16"), (768, 'uint32', np.uint32, "NIFTI_TYPE_UINT32"), (1024,'int64', np.int64, "NIFTI_TYPE_INT64"), (1280, 'uint64', np.uint64, "NIFTI_TYPE_UINT64"), (1536, 'float128', _float128t, "NIFTI_TYPE_FLOAT128"), (1792, 'complex128', np.complex128, "NIFTI_TYPE_COMPLEX128"), (2048, 'complex256', _complex256t, "NIFTI_TYPE_COMPLEX256"), """ from nibabel import Nifti1Image, save from sct_utils import printv if type != '': self.changeType(type) self.hdr.set_data_shape(self.data.shape) img = Nifti1Image(self.data, None, self.hdr) printv('saving ' + self.path + self.file_name + self.ext + '\n', verbose=self.verbose, type='normal') save(img, self.path + self.file_name + self.ext) # flatten the array in a single dimension vector, its shape will be (d, 1) compared to the flatten built in method # which would have returned (d,) def flatten(self): # return self.data.flatten().reshape(self.data.flatten().shape[0], 1) return self.data.flatten() # return a list of the image slices flattened def slices(self): slices = [] for slc in self.data: slices.append(slc.flatten()) return slices def getNonZeroCoordinates(self, sorting=None, reverse_coord=False, coordValue=False): """ This function return all the non-zero coordinates that the image contains. Coordinate list can also be sorted by x, y, z, or the value with the parameter sorting='x', sorting='y', sorting='z' or sorting='value' If reverse_coord is True, coordinate are sorted from larger to smaller. """ from msct_types import Coordinate from sct_utils import printv try: if len(self.dim) == 3: X, Y, Z = (self.data > 0).nonzero() list_coordinates = [ Coordinate([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] elif len(self.dim) == 2: X, Y = (self.data > 0).nonzero() list_coordinates = [ Coordinate([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X)) ] except Exception, e: printv( 'ERROR: Exception ' + str(e) + ' caught while geting non Zeros coordinates', 1, 'error') if coordValue: from msct_types import CoordinateValue if len(self.dim) == 3: list_coordinates = [ CoordinateValue( [X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] else: list_coordinates = [ CoordinateValue([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X)) ] else: from msct_types import Coordinate if len(self.dim) == 3: list_coordinates = [ Coordinate([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] else: list_coordinates = [ Coordinate([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X)) ] if sorting is not None: if reverse_coord not in [True, False]: raise ValueError('reverse_coord parameter must be a boolean') if sorting == 'x': list_coordinates = sorted(list_coordinates, key=lambda obj: obj.x, reverse=reverse_coord) elif sorting == 'y': list_coordinates = sorted(list_coordinates, key=lambda obj: obj.y, reverse=reverse_coord) elif sorting == 'z': list_coordinates = sorted(list_coordinates, key=lambda obj: obj.z, reverse=reverse_coord) elif sorting == 'value': list_coordinates = sorted(list_coordinates, key=lambda obj: obj.value, reverse=reverse_coord) else: raise ValueError( "sorting parameter must be either 'x', 'y', 'z' or 'value'" ) return list_coordinates
class Image(object): """ """ def __init__(self, param=None, hdr=None, orientation=None, absolutepath="", verbose=1): from numpy import zeros, ndarray, generic from sct_utils import extract_fname from nibabel import AnalyzeHeader # initialization of all parameters self.verbose = verbose self.data = None self.absolutepath = "" self.path = "" self.file_name = "" self.ext = "" self.orientation = None if hdr == None: hdr = AnalyzeHeader() self.hdr = AnalyzeHeader() # an empty header else: self.hdr = hdr self.dim = None self.verbose = verbose # load an image from file if type(param) is str: self.loadFromPath(param, verbose) # copy constructor elif isinstance(param, type(self)): self.copy(param) # create an empty image (full of zero) of dimension [dim]. dim must be [x,y,z] or (x,y,z). No header. elif type(param) is list: self.data = zeros(param) self.dim = param self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) # create a copy of im_ref elif isinstance(param, (ndarray, generic)): self.data = param self.dim = self.data.shape self.hdr = hdr self.orientation = orientation self.absolutepath = absolutepath self.path, self.file_name, self.ext = extract_fname(absolutepath) else: raise TypeError(" Image constructor takes at least one argument.") def __deepcopy__(self, memo): from copy import deepcopy return type(self)( deepcopy(self.data, memo), deepcopy(self.hdr, memo), deepcopy(self.orientation, memo), deepcopy(self.absolutepath, memo), ) def copy(self, image=None): from copy import deepcopy from sct_utils import extract_fname if image is not None: self.data = deepcopy(image.data) self.dim = deepcopy(image.dim) self.hdr = deepcopy(image.hdr) self.orientation = deepcopy(image.orientation) self.absolutepath = deepcopy(image.absolutepath) self.path, self.file_name, self.ext = extract_fname(self.absolutepath) else: return deepcopy(self) def loadFromPath(self, path, verbose): """ This function load an image from an absolute path using nibabel library :param path: path of the file from which the image will be loaded :return: """ from nibabel import load, spatialimages from sct_utils import check_file_exist, printv, extract_fname, get_dimension from sct_orientation import get_orientation check_file_exist(path, verbose=verbose) try: im_file = load(path) except spatialimages.ImageFileError: printv("Error: make sure " + path + " is an image.", 1, "error") self.orientation = get_orientation(path) self.data = im_file.get_data() self.hdr = im_file.get_header() self.absolutepath = path self.path, self.file_name, self.ext = extract_fname(path) nx, ny, nz, nt, px, py, pz, pt = get_dimension(path) self.dim = [nx, ny, nz] def setFileName(self, filename): from sct_utils import extract_fname self.absolutepath = filename self.path, self.file_name, self.ext = extract_fname(filename) def changeType(self, type=""): from numpy import uint8, uint16, uint32, uint64, int8, int16, int32, int64, float32, float64 """ Change the voxel type of the image :param type: if not set, the image is saved in standard type if 'minimize', image space is minimize if 'minimize_int', image space is minimize and values are approximated to integers (2, 'uint8', np.uint8, "NIFTI_TYPE_UINT8"), (4, 'int16', np.int16, "NIFTI_TYPE_INT16"), (8, 'int32', np.int32, "NIFTI_TYPE_INT32"), (16, 'float32', np.float32, "NIFTI_TYPE_FLOAT32"), (32, 'complex64', np.complex64, "NIFTI_TYPE_COMPLEX64"), (64, 'float64', np.float64, "NIFTI_TYPE_FLOAT64"), (256, 'int8', np.int8, "NIFTI_TYPE_INT8"), (512, 'uint16', np.uint16, "NIFTI_TYPE_UINT16"), (768, 'uint32', np.uint32, "NIFTI_TYPE_UINT32"), (1024,'int64', np.int64, "NIFTI_TYPE_INT64"), (1280, 'uint64', np.uint64, "NIFTI_TYPE_UINT64"), (1536, 'float128', _float128t, "NIFTI_TYPE_FLOAT128"), (1792, 'complex128', np.complex128, "NIFTI_TYPE_COMPLEX128"), (2048, 'complex256', _complex256t, "NIFTI_TYPE_COMPLEX256"), :return: """ if type == "": type = self.hdr.get_data_dtype() if type == "minimize" or type == "minimize_int": from numpy import nanmax, nanmin # compute max value in the image and choose the best pixel type to represent all the pixels within smallest memory space # warning: does not take intensity resolution into account, neither complex voxels max_vox = nanmax(self.data) min_vox = nanmin(self.data) # check if voxel values are real or integer isInteger = True if type == "minimize": for vox in self.data.flatten(): if int(vox) != vox: isInteger = False break if isInteger: from numpy import iinfo, uint8, uint16, uint32, uint64 if min_vox >= 0: # unsigned if max_vox <= iinfo(uint8).max: type = "uint8" elif max_vox <= iinfo(uint16): type = "uint16" elif max_vox <= iinfo(uint32).max: type = "uint32" elif max_vox <= iinfo(uint64).max: type = "uint64" else: raise ValueError("Maximum value of the image is to big to be represented.") else: if max_vox <= iinfo(int8).max and min_vox >= iinfo(int8).min: type = "int8" elif max_vox <= iinfo(int16).max and min_vox >= iinfo(int16).min: type = "int16" elif max_vox <= iinfo(int32).max and min_vox >= iinfo(int32).min: type = "int32" elif max_vox <= iinfo(int64).max and min_vox >= iinfo(int64).min: type = "int64" else: raise ValueError("Maximum value of the image is to big to be represented.") else: from numpy import finfo, float32, float64 # if max_vox <= np.finfo(np.float16).max and min_vox >= np.finfo(np.float16).min: # type = 'np.float16' # not supported by nibabel if max_vox <= finfo(float32).max and min_vox >= finfo(float32).min: type = "float32" elif max_vox <= finfo(float64).max and min_vox >= finfo(float64).min: type = "float64" # print "The image has been set to "+type+" (previously "+str(self.hdr.get_data_dtype())+")" # change type of data in both numpy array and nifti header type_build = eval(type) self.data = type_build(self.data) self.hdr.set_data_dtype(type) def save(self, type=""): """ Write an image in a nifti file :param type: if not set, the image is saved in standard type if 'minimize', image space is minimize (2, 'uint8', np.uint8, "NIFTI_TYPE_UINT8"), (4, 'int16', np.int16, "NIFTI_TYPE_INT16"), (8, 'int32', np.int32, "NIFTI_TYPE_INT32"), (16, 'float32', np.float32, "NIFTI_TYPE_FLOAT32"), (32, 'complex64', np.complex64, "NIFTI_TYPE_COMPLEX64"), (64, 'float64', np.float64, "NIFTI_TYPE_FLOAT64"), (256, 'int8', np.int8, "NIFTI_TYPE_INT8"), (512, 'uint16', np.uint16, "NIFTI_TYPE_UINT16"), (768, 'uint32', np.uint32, "NIFTI_TYPE_UINT32"), (1024,'int64', np.int64, "NIFTI_TYPE_INT64"), (1280, 'uint64', np.uint64, "NIFTI_TYPE_UINT64"), (1536, 'float128', _float128t, "NIFTI_TYPE_FLOAT128"), (1792, 'complex128', np.complex128, "NIFTI_TYPE_COMPLEX128"), (2048, 'complex256', _complex256t, "NIFTI_TYPE_COMPLEX256"), """ from nibabel import Nifti1Image, save from sct_utils import printv if type != "": self.changeType(type) self.hdr.set_data_shape(self.data.shape) img = Nifti1Image(self.data, None, self.hdr) printv("saving " + self.path + self.file_name + self.ext + "\n", verbose=self.verbose, type="normal") save(img, self.path + self.file_name + self.ext) # flatten the array in a single dimension vector, its shape will be (d, 1) compared to the flatten built in method # which would have returned (d,) def flatten(self): # return self.data.flatten().reshape(self.data.flatten().shape[0], 1) return self.data.flatten() # return a list of the image slices flattened def slices(self): slices = [] for slc in self.data: slices.append(slc.flatten()) return slices def getNonZeroCoordinates(self, sorting=None, reverse_coord=False, coordValue=False): """ This function return all the non-zero coordinates that the image contains. Coordinate list can also be sorted by x, y, z, or the value with the parameter sorting='x', sorting='y', sorting='z' or sorting='value' If reverse_coord is True, coordinate are sorted from larger to smaller. """ from msct_types import Coordinate from sct_utils import printv try: if len(self.dim) == 3: X, Y, Z = (self.data > 0).nonzero() list_coordinates = [ Coordinate([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] elif len(self.dim) == 2: X, Y = (self.data > 0).nonzero() list_coordinates = [Coordinate([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X))] except Exception, e: printv("ERROR: Exception " + str(e) + " caught while geting non Zeros coordinates", 1, "error") if coordValue: from msct_types import CoordinateValue if len(self.dim) == 3: list_coordinates = [ CoordinateValue([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] else: list_coordinates = [CoordinateValue([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X))] else: from msct_types import Coordinate if len(self.dim) == 3: list_coordinates = [ Coordinate([X[i], Y[i], Z[i], self.data[X[i], Y[i], Z[i]]]) for i in range(0, len(X)) ] else: list_coordinates = [Coordinate([X[i], Y[i], self.data[X[i], Y[i]]]) for i in range(0, len(X))] if sorting is not None: if reverse_coord not in [True, False]: raise ValueError("reverse_coord parameter must be a boolean") if sorting == "x": list_coordinates = sorted(list_coordinates, key=lambda obj: obj.x, reverse=reverse_coord) elif sorting == "y": list_coordinates = sorted(list_coordinates, key=lambda obj: obj.y, reverse=reverse_coord) elif sorting == "z": list_coordinates = sorted(list_coordinates, key=lambda obj: obj.z, reverse=reverse_coord) elif sorting == "value": list_coordinates = sorted(list_coordinates, key=lambda obj: obj.value, reverse=reverse_coord) else: raise ValueError("sorting parameter must be either 'x', 'y', 'z' or 'value'") return list_coordinates