Source code for cil.framework.acquisition_data

#  Copyright 2018 United Kingdom Research and Innovation
#  Copyright 2018 The University of Manchester
#
#  Licensed under the Apache License, Version 2.0 (the "License");
#  you may not use this file except in compliance with the License.
#  You may obtain a copy of the License at
#
#      http://www.apache.org/licenses/LICENSE-2.0
#
#  Unless required by applicable law or agreed to in writing, software
#  distributed under the License is distributed on an "AS IS" BASIS,
#  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
#  See the License for the specific language governing permissions and
#  limitations under the License.
#
# Authors:
# CIL Developers, listed at: https://github.com/TomographicImaging/CIL/blob/master/NOTICE.txt
import numpy

from .labels import AcquisitionDimension, Backend
from .data_container import DataContainer
from .partitioner import Partitioner


[docs] class AcquisitionData(DataContainer, Partitioner): '''DataContainer for holding 2D or 3D sinogram''' __container_priority__ = 1 @property def geometry(self): return self._geometry @geometry.setter def geometry(self, val): self._geometry = val @property def dimension_labels(self): return self.geometry.dimension_labels @dimension_labels.setter def dimension_labels(self, val): if val is not None: raise ValueError("Unable to set the dimension_labels directly. Use geometry.set_labels() instead") def __init__(self, array = None, deep_copy=True, geometry = None, **kwargs): dtype = kwargs.get('dtype', numpy.float32) if geometry is None: raise AttributeError("AcquisitionData requires a geometry") labels = kwargs.get('dimension_labels', None) if labels is not None and labels != geometry.dimension_labels: raise ValueError("Deprecated: 'dimension_labels' cannot be set with 'allocate()'. Use 'geometry.set_labels()' to modify the geometry before using allocate.") if array is None: array = numpy.empty(geometry.shape, dtype=dtype) elif issubclass(type(array) , DataContainer): array = array.as_array() elif issubclass(type(array) , numpy.ndarray): # remove singleton dimensions array = numpy.squeeze(array) else: raise TypeError('array must be a CIL type DataContainer or numpy.ndarray got {}'.format(type(array))) if array.shape != geometry.shape: raise ValueError('Shape mismatch got {} expected {}'.format(array.shape, geometry.shape)) super(AcquisitionData, self).__init__(array, deep_copy, geometry=geometry,**kwargs) def __eq__(self, other): ''' Check if two AcquisitionData objects are equal. This is done by checking if the geometry, data and dtype are equal. Also, if the other object is a numpy.ndarray, it will check if the data and dtype are equal. Parameters ---------- other: AcquisitionData or numpy.ndarray The object to compare with. Returns ------- bool True if the two objects are equal, False otherwise. ''' if isinstance(other, AcquisitionData): if numpy.array_equal(self.as_array(), other.as_array()) \ and self.geometry == other.geometry \ and self.dtype == other.dtype: return True elif numpy.array_equal(self.as_array(), other) and self.dtype==other.dtype: return True else: return False
[docs] def get_slice(self,channel=None, angle=None, vertical=None, horizontal=None, force=False): '''Returns a new dataset of a single slice in the requested direction.''' try: geometry_new = self.geometry.get_slice(channel=channel, angle=angle, vertical=vertical, horizontal=horizontal) except ValueError: if force: geometry_new = None else: raise ValueError ("Unable to return slice of requested AcquisitionData. Use 'force=True' to return DataContainer instead.") #get new data #if vertical = 'centre' slice convert to index and subset, this will interpolate 2 rows to get the center slice value if vertical == 'centre': dim = self.geometry.dimension_labels.index('vertical') centre_slice_pos = (self.geometry.shape[dim]-1) / 2. ind0 = int(numpy.floor(centre_slice_pos)) w2 = centre_slice_pos - ind0 out = DataContainer.get_slice(self, channel=channel, angle=angle, vertical=ind0, horizontal=horizontal) if w2 > 0: out2 = DataContainer.get_slice(self, channel=channel, angle=angle, vertical=ind0 + 1, horizontal=horizontal) out = out * (1 - w2) + out2 * w2 else: out = DataContainer.get_slice(self, channel=channel, angle=angle, vertical=vertical, horizontal=horizontal) if len(out.shape) == 1 or geometry_new is None: return out else: return AcquisitionData(out.array, deep_copy=False, geometry=geometry_new, suppress_warning=True)
[docs] def reorder(self, order): ''' Reorders the data in memory as requested. This is an in-place operation. Parameters ---------- order: list or str Ordered list of labels from self.dimension_labels, or string 'astra' or 'tigre'. ''' if order in Backend: order = AcquisitionDimension.get_order_for_engine(order, self.geometry) super().reorder(order)