예제 #1
0
 def test_ImageGeometry_allocate(self):
     vgeometry = ImageGeometry(voxel_num_x=4, voxel_num_y=3, channels=2)
     image = vgeometry.allocate()
     self.assertEqual(0,image.as_array()[0][0][0])
     image = vgeometry.allocate(1)
     self.assertEqual(1,image.as_array()[0][0][0])
     default_order = ['channel' , 'horizontal_y' , 'horizontal_x']
     self.assertEqual(default_order[0], image.dimension_labels[0])
     self.assertEqual(default_order[1], image.dimension_labels[1])
     self.assertEqual(default_order[2], image.dimension_labels[2])
     order = [ 'horizontal_x' , 'horizontal_y', 'channel' ]
     vgeometry.set_labels(order)
     image = vgeometry.allocate(0)
     self.assertEqual(order[0], image.dimension_labels[0])
     self.assertEqual(order[1], image.dimension_labels[1])
     self.assertEqual(order[2], image.dimension_labels[2])
     
     ig = ImageGeometry(2,3,2)
     try:
         z = ImageData(numpy.random.randint(10, size=(2,3)), geometry=ig)
         self.assertTrue(False)
     except ValueError as ve:
         print (ve)
         self.assertTrue(True)
예제 #2
0
class NEXUSDataReader(object):
    def __init__(self, **kwargs):
        '''
        Constructor
        
        Input:
            
            file_name      full path to NEXUS file
        '''

        self.file_name = kwargs.get('file_name', None)

        if self.file_name is not None:
            self.set_up(file_name=self.file_name)

    def set_up(self, file_name=None):

        self.file_name = os.path.abspath(file_name)

        # check that h5py library is installed
        if (h5pyAvailable == False):
            raise Exception('h5py is not available, cannot load NEXUS files.')

        if self.file_name == None:
            raise Exception('Path to nexus file is required.')

        # check if nexus file exists
        if not (os.path.isfile(self.file_name)):
            raise Exception('File\n {}\n does not exist.'.format(
                self.file_name))

        self._geometry = None

    def read_dimension_labels(self, attrs):
        dimension_labels = [None] * 4
        for k, v in attrs.items():
            if k in ['dim0', 'dim1', 'dim2', 'dim3']:
                dimension_labels[int(k[3:])] = v

        # remove Nones
        dimension_labels = [i for i in dimension_labels if i]

        if len(dimension_labels) == 0:
            dimension_labels = None

        return dimension_labels

    def get_geometry(self):
        '''
        Parse NEXUS file and returns either ImageData or Acquisition Data 
        depending on file content
        '''

        with h5py.File(self.file_name, 'r') as dfile:

            if np.string_(dfile.attrs['creator']) != np.string_(
                    'NEXUSDataWriter.py'):
                raise Exception(
                    'We can parse only files created by NEXUSDataWriter.py')

            ds_data = dfile['entry1/tomo_entry/data/data']

            if ds_data.attrs['data_type'] == 'ImageData':

                self._geometry = ImageGeometry(
                    voxel_num_x=int(ds_data.attrs['voxel_num_x']),
                    voxel_num_y=int(ds_data.attrs['voxel_num_y']),
                    voxel_num_z=int(ds_data.attrs['voxel_num_z']),
                    voxel_size_x=ds_data.attrs['voxel_size_x'],
                    voxel_size_y=ds_data.attrs['voxel_size_y'],
                    voxel_size_z=ds_data.attrs['voxel_size_z'],
                    center_x=ds_data.attrs['center_x'],
                    center_y=ds_data.attrs['center_y'],
                    center_z=ds_data.attrs['center_z'],
                    channels=ds_data.attrs['channels'])

                if ds_data.attrs.__contains__('channel_spacing') == True:
                    self._geometry.channel_spacing = ds_data.attrs[
                        'channel_spacing']

                # read the dimension_labels from dim{}
                dimension_labels = self.read_dimension_labels(ds_data.attrs)

            else:  # AcquisitionData
                if ds_data.attrs.__contains__('dist_source_center') or dfile[
                        'entry1/tomo_entry'].__contains__(
                            'config/source/position'):
                    geom_type = 'cone'
                else:
                    geom_type = 'parallel'

                if ds_data.attrs.__contains__('num_pixels_v'):
                    num_pixels_v = ds_data.attrs.get('num_pixels_v')
                elif ds_data.attrs.__contains__('pixel_num_v'):
                    num_pixels_v = ds_data.attrs.get('pixel_num_v')
                else:
                    num_pixels_v = 1

                if num_pixels_v > 1:
                    dim = 3
                else:
                    dim = 2

                if self.is_old_file_version():
                    num_pixels_h = ds_data.attrs.get('pixel_num_h', 1)
                    num_channels = ds_data.attrs['channels']
                    ds_angles = dfile['entry1/tomo_entry/data/rotation_angle']

                    if geom_type == 'cone' and dim == 3:
                        self._geometry = AcquisitionGeometry.create_Cone3D(
                            source_position=[
                                0, -ds_data.attrs['dist_source_center'], 0
                            ],
                            detector_position=[
                                0, ds_data.attrs['dist_center_detector'], 0
                            ])
                    elif geom_type == 'cone' and dim == 2:
                        self._geometry = AcquisitionGeometry.create_Cone2D(
                            source_position=[
                                0, -ds_data.attrs['dist_source_center']
                            ],
                            detector_position=[
                                0, ds_data.attrs['dist_center_detector']
                            ])
                    elif geom_type == 'parallel' and dim == 3:
                        self._geometry = AcquisitionGeometry.create_Parallel3D(
                        )
                    elif geom_type == 'parallel' and dim == 2:
                        self._geometry = AcquisitionGeometry.create_Parallel2D(
                        )

                else:
                    num_pixels_h = ds_data.attrs.get('num_pixels_h', 1)
                    num_channels = ds_data.attrs['num_channels']
                    ds_angles = dfile['entry1/tomo_entry/config/angles']

                    rotation_axis_position = list(dfile[
                        'entry1/tomo_entry/config/rotation_axis/position'])
                    detector_position = list(
                        dfile['entry1/tomo_entry/config/detector/position'])

                    ds_detector = dfile['entry1/tomo_entry/config/detector']
                    if ds_detector.__contains__('direction_x'):
                        detector_direction_x = list(dfile[
                            'entry1/tomo_entry/config/detector/direction_x'])
                    else:
                        detector_direction_x = list(dfile[
                            'entry1/tomo_entry/config/detector/direction_row'])

                    if ds_detector.__contains__('direction_y'):
                        detector_direction_y = list(dfile[
                            'entry1/tomo_entry/config/detector/direction_y'])
                    elif ds_detector.__contains__('direction_col'):
                        detector_direction_y = list(dfile[
                            'entry1/tomo_entry/config/detector/direction_col'])

                    ds_rotate = dfile['entry1/tomo_entry/config/rotation_axis']
                    if ds_rotate.__contains__('direction'):
                        rotation_axis_direction = list(dfile[
                            'entry1/tomo_entry/config/rotation_axis/direction']
                                                       )

                    if geom_type == 'cone':
                        source_position = list(
                            dfile['entry1/tomo_entry/config/source/position'])

                        if dim == 2:
                            self._geometry = AcquisitionGeometry.create_Cone2D(
                                source_position, detector_position,
                                detector_direction_x, rotation_axis_position)
                        else:
                            self._geometry = AcquisitionGeometry.create_Cone3D(source_position,\
                                                detector_position, detector_direction_x, detector_direction_y,\
                                                rotation_axis_position, rotation_axis_direction)
                    else:
                        ray_direction = list(
                            dfile['entry1/tomo_entry/config/ray/direction'])

                        if dim == 2:
                            self._geometry = AcquisitionGeometry.create_Parallel2D(
                                ray_direction, detector_position,
                                detector_direction_x, rotation_axis_position)
                        else:
                            self._geometry = AcquisitionGeometry.create_Parallel3D(ray_direction,\
                                                detector_position, detector_direction_x, detector_direction_y,\
                                                rotation_axis_position, rotation_axis_direction)

                # for all Aquisition data
                #set angles
                angles = list(ds_angles)
                angle_unit = ds_angles.attrs.get('angle_unit', 'degree')
                initial_angle = ds_angles.attrs.get('initial_angle', 0)
                self._geometry.set_angles(angles,
                                          initial_angle=initial_angle,
                                          angle_unit=angle_unit)

                #set panel
                pixel_size_v = ds_data.attrs.get('pixel_size_v',
                                                 ds_data.attrs['pixel_size_h'])
                origin = ds_data.attrs.get('panel_origin', 'bottom-left')
                self._geometry.set_panel((num_pixels_h, num_pixels_v),\
                                        pixel_size=(ds_data.attrs['pixel_size_h'], pixel_size_v),\
                                        origin=origin)

                # set channels
                self._geometry.set_channels(num_channels)

                dimension_labels = []
                dimension_labels = self.read_dimension_labels(ds_data.attrs)

        #set labels
        self._geometry.set_labels(dimension_labels)

        return self._geometry

    def read(self):

        if self._geometry is None:
            self.get_geometry()

        with h5py.File(self.file_name, 'r') as dfile:

            ds_data = dfile['entry1/tomo_entry/data/data']
            data = np.array(ds_data, dtype=np.float32)

            # handle old files?
            if self.is_old_file_version():
                if isinstance(self._geometry, AcquisitionGeometry):
                    return AcquisitionData(data,
                                           True,
                                           geometry=self._geometry,
                                           suppress_warning=True)
                elif isinstance(self._geometry, ImageGeometry):
                    return ImageData(data,
                                     True,
                                     geometry=self._geometry,
                                     suppress_warning=True)
                else:
                    raise TypeError("Unsupported geometry. Expected ImageGeometry or AcquisitionGeometry, got {}"\
                        .format(type(self._geometry)))

            output = self._geometry.allocate(None)
            output.fill(data)
            return output

    def load_data(self):
        '''alias of read'''
        return self.read()

    def is_old_file_version(self):
        #return ds_data.attrs.__contains__('geom_type')
        with h5py.File(self.file_name, 'r') as dfile:

            if np.string_(dfile.attrs['creator']) != np.string_(
                    'NEXUSDataWriter.py'):
                raise Exception(
                    'We can parse only files created by NEXUSDataWriter.py')

            ds_data = dfile['entry1/tomo_entry/data/data']

            return 'geom_type' in ds_data.attrs.keys()
예제 #3
0
class TestSubset(unittest.TestCase):
    def setUp(self):
        self.ig = ImageGeometry(2, 3, 4, channels=5)
        angles = numpy.asarray([90., 0., -90.], dtype=numpy.float32)

        self.ag_cone = AcquisitionGeometry.create_Cone3D([0,-500,0],[0,500,0])\
                                    .set_panel((20,2))\
                                    .set_angles(angles)\
                                    .set_channels(4)

        self.ag = AcquisitionGeometry.create_Parallel3D()\
                                    .set_angles(angles)\
                                    .set_channels(4)\
                                    .set_panel((20,2))

    def test_ImageDataAllocate1a(self):
        data = self.ig.allocate()
        default_dimension_labels = [
            ImageGeometry.CHANNEL, ImageGeometry.VERTICAL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.HORIZONTAL_X
        ]
        self.assertTrue(
            default_dimension_labels == list(data.dimension_labels))

    def test_ImageDataAllocate1b(self):
        data = self.ig.allocate()
        self.assertTrue(data.shape == (5, 4, 3, 2))

    def test_ImageDataAllocate2a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.VERTICAL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.CHANNEL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        self.assertTrue(
            non_default_dimension_labels == list(data.dimension_labels))

    def test_ImageDataAllocate2b(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.VERTICAL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.CHANNEL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        self.assertTrue(data.shape == (2, 4, 3, 5))

    def test_ImageDataSubset1a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.CHANNEL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        sub = data.subset(horizontal_y=1)
        self.assertTrue(sub.shape == (2, 5, 4))

    def test_ImageDataSubset2a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.CHANNEL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        sub = data.subset(horizontal_x=1)
        self.assertTrue(sub.shape == (5, 3, 4))

    def test_ImageDataSubset3a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.CHANNEL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        sub = data.subset(channel=1)
        self.assertTrue(sub.shape == (2, 3, 4))

    def test_ImageDataSubset4a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.CHANNEL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        sub = data.subset(vertical=1)
        self.assertTrue(sub.shape == (2, 5, 3))

    def test_ImageDataSubset5a(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.HORIZONTAL_Y
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        sub = data.subset(horizontal_y=1)
        self.assertTrue(sub.shape == (2, ))

    def test_ImageDataSubset1b(self):
        non_default_dimension_labels = [
            ImageGeometry.HORIZONTAL_X, ImageGeometry.CHANNEL,
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.VERTICAL
        ]
        self.ig.set_labels(non_default_dimension_labels)
        data = self.ig.allocate()
        new_dimension_labels = [
            ImageGeometry.HORIZONTAL_Y, ImageGeometry.CHANNEL,
            ImageGeometry.VERTICAL, ImageGeometry.HORIZONTAL_X
        ]
        sub = data.subset(dimensions=new_dimension_labels)
        self.assertTrue(sub.shape == (3, 5, 4, 2))

    def test_ImageDataSubset1c(self):
        data = self.ig.allocate()
        sub = data.subset(channel=0, horizontal_x=0, horizontal_y=0)
        self.assertTrue(sub.shape == (4, ))

    def test_AcquisitionDataAllocate1a(self):
        data = self.ag.allocate()
        default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.ANGLE,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.HORIZONTAL
        ]
        self.assertTrue(
            default_dimension_labels == list(data.dimension_labels))

    def test_AcquisitionDataAllocate1b(self):
        data = self.ag.allocate()
        self.assertTrue(data.shape == (4, 3, 2, 20))

    def test_AcquisitionDataAllocate2a(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()

        self.assertTrue(
            non_default_dimension_labels == list(data.dimension_labels))

    def test_AcquisitionDataAllocate2b(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        self.assertTrue(data.shape == (4, 20, 2, 3))

    def test_AcquisitionDataSubset1a(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sub = data.subset(vertical=0)
        self.assertTrue(sub.shape == (4, 20, 3))

    def test_AcquisitionDataSubset1b(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sub = data.subset(channel=0)
        self.assertTrue(sub.shape == (20, 2, 3))

    def test_AcquisitionDataSubset1c(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sub = data.subset(horizontal=0, force=True)
        self.assertTrue(sub.shape == (4, 2, 3))

    def test_AcquisitionDataSubset1d(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sliceme = 1
        sub = data.subset(angle=sliceme)
        #print (sub.shape  , sub.dimension_labels)
        self.assertTrue(sub.shape == (4, 20, 2))
        self.assertTrue(
            sub.geometry.angles[0] == data.geometry.angles[sliceme])

    def test_AcquisitionDataSubset1e(self):
        non_default_dimension_labels = [
            AcquisitionGeometry.CHANNEL, AcquisitionGeometry.HORIZONTAL,
            AcquisitionGeometry.VERTICAL, AcquisitionGeometry.ANGLE
        ]
        self.ag.set_labels(non_default_dimension_labels)
        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sliceme = 1
        sub = data.subset(angle=sliceme)
        self.assertTrue(
            sub.geometry.angles[0] == data.geometry.angles[sliceme])

    def test_AcquisitionDataSubset1f(self):

        data = self.ag.allocate()
        #self.assertTrue( data.shape == (4,20,2,3))
        sliceme = 1
        sub = data.subset(angle=sliceme)
        self.assertTrue(
            sub.geometry.angles[0] == data.geometry.angles[sliceme])

    def test_AcquisitionDataSubset1g(self):

        data = self.ag_cone.allocate()
        sliceme = 1
        sub = data.subset(angle=sliceme)
        self.assertTrue(
            sub.geometry.angles[0] == data.geometry.angles[sliceme])

    def test_AcquisitionDataSubset1h(self):

        data = self.ag_cone.allocate()
        sub = data.subset(vertical='centre')
        self.assertTrue(sub.geometry.shape == (4, 3, 20))

    def test_AcquisitionDataSubset1i(self):

        data = self.ag_cone.allocate()
        sliceme = 1
        sub = data.subset(vertical=sliceme, force=True)
        self.assertTrue(sub.shape == (4, 3, 20))

    def test_AcquisitionDataSubset1j(self):

        data = self.ag.allocate()
        sub = data.subset(angle=0)
        sub = sub.subset(vertical=0)
        sub = sub.subset(horizontal=0, force=True)

        self.assertTrue(sub.shape == (4, ))