def get_direction_matrix(self): """Each row gives a vector dictating the direction of the axis in LPS physical space.""" arr = numpy.ndarray((3, 3), dtype=numpy.float32) try_calling( pysirf.cSIRF_GeomInfo_get_direction_matrix(self.handle, arr.ctypes.data)) return arr
def axpby(self, a, b, y, out=None, **kwargs): ''' Addition for data containers. Returns the sum of the container data with another container data viewed as vectors. y: DataContainer out: DataContainer to store the result to. ''' # if isinstance(other , ( Number, int, float, numpy.float32 )): # tmp = other + numpy.zeros(self.as_array().shape) # other = self.copy() # other.fill(tmp) assert_validities(self, y) alpha = numpy.asarray([a.real, a.imag], dtype=numpy.float32) beta = numpy.asarray([b.real, b.imag], dtype=numpy.float32) if out is None: z = self.same_object() z.handle = pysirf.cSIRF_axpby \ (alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle) else: assert_validities(self, out) z = out try_calling(pysirf.cSIRF_axpbyAlt \ (alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle, z.handle)) check_status(z.handle) return z
def get_index_to_physical_point_matrix(self): """Get the 4x4 affine matrix that converts an index to a point in LPS physical space.""" arr = numpy.ndarray((4, 4), dtype=numpy.float32) try_calling( pysirf.cSIRF_GeomInfo_get_index_to_physical_point_matrix( self.handle, arr.ctypes.data)) return arr
def set_properties(self, prop): ''' Assigns specified values to specified gadget properties. prop: a string with comma-separated list of property value assignments prop_name=prop_value ''' try_calling(pygadgetron.cGT_setGadgetProperties(self.handle, prop))
def as_array(self): ''' Returns all self's images as a 3D Numpy ndarray. ''' assert self.handle is not None if self.number() < 1: return numpy.ndarray((0, 0, 0), dtype=numpy.float32) dim = numpy.ndarray((4, ), dtype=numpy.int32) image = Image(self) pygadgetron.cGT_getImageDim(image.handle, dim.ctypes.data) nx = dim[0] ny = dim[1] nz = dim[2] nc = dim[3] nz = nz * nc * self.number() if self.is_real(): array = numpy.ndarray((nz, ny, nx), dtype=numpy.float32) try_calling(pygadgetron.cGT_getImagesDataAsFloatArray\ (self.handle, array.ctypes.data)) return array else: z = numpy.ndarray((nz, ny, nx), dtype=numpy.complex64) try_calling(pygadgetron.cGT_getImagesDataAsCmplxArray\ (self.handle, z.ctypes.data)) return z
def subtract(self, other, out=None): ''' Overloads - for data containers. Returns the difference of the container data with another container data viewed as vectors. other: DataContainer ''' if not isinstance(other, (DataContainer, Number)): return NotImplemented if isinstance(other, Number): tmp = other + numpy.zeros(self.shape, self.dtype) other = self.copy() other.fill(tmp) assert_validities(self, other) pl_one = numpy.asarray([1.0, 0.0], dtype=numpy.float32) mn_one = numpy.asarray([-1.0, 0.0], dtype=numpy.float32) if out is None: z = self.same_object() z.handle = pysirf.cSIRF_axpby \ (pl_one.ctypes.data, self.handle, mn_one.ctypes.data, other.handle) check_status(z.handle) else: assert_validities(self, out) z = out try_calling(pysirf.cSIRF_axpbyAlt \ (pl_one.ctypes.data, self.handle, mn_one.ctypes.data, other.handle, z.handle)) return z
def process(self): ''' Processes the input with the gadget chain. ''' if self.input_data is None: raise error('no input data') try_calling(pygadgetron.cGT_reconstructImages\ (self.handle, self.input_data.handle))
def add_gadget(self, id, gadget): ''' Adds a gadget to the chain. id : gadget id (string) writer: Gadget ''' assert isinstance(gadget, Gadget) try_calling(pygadgetron.cGT_addGadget(self.handle, id, gadget.handle))
def set_coil_sensitivity_maps(self, csm): ''' Specifies the coil sensitivity maps to be used by the model. csm: CoilSensitivityData ''' assert_validity(csm, CoilSensitivityData) try_calling(pygadgetron.cGT_setAcquisitionModelParameter \ (self.handle, 'coil_sensitivity_maps', csm.handle))
def fill(self, data): ''' Fills self's acquisitions with specified values. data: Python Numpy array ''' assert self.handle is not None try_calling(pygadgetron.cGT_fillAcquisitionsData\ (self.handle, data.ctypes.data, 1))
def set_property(self, prop, value): ''' Assigns specified value to specified gadget property. prop : property name (string) value: property value (string) ''' try_calling(pygadgetron.cGT_setGadgetProperty(self.handle, prop, value))
def calculate(self, acqs): ''' Calculates coil images from a given sorted acquisitions. acqs: AcquisitionData ''' assert_validity(acqs, AcquisitionData) if acqs.is_sorted() is False: print('WARNING: acquisitions may be in a wrong order') try_calling(pygadgetron.cGT_computeCoilImages\ (self.handle, acqs.handle))
def sort(self): ''' Sorts acquisitions with respect to (in this order): - repetition - slice - kspace_encode_step_1 ''' assert self.handle is not None try_calling(pygadgetron.cGT_sortAcquisitions(self.handle)) self.sorted = True
def set_storage_scheme(scheme): '''Sets acquisition data storage scheme. scheme = 'file' (default): all acquisition data generated from now on will be kept in scratch files deleted after the user's script terminates scheme = 'memory': all acquisition data generated from now on will be kept in RAM (avoid if data is very large) ''' try_calling(pygadgetron.cGT_setAcquisitionsStorageScheme(scheme))
def calculate(self, data, method=None): ''' Calculates coil sensitivity maps from coil images or sorted acquisitions. data : either AcquisitionData or CoilImages method: either SRSS (Square Root of the Sum of Squares, default) or Inati ''' if isinstance(data, AcquisitionData): if data.is_sorted() is False: print('WARNING: acquisitions may be in a wrong order') if self.handle is not None: pyiutil.deleteDataHandle(self.handle) self.handle = pygadgetron.cGT_CoilSensitivities('') check_status(self.handle) if method is not None: method_name, parm_list = name_and_parameters(method) parm = parse_arglist(parm_list) else: method_name = 'SRSS' parm = {} if isinstance(data, AcquisitionData): assert data.handle is not None _set_int_par\ (self.handle, 'coil_sensitivity', 'smoothness', self.smoothness) try_calling(pygadgetron.cGT_computeCoilSensitivities\ (self.handle, data.handle)) elif isinstance(data, CoilImageData): assert data.handle is not None if method_name == 'Inati': # if not HAVE_ISMRMRDTOOLS: try: from ismrmrdtools import coils except: raise error('Inati method requires ismrmrd-python-tools') nz = data.number() for z in range(nz): ci = numpy.squeeze(data.as_array(z)) (csm, rho) = coils.calculate_csm_inati_iter(ci) self.append(csm.astype(numpy.complex64)) elif method_name == 'SRSS': if 'niter' in parm: nit = int(parm['niter']) _set_int_par\ (self.handle, 'coil_sensitivity', 'smoothness', nit) try_calling(pygadgetron.cGT_computeCSMsFromCIs\ (self.handle, data.handle)) else: raise error('Unknown method %s' % method_name) else: raise error('Cannot calculate coil sensitivities from %s' % \ repr(type(data)))
def set_gadget_property(self, id, prop, value): ''' Assigns specified value to specified gadget property. id : gadget id prop : property name (string) value: property value (string) ''' if type(value) == type('abc'): v = value else: v = repr(value).lower() hg = _parameterHandle(self.handle, 'gadget_chain', id) try_calling(pygadgetron.cGT_setGadgetProperty(hg, prop, v)) pyiutil.deleteDataHandle(hg)
def as_array(self, select='image'): ''' Returns selected self's acquisitions as a 3D Numpy ndarray. ''' assert self.handle is not None na = self.number() ny, nc, ns = self.dimensions(select) if select == 'all': # return all return_all = 1 else: # return only image-related return_all = 0 z = numpy.ndarray((ny, nc, ns), dtype=numpy.complex64) try_calling(pygadgetron.cGT_acquisitionsDataAsArray\ (self.handle, z.ctypes.data, return_all)) return z
def fill(self, data): ''' Fills self's image data with specified values. data: Python Numpy array ''' assert self.handle is not None if self.is_real(): if data.dtype != numpy.float32: data = data.astype(numpy.float32) try_calling(pygadgetron.cGT_setImagesDataAsFloatArray\ (self.handle, data.ctypes.data)) else: if data.dtype != numpy.complex64: data = data.astype(numpy.complex64) try_calling(pygadgetron.cGT_setImagesDataAsCmplxArray\ (self.handle, data.ctypes.data))
def conjugate(self, out=None): ''' Computes complex conjugate of self. Use y = x.conjugate() to get the conjugated copy of x. Use x.conjugate(out=x) to conjugate in-place. ''' assert self.handle is not None if out is self: try_calling(pysirf.cSIRF_conjugate(self.handle)) return elif out is None: x = self.same_object() else: x = out x.handle = pysirf.cSIRF_conjugated(self.handle) check_status(x.handle) if out is None: return x
def divide(self, other, out=None): ''' Returns the elementwise ratio of this and another container data viewed as vectors. other: DataContainer out: DataContainer to store the result to. ''' if not isinstance (other, ( DataContainer , Number )): return NotImplemented if isinstance(other , Number ): tmp = other + numpy.zeros(self.shape, self.dtype) other = self.copy() other.fill(tmp) assert_validities(self, other) if out is None: out = self.same_object() out.handle = pysirf.cSIRF_ratio(self.handle, other.handle) check_status(out.handle) #out = self.copy() else: assert_validities(self, out) try_calling(pysirf.cSIRF_divide(self.handle, other.handle, out.handle)) return out
def axpby(self, a, b, y, out=None, **kwargs): ''' Addition for data containers. Returns the sum of the container data with another container data viewed as vectors. a: multiplier to self, can be a number or a DataContainer b: multiplier to y, can be a number or a DataContainer y: DataContainer out: DataContainer to store the result to. ''' # splits axpby in 3 steps if a and b are not numbers as # pysirf.cSIRF_axpby requires them as numbers if not (isinstance(a, Number) and isinstance(b, Number)): if out is None: out = y.multiply(b) else: y.multiply(b, out=out) tmp = self.multiply(a) out.add(tmp, out=out) return out assert_validities(self, y) alpha = numpy.asarray([a.real, a.imag], dtype=numpy.float32) beta = numpy.asarray([b.real, b.imag], dtype=numpy.float32) if out is None: z = self.same_object() z.handle = pysirf.cSIRF_axpby \ (alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle) else: assert_validities(self, out) z = out try_calling(pysirf.cSIRF_axpbyAlt \ (alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle, z.handle)) check_status(z.handle) return z
def write(self, filename): ''' Writes to file. ''' assert self.handle is not None try_calling(pysirf.cSIRF_write(self.handle, filename))
def push_back(self, handle): """Push back new data handle.""" try_calling(pysirf.cSIRF_DataHandleVector_push_back(self.handle, handle)) check_status(self.handle)
def reorient(self, geom_info): """Reorient image. Requires that dimensions match.""" if not isinstance(geom_info, GeometricalInfo): raise AssertionError() try_calling( pysirf.cSIRF_ImageData_reorient(self.handle, geom_info.handle))
def sapyb(self, a, y, b, out=None, **kwargs): ''' Addition for data containers. Can be in place. Returns the sum of the container data with another container data viewed as vectors. a: multiplier to self, can be a number or a DataContainer b: multiplier to y, can be a number or a DataContainer y: DataContainer out: DataContainer to store the result to, can be self or y. ''' assert_validities(self, y) if out is not None: assert_validities(self, out) z = out else: z = self.same_object() if isinstance(a, Number): alpha = numpy.asarray([a.real, a.imag], dtype=numpy.float32) if isinstance(b, Number): #a is scalar, b is scalar beta = numpy.asarray([b.real, b.imag], dtype=numpy.float32) if out is None: z.handle = pysirf.cSIRF_axpby(alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle) else: try_calling( pysirf.cSIRF_axpbyAlt(alpha.ctypes.data, self.handle, beta.ctypes.data, y.handle, z.handle)) else: #a is scalar, b is array one = numpy.asarray([1.0, 0.0], dtype=numpy.float32) tmp = y.multiply(b) if out is None: z.handle = pysirf.cSIRF_axpby(alpha.ctypes.data, self.handle, one.ctypes.data, tmp.handle) else: try_calling( pysirf.cSIRF_axpbyAlt(alpha.ctypes.data, self.handle, one.ctypes.data, tmp.handle, z.handle)) else: assert_validities(self, a) if isinstance(b, Number): #a is array, b is scalar one = numpy.asarray([1.0, 0.0], dtype=numpy.float32) beta = numpy.asarray([b.real, b.imag], dtype=numpy.float32) tmp = self.multiply(a) if out is None: z.handle = pysirf.cSIRF_axpby(one.ctypes.data, tmp.handle, beta.ctypes.data, y.handle) else: try_calling( pysirf.cSIRF_axpbyAlt(one.ctypes.data, tmp.handle, beta.ctypes.data, y.handle, z.handle)) else: #a is array, b is array assert_validities(self, b) if out is None: try: z.handle = pysirf.cSIRF_xapyb(self.handle, a.handle, y.handle, b.handle) check_status(z.handle) except error as e: if 'NotImplemented' in str(e): tmp = self.multiply(a) z = y.multiply(b) z.add(tmp, out=z) else: raise RuntimeError(str(e)) else: try: try_calling( pysirf.cSIRF_xapybAlt(self.handle, a.handle, y.handle, b.handle, z.handle)) except error as e: if 'NotImplemented' in str(e): tmp = self.multiply(a) y.multiply(b, out=z) z.add(tmp, out=z) else: raise RuntimeError(str(e)) check_status(z.handle) return z
def get_size(self): """Size is the number of voxels in each dimension.""" arr = numpy.ndarray((3, ), dtype=numpy.int32) try_calling( pysirf.cSIRF_GeomInfo_get_size(self.handle, arr.ctypes.data)) return tuple(arr)
def get_spacing(self): """Spacing is the physical distance between voxels in each dimension.""" arr = numpy.ndarray((3, ), dtype=numpy.float32) try_calling( pysirf.cSIRF_GeomInfo_get_spacing(self.handle, arr.ctypes.data)) return tuple(arr)
def get_offset(self): """Offset is the LPS coordinate of the centre of the first voxel.""" arr = numpy.ndarray((3, ), dtype=numpy.float32) try_calling( pysirf.cSIRF_GeomInfo_get_offset(self.handle, arr.ctypes.data)) return tuple(arr)
def print_info(self): """Print the geom info""" try_calling(pysirf.cSIRF_GeomInfo_print(self.handle))
def fill(self, image): try_calling(pysirf.cSIRF_fillImageFromImage(self.handle, image.handle))