Test Failed
Push — master ( b43827...693fba )
by Daniil
114:55 queued 111:23
created

ImageLoader.set_rotation_angles()   B

Complexity

Conditions 5

Size

Total Lines 23
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 5
eloc 20
nop 2
dl 0
loc 23
rs 8.9332
c 0
b 0
f 0
1
# Copyright 2014 Diamond Light Source Ltd.
2
#
3
# Licensed under the Apache License, Version 2.0 (the "License");
4
# you may not use this file except in compliance with the License.
5
# You may obtain a copy of the License at
6
#
7
#     http://www.apache.org/licenses/LICENSE-2.0
8
#
9
# Unless required by applicable law or agreed to in writing, software
10
# distributed under the License is distributed on an "AS IS" BASIS,
11
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
# See the License for the specific language governing permissions and
13
# limitations under the License.
14
15
"""
16
.. module:: temp_loader
17
   :platform: Unix
18
   :synopsis: A class for loading standard tomography data in a variety of
19
    formats.
20
21
.. moduleauthor:: Nicola Wadeson <[email protected]>
22
23
"""
24
25
import os
26
import tempfile
27
import warnings
28
29
import h5py
30
import numpy as np
31
32
from savu.data.data_structures.data_types.data_plus_darks_and_flats \
33
    import NoImageKey
34
from savu.data.data_structures.data_types.image_data import ImageData
35
from savu.plugins.loaders.base_loader import BaseLoader
36
from savu.plugins.utils import register_plugin
37
38
39
@register_plugin
40
class ImageLoader(BaseLoader):
41
    """
42
    Load any FabIO compatible formats (e.g. tiffs)
43
44
    :param dataset_name: The name assigned to the dataset. Default: 'tomo'.
45
    :param angles: A python statement to be evaluated \
46
    (e.g np.linspace(0, 180, nAngles)) or a file. Default: None.
47
    :param frame_dim: Which dimension requires stitching? Default: 0.
48
    :param data_prefix: A file prefix for the data file. Default: None.
49
    :param dark_prefix: A file prefix for the dark field files, including the\
50
    folder path if different from the data. Default: None.
51
    :param flat_prefix: A file prefix for the flat field files, including the\
52
    folder path if different from the data. Default: None.
53
    """
54
55
    def __init__(self, name='ImageLoader'):
56
        super(ImageLoader, self).__init__(name)
57
58
    def setup(self):
59
        exp = self.exp
60
        data_obj = exp.create_data_object('in_data',
61
                                          self.parameters['dataset_name'])
62
63
        rot = 0
64
        detY = 1
65
        detX = 2
66
        data_obj.set_axis_labels('rotation_angle.degrees',
67
                                 'detector_y.pixel',
68
                                 'detector_x.pixel')
69
70
        data_obj.add_pattern('PROJECTION', core_dims=(detX, detY),
71
                             slice_dims=(rot,))
72
        data_obj.add_pattern('SINOGRAM', core_dims=(detX, rot),
73
                             slice_dims=(detY,))
74
75
        path = os.path.abspath(exp.meta_data.get("data_file"))
76
        data_obj.data = self._get_data_type(data_obj, path)
77
78
        self.set_rotation_angles(data_obj)
79
80
        # dummy file
81
        filename = path.split(os.sep)[-1] + '.h5'
82
        data_obj.backing_file = \
83
            h5py.File(os.path.join(tempfile.mkdtemp(), filename), 'a')
84
85
        data_obj.set_shape(data_obj.data.get_shape())
86
        self.set_data_reduction_params(data_obj)
87
        self._set_darks_and_flats(data_obj, path)
88
89
    def _set_darks_and_flats(self, dObj, path):
90
        if not self.parameters['flat_prefix']:
91
            return
92
93
        dObj.data = NoImageKey(dObj, None, 0)
94
        fdim = self.parameters['frame_dim']
95
96
        # read dark and flat images
97
        fpath, ffix = self._get_path(self.parameters['flat_prefix'], path)
98
        flat = ImageData(fpath, dObj, [fdim], None, ffix)
99
100
        if self.parameters['dark_prefix']:
101
            dpath, dfix = self._get_path(self.parameters['dark_prefix'], path)
102
            dark = ImageData(dpath, dObj, [fdim], None, dfix)
103
        else:
104
            shape = dObj.get_shape()
105
            dark = np.zeros([1] + [shape[i] for i in [1, 2]], dtype=flat.dtype)
106
107
        dObj.data._set_dark_path(dark)
108
        dObj.data._set_flat_path(flat)
109
        dObj.data._set_dark_and_flat()
110
111
    def _get_path(self, param, data):
112
        ppath, pfix = os.path.split(param)
113
        ppath = \
114
            os.path.join(data, ppath) if not os.path.isabs(ppath) else ppath
115
        return ppath, pfix
116
117
    def _get_data_type(self, obj, path):
118
        prefix = self.parameters['data_prefix']
119
        return ImageData(path, obj, [self.parameters['frame_dim']], None, prefix)
120
121
    def set_rotation_angles(self, data_obj):
122
        angles = self.parameters['angles']
123
124
        if angles is None:
125
            angles = np.linspace(0, 180, data_obj.data.get_shape()[0])
126
        else:
127
            try:
128
                ldict = {}
129
                exec("angles = " + angles,globals(),ldict)
130
                angles = ldict['angles']
131
            except Exception as e:
132
                warnings.warn("Could not execute statement: {}".format(e))
133
                try:
134
                    angles = np.loadtxt(angles)
135
                except Exception as e:
136
                    raise Exception('Cannot set angles in loader. Error: {}'.format(e))
137
138
        n_angles = len(angles)
139
        data_angles = data_obj.data.get_shape()[self.parameters['frame_dim']]
140
        if data_angles != n_angles:
141
            raise Exception("The number of angles %s does not match the data "
142
                            "dimension length %s", n_angles, data_angles)
143
        data_obj.meta_data.set("rotation_angle", angles)
144