diff options
| author | Jakob Jorgensen, WS at HMXIF <jakob.jorgensen@manchester.ac.uk> | 2019-04-30 20:28:49 +0100 | 
|---|---|---|
| committer | Jakob Jorgensen, WS at HMXIF <jakob.jorgensen@manchester.ac.uk> | 2019-04-30 20:28:49 +0100 | 
| commit | 3d69f8d06c01656339558f3229e08ebbcf712431 (patch) | |
| tree | 375fbd5625efd8c2831a1f07c4cb57bac67e054e /Wrappers/Python/ccpi | |
| parent | 196637dd9f8dc73aa13993d632837a9bea6603b5 (diff) | |
| parent | d6b38d0e635db69f46b603525d746620a47f0528 (diff) | |
| download | astra-wrapper-3d69f8d06c01656339558f3229e08ebbcf712431.tar.gz astra-wrapper-3d69f8d06c01656339558f3229e08ebbcf712431.tar.bz2 astra-wrapper-3d69f8d06c01656339558f3229e08ebbcf712431.tar.xz astra-wrapper-3d69f8d06c01656339558f3229e08ebbcf712431.zip | |
Merge branch 'reorganise'
Diffstat (limited to 'Wrappers/Python/ccpi')
15 files changed, 635 insertions, 623 deletions
| diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py new file mode 100644 index 0000000..8058cdc --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py @@ -0,0 +1,69 @@ +# -*- coding: utf-8 -*- +#    This work is independent part of the Core Imaging Library developed by +#    Visual Analytics and Imaging System Group of the Science Technology +#    Facilities Council, STFC +#    This program is free software: you can redistribute it and/or modify +#    it under the terms of the GNU General Public License as published by +#    the Free Software Foundation, either version 3 of the License, or +#    (at your option) any later version. +# +#    This program is distributed in the hope that it will be useful, +#    but WITHOUT ANY WARRANTY; without even the implied warranty of +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#    GNU General Public License for more details. +# +#    You should have received a copy of the GNU General Public License +#    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +from ccpi.optimisation.operators import Operator, LinearOperator +from ccpi.framework import AcquisitionData, ImageData, DataContainer +from ccpi.optimisation.ops import PowerMethodNonsquare +from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \ +     AstraForwardProjector3D, AstraBackProjector3D + +class AstraProjector3DSimple(LinearOperator): +    """ASTRA projector modified to use DataSet and geometry.""" +    def __init__(self, geomv, geomp): +        super(AstraProjector3DSimple, self).__init__() +         +        # Store volume and sinogram geometries. +        self.sinogram_geometry = geomp +        self.volume_geometry = geomv +         +        self.fp = AstraForwardProjector3D(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        output_axes_order=['vertical','angle','horizontal']) +         +        self.bp = AstraBackProjector3D(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        output_axes_order=['vertical','horizontal_y','horizontal_x']) +                 +        # Initialise empty for singular value. +        self.s1 = None +     +    def direct(self, IM, out=None): +        self.fp.set_input(IM) +         +        if out is None: +            return self.fp.get_output() +        else: +            out.fill(self.fp.get_output()) +     +    def adjoint(self, DATA, out=None): +        self.bp.set_input(DATA) +         +        if out is None: +            return self.bp.get_output() +        else: +            out.fill(self.bp.get_output())     +     +    def domain_geometry(self): +        return self.volume_geometry +     +    def range_geometry(self): +        return self.sinogram_geometry   +     +    def norm(self): +        x0 = self.volume_geometry.allocate('random') +        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0) +        return self.s1
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py new file mode 100644 index 0000000..f796a63 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py @@ -0,0 +1,72 @@ +# -*- coding: utf-8 -*- +#    This work is independent part of the Core Imaging Library developed by +#    Visual Analytics and Imaging System Group of the Science Technology +#    Facilities Council, STFC +#    This program is free software: you can redistribute it and/or modify +#    it under the terms of the GNU General Public License as published by +#    the Free Software Foundation, either version 3 of the License, or +#    (at your option) any later version. +# +#    This program is distributed in the hope that it will be useful, +#    but WITHOUT ANY WARRANTY; without even the implied warranty of +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#    GNU General Public License for more details. +# +#    You should have received a copy of the GNU General Public License +#    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +from ccpi.optimisation.operators import Operator, LinearOperator +from ccpi.framework import AcquisitionData, ImageData, DataContainer +from ccpi.optimisation.ops import PowerMethodNonsquare +from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \ +     AstraForwardProjectorMC, AstraBackProjectorMC, AstraForwardProjector3D, \ +     AstraBackProjector3D + +class AstraProjectorMC(LinearOperator): +    """ASTRA Multichannel projector""" +    def __init__(self, geomv, geomp, device): +        super(AstraProjectorMC, self).__init__() +         +        # Store volume and sinogram geometries. +        self.sinogram_geometry = geomp +        self.volume_geometry = geomv +         +        self.fp = AstraForwardProjectorMC(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        proj_id=None, +                                        device=device) +         +        self.bp = AstraBackProjectorMC(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        proj_id=None, +                                        device=device) +                 +        # Initialise empty for singular value. +        self.s1 = None     +     +    def direct(self, IM, out=None): +        self.fp.set_input(IM) +         +        if out is None: +            return self.fp.get_output() +        else: +            out.fill(self.fp.get_output()) +     +    def adjoint(self, DATA, out=None): +        self.bp.set_input(DATA) +         +        if out is None: +            return self.bp.get_output() +        else: +            out.fill(self.bp.get_output())     +     +    def domain_geometry(self): +        return self.volume_geometry +     +    def range_geometry(self): +        return self.sinogram_geometry     +     +    def norm(self): +        x0 = self.volume_geometry.allocate('random') +        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0) +        return self.s1
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py new file mode 100644 index 0000000..71bc3c6 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py @@ -0,0 +1,70 @@ +# -*- coding: utf-8 -*- +#    This work is independent part of the Core Imaging Library developed by +#    Visual Analytics and Imaging System Group of the Science Technology +#    Facilities Council, STFC +#    This program is free software: you can redistribute it and/or modify +#    it under the terms of the GNU General Public License as published by +#    the Free Software Foundation, either version 3 of the License, or +#    (at your option) any later version. +# +#    This program is distributed in the hope that it will be useful, +#    but WITHOUT ANY WARRANTY; without even the implied warranty of +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the +#    GNU General Public License for more details. +# +#    You should have received a copy of the GNU General Public License +#    along with this program.  If not, see <http://www.gnu.org/licenses/>. + +from ccpi.optimisation.operators import Operator, LinearOperator +from ccpi.framework import AcquisitionData, ImageData, DataContainer +from ccpi.optimisation.ops import PowerMethodNonsquare +from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector + +class AstraProjectorSimple(LinearOperator): +    """ASTRA projector modified to use DataSet and geometry.""" +    def __init__(self, geomv, geomp, device): +        super(AstraProjectorSimple, self).__init__() +         +        # Store volume and sinogram geometries. +        self.sinogram_geometry = geomp +        self.volume_geometry = geomv +         +        self.fp = AstraForwardProjector(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        proj_id=None, +                                        device=device) +         +        self.bp = AstraBackProjector(volume_geometry=geomv, +                                        sinogram_geometry=geomp, +                                        proj_id=None, +                                        device=device) +                 +        # Initialise empty for singular value. +        self.s1 = None +         +    def direct(self, IM, out=None): +        self.fp.set_input(IM) +         +        if out is None: +            return self.fp.get_output() +        else: +            out.fill(self.fp.get_output()) +     +    def adjoint(self, DATA, out=None): +        self.bp.set_input(DATA) +         +        if out is None: +            return self.bp.get_output() +        else: +            out.fill(self.bp.get_output()) + +    def domain_geometry(self): +        return self.volume_geometry +     +    def range_geometry(self): +        return self.sinogram_geometry     +     +    def norm(self): +        x0 = self.volume_geometry.allocate('random') +        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0) +        return self.s1
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/operators/__init__.py b/Wrappers/Python/ccpi/astra/operators/__init__.py new file mode 100644 index 0000000..6848776 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/__init__.py @@ -0,0 +1,4 @@ + +from .AstraProjectorSimple import AstraProjectorSimple +from .AstraProjector3DSimple import AstraProjector3DSimple +from .AstraProjectorMC import AstraProjectorMC
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/ops.py b/Wrappers/Python/ccpi/astra/ops.py deleted file mode 100755 index 85eb83a..0000000 --- a/Wrappers/Python/ccpi/astra/ops.py +++ /dev/null @@ -1,260 +0,0 @@ -# -*- coding: utf-8 -*- -#    This work is independent part of the Core Imaging Library developed by -#    Visual Analytics and Imaging System Group of the Science Technology -#    Facilities Council, STFC -#    This program is free software: you can redistribute it and/or modify -#    it under the terms of the GNU General Public License as published by -#    the Free Software Foundation, either version 3 of the License, or -#    (at your option) any later version. -# -#    This program is distributed in the hope that it will be useful, -#    but WITHOUT ANY WARRANTY; without even the implied warranty of -#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the -#    GNU General Public License for more details. -# -#    You should have received a copy of the GNU General Public License -#    along with this program.  If not, see <http://www.gnu.org/licenses/>. - -from ccpi.optimisation.operators import Operator, LinearOperator -import numpy -from ccpi.framework import AcquisitionData, ImageData, DataContainer -from ccpi.optimisation.ops import PowerMethodNonsquare -from ccpi.astra.processors import AstraForwardProjector, AstraBackProjector, \ -     AstraForwardProjectorMC, AstraBackProjectorMC, AstraForwardProjector3D, \ -     AstraBackProjector3D - -class AstraProjectorSimple(LinearOperator): -     -    """ASTRA projector modified to use DataSet and geometry.""" -    def __init__(self, geomv, geomp, device): -        super(AstraProjectorSimple, self).__init__() -         -        # Store volume and sinogram geometries. -        self.sinogram_geometry = geomp -        self.volume_geometry = geomv -         -        self.fp = AstraForwardProjector(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        proj_id=None, -                                        device=device) -         -        self.bp = AstraBackProjector(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        proj_id=None, -                                        device=device) -                 -        # Initialise empty for singular value. -        self.s1 = None -         -    def direct(self, IM, out=None): -        self.fp.set_input(IM) -         -        if out is None: -            return self.fp.get_output() -        else: -            out.fill(self.fp.get_output()) -     -    def adjoint(self, DATA, out=None): -        self.bp.set_input(DATA) -         -        if out is None: -            return self.bp.get_output() -        else: -            out.fill(self.bp.get_output()) -             -             -    def sum_abs_row(self): -         -        return self.adjoint(self.sinogram_geometry.allocate(1)) -             -    def sum_abs_col(self): - -        return self.direct(self.volume_geometry.allocate(1)) -                   -                -         -     -#    def direct(self, IM): -#        self.fp.set_input(IM) -#        out = self.fp.get_output() -#        return out -#     -#    def adjoint(self, DATA): -#        self.bp.set_input(DATA) -#        out = self.bp.get_output() -#        return out -     -    #def delete(self): -    #    astra.data2d.delete(self.proj_id) -     -    #def get_max_sing_val(self): -    #    self.s1, sall, svec = PowerMethodNonsquare(self,10) -    #    return self.s1 - -    def domain_geometry(self): -        return self.volume_geometry -     -    def range_geometry(self): -        return self.sinogram_geometry     -     -    def norm(self): - -        x0 = self.volume_geometry.allocate('random') -        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0) -        return self.s1 -     -    def size(self): -        # Only implemented for 2D -        return ( (self.sinogram_geometry.angles.size, \ -                  self.sinogram_geometry.pixel_num_h), \ -                 (self.volume_geometry.voxel_num_x, \ -                  self.volume_geometry.voxel_num_y) ) -     -    #def create_image_data(self): -    #    inputsize = self.size()[1] -    #    return DataContainer(numpy.random.randn(inputsize[0], -    #                                            inputsize[1])) - -class AstraProjector3DSimple(Operator): -    """ASTRA projector modified to use DataSet and geometry.""" -    def __init__(self, geomv, geomp): -        super(AstraProjector3DSimple, self).__init__() -         -        # Store volume and sinogram geometries. -        self.sinogram_geometry = geomp -        self.volume_geometry = geomv -         -        self.fp = AstraForwardProjector3D(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        output_axes_order=['vertical','angle','horizontal']) -         -        self.bp = AstraBackProjector3D(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        output_axes_order=['vertical','horizontal_y','horizontal_x']) -                 -        # Initialise empty for singular value. -        self.s1 = None -     -    def direct(self, IM): -        self.fp.set_input(IM) -        out = self.fp.get_output() -        return out -     -    def adjoint(self, DATA): -        self.bp.set_input(DATA) -        out = self.bp.get_output() -        return out -     -    #def delete(self): -    #    astra.data2d.delete(self.proj_id) -     -    def get_max_sing_val(self): -        self.s1, sall, svec = PowerMethodNonsquare(self,10) -        return self.s1 -     -    def size(self): -        # Only implemented for 2D -        return ( (self.sinogram_geometry.angles.size, \ -                  self.sinogram_geometry.pixel_num_h, \ -                  self.sinogram_geometry.pixel_num_v,), \ -                 (self.volume_geometry.voxel_num_x, \ -                  self.volume_geometry.voxel_num_y, \ -                  self.volume_geometry.voxel_num_z) ) -     -    def create_image_data(self): -        inputsize = self.size()[1] -        return DataContainer(numpy.random.randn(inputsize[2], -                                                inputsize[1], -                                                inputsize[0])) - - -class AstraProjectorMC(LinearOperator): -    """ASTRA Multichannel projector""" -    def __init__(self, geomv, geomp, device): -        super(AstraProjectorMC, self).__init__() -         -        # Store volume and sinogram geometries. -        self.sinogram_geometry = geomp -        self.volume_geometry = geomv -         -        self.fp = AstraForwardProjectorMC(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        proj_id=None, -                                        device=device) -         -        self.bp = AstraBackProjectorMC(volume_geometry=geomv, -                                        sinogram_geometry=geomp, -                                        proj_id=None, -                                        device=device) -                 -        # Initialise empty for singular value. -        self.s1 = None -     -#    def direct(self, IM): -#        self.fp.set_input(IM) -#        out = self.fp.get_output() -#        return out -#     -#    def adjoint(self, DATA): -#        self.bp.set_input(DATA) -#        out = self.bp.get_output() -#        return out -     -     -    def direct(self, IM, out=None): -        self.fp.set_input(IM) -         -        if out is None: -            return self.fp.get_output() -        else: -            out.fill(self.fp.get_output()) -     -    def adjoint(self, DATA, out=None): -        self.bp.set_input(DATA) -         -        if out is None: -            return self.bp.get_output() -        else: -            out.fill(self.bp.get_output())     -     -    #def delete(self): -    #    astra.data2d.delete(self.proj_id) -     -#    def get_max_sing_val(self): -#        if self.s1 is None: -#            self.s1, sall, svec = PowerMethodNonsquare(self,10) -#            return self.s1 -#        else: -#            return self.s1 -#     -#    def size(self): -#        # Only implemented for 2D -#        return ( (self.sinogram_geometry.angles.size, \ -#                  self.sinogram_geometry.pixel_num_h), \ -#                 (self.volume_geometry.voxel_num_x, \ -#                  self.volume_geometry.voxel_num_y) ) -#     -#    def create_image_data(self): -#        inputsize = self.size()[1] -#        return DataContainer(numpy.random.randn(self.volume_geometry.channels, -#                                                inputsize[0], -#                                                inputsize[1])) -         -#    def allocate_direct(self): -#        return self.create_image_data()def domain_geometry(self): -#        return self.volume_geometry -     -    def domain_geometry(self): -        return self.volume_geometry -     -    def range_geometry(self): -        return self.sinogram_geometry     -     -    def norm(self): - -        x0 = self.volume_geometry.allocate('random') -        self.s1, sall, svec = PowerMethodNonsquare(self, 50, x0) -        return self.s1 -     - - diff --git a/Wrappers/Python/ccpi/astra/processors.py b/Wrappers/Python/ccpi/astra/processors.py deleted file mode 100644 index 855f890..0000000 --- a/Wrappers/Python/ccpi/astra/processors.py +++ /dev/null @@ -1,363 +0,0 @@ -from ccpi.framework import DataProcessor, ImageData, AcquisitionData -from ccpi.astra.utils import convert_geometry_to_astra -import astra - - -class AstraForwardProjector(DataProcessor): -    '''AstraForwardProjector -     -    Forward project ImageData to AcquisitionData using ASTRA proj_id. -     -    Input: ImageData -    Parameter: proj_id -    Output: AcquisitionData -    ''' -     -    def __init__(self, -                 volume_geometry=None, -                 sinogram_geometry=None, -                 proj_id=None, -                 device='cpu'): -        kwargs = { -                  'volume_geometry'  : volume_geometry, -                  'sinogram_geometry'  : sinogram_geometry, -                  'proj_id'  : proj_id, -                  'device'  : device -                  } -         -        #DataProcessor.__init__(self, **kwargs) -        super(AstraForwardProjector, self).__init__(**kwargs) -         -        self.set_ImageGeometry(volume_geometry) -        self.set_AcquisitionGeometry(sinogram_geometry) -         -        # Set up ASTRA Volume and projection geometry, not to be stored in self -        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, -                                                        self.sinogram_geometry) -         -        # ASTRA projector, to be stored -        if device == 'cpu': -            # Note that 'line' only one option -            if self.sinogram_geometry.geom_type == 'parallel': -                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) ) -            elif self.sinogram_geometry.geom_type == 'cone': -                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) ) -            else: -                NotImplemented     -        elif device == 'gpu': -            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) ) -        else: -            NotImplemented -     -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 3 or\ -           dataset.number_of_dimensions == 2: -               return True -        else: -            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -     -    def set_projector(self, proj_id): -        self.proj_id = proj_id -     -    def set_ImageGeometry(self, volume_geometry): -        self.volume_geometry = volume_geometry -     -    def set_AcquisitionGeometry(self, sinogram_geometry): -        self.sinogram_geometry = sinogram_geometry -     -    def process(self): -        IM = self.get_input() -        DATA = AcquisitionData(geometry=self.sinogram_geometry) -        #sinogram_id, DATA = astra.create_sino( IM.as_array(),  -        #                           self.proj_id) -        sinogram_id, DATA.array = astra.create_sino(IM.as_array(),  -                                                           self.proj_id) -        astra.data2d.delete(sinogram_id) -         -        if self.device == 'cpu': -            return DATA -        else: -            if self.sinogram_geometry.geom_type == 'cone': -                return DATA -            else: -                 scaling = 1.0/self.volume_geometry.voxel_size_x -                 return scaling*DATA - -class AstraBackProjector(DataProcessor): -    '''AstraBackProjector -     -    Back project AcquisitionData to ImageData using ASTRA proj_id. -     -    Input: AcquisitionData -    Parameter: proj_id -    Output: ImageData -    ''' -     -    def __init__(self, -                 volume_geometry=None, -                 sinogram_geometry=None, -                 proj_id=None, -                 device='cpu'): -        kwargs = { -                  'volume_geometry'  : volume_geometry, -                  'sinogram_geometry'  : sinogram_geometry, -                  'proj_id'  : proj_id, -                  'device'  : device -                  } -         -        #DataProcessor.__init__(self, **kwargs) -        super(AstraBackProjector, self).__init__(**kwargs) -         -        self.set_ImageGeometry(volume_geometry) -        self.set_AcquisitionGeometry(sinogram_geometry) -         -                # Set up ASTRA Volume and projection geometry, not to be stored in self -        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, -                                                        self.sinogram_geometry) -         -        # ASTRA projector, to be stored -        if device == 'cpu': -            # Note that 'line' only one option -            if self.sinogram_geometry.geom_type == 'parallel': -                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) ) -            elif self.sinogram_geometry.geom_type == 'cone': -                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) ) -            else: -                NotImplemented  -        elif device == 'gpu': -            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) ) -        else: -            NotImplemented -     -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 3 or dataset.number_of_dimensions == 2: -               return True -        else: -            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -     -    def set_projector(self, proj_id): -        self.proj_id = proj_id -         -    def set_ImageGeometry(self, volume_geometry): -        self.volume_geometry = volume_geometry -         -    def set_AcquisitionGeometry(self, sinogram_geometry): -        self.sinogram_geometry = sinogram_geometry -     -    def process(self): -        DATA = self.get_input() -        IM = ImageData(geometry=self.volume_geometry) -        rec_id, IM.array = astra.create_backprojection(DATA.as_array(), -                            self.proj_id) -        astra.data2d.delete(rec_id) -         -        if self.device == 'cpu': -            return IM -        else: -            scaling = self.volume_geometry.voxel_size_x**3   -            return scaling*IM - -class AstraForwardProjectorMC(AstraForwardProjector): -    '''AstraForwardProjector Multi channel -     -    Forward project ImageData to AcquisitionDataSet using ASTRA proj_id. -     -    Input: ImageDataSet -    Parameter: proj_id -    Output: AcquisitionData -    ''' -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 2 or \ -           dataset.number_of_dimensions == 3 or \ -           dataset.number_of_dimensions == 4: -               return True -        else: -            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -    def process(self): -        IM = self.get_input() -        #create the output AcquisitionData -        DATA = AcquisitionData(geometry=self.sinogram_geometry) -         -        for k in range(DATA.geometry.channels): -            sinogram_id, DATA.as_array()[k] = astra.create_sino(IM.as_array()[k],  -                                                           self.proj_id) -            astra.data2d.delete(sinogram_id) -         -        if self.device == 'cpu': -            return DATA -        else: -            if self.sinogram_geometry.geom_type == 'cone': -                return DATA -            else: -                 scaling = (1.0/self.volume_geometry.voxel_size_x)  -                 return scaling*DATA - -class AstraBackProjectorMC(AstraBackProjector): -    '''AstraBackProjector Multi channel -     -    Back project AcquisitionData to ImageData using ASTRA proj_id. -     -    Input: AcquisitionData -    Parameter: proj_id -    Output: ImageData -    ''' -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 2 or \ -           dataset.number_of_dimensions == 3 or \ -           dataset.number_of_dimensions == 4: -               return True -        else: -            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -    def process(self): -        DATA = self.get_input() -         -        IM = ImageData(geometry=self.volume_geometry) -         -        for k in range(IM.geometry.channels): -            rec_id, IM.as_array()[k] = astra.create_backprojection( -                    DATA.as_array()[k],  -                    self.proj_id) -            astra.data2d.delete(rec_id) -         -        if self.device == 'cpu': -            return IM -        else: -            scaling = self.volume_geometry.voxel_size_x**3   -            return scaling*IM - -class AstraForwardProjector3D(DataProcessor): -    '''AstraForwardProjector3D -     -    Forward project ImageData to AcquisitionData using ASTRA proj_geom and  -    vol_geom. -     -    Input: ImageData -    Parameter: proj_geom, vol_geom -    Output: AcquisitionData -    ''' -     -    def __init__(self, -                 volume_geometry=None, -                 sinogram_geometry=None, -                 proj_geom=None, -                 vol_geom=None, -                 output_axes_order=None): -        kwargs = { -                  'volume_geometry'  : volume_geometry, -                  'sinogram_geometry'  : sinogram_geometry, -                  'proj_geom'  : proj_geom, -                  'vol_geom'  : vol_geom, -                  'output_axes_order'  : output_axes_order -                  } -         -        #DataProcessor.__init__(self, **kwargs) -        super(AstraForwardProjector3D, self).__init__(**kwargs) -         -        self.set_ImageGeometry(volume_geometry) -        self.set_AcquisitionGeometry(sinogram_geometry) -         -        # Set up ASTRA Volume and projection geometry, not to be stored in self -        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, -                                                        self.sinogram_geometry) -         -        # Also store ASTRA geometries -        self.vol_geom = vol_geom -        self.proj_geom = proj_geom -     -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 3: -               return True -        else: -            raise ValueError("Expected input dimensions 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -     -    def set_ImageGeometry(self, volume_geometry): -        self.volume_geometry = volume_geometry -     -    def set_AcquisitionGeometry(self, sinogram_geometry): -        self.sinogram_geometry = sinogram_geometry -     -    def set_vol_geom(self, vol_geom): -        self.vol_geom = vol_geom -     -    def set_AcquisitionGeometry(self, sinogram_geometry): -        self.sinogram_geometry = sinogram_geometry -     -    def process(self): -        IM = self.get_input() -        DATA = AcquisitionData(geometry=self.sinogram_geometry, -                               dimension_labels=self.output_axes_order) -        sinogram_id, DATA.array = astra.create_sino3d_gpu(IM.as_array(),  -                                                           self.proj_geom, -                                                           self.vol_geom) -        astra.data3d.delete(sinogram_id) -        # 3D CUDA FP does not need scaling -        return DATA - -class AstraBackProjector3D(DataProcessor): -    '''AstraBackProjector3D -     -    Back project AcquisitionData to ImageData using ASTRA proj_geom, vol_geom. -     -    Input: AcquisitionData -    Parameter: proj_geom, vol_geom -    Output: ImageData -    ''' -     -    def __init__(self, -                 volume_geometry=None, -                 sinogram_geometry=None, -                 proj_geom=None, -                 vol_geom=None, -                 output_axes_order=None): -        kwargs = { -                  'volume_geometry'  : volume_geometry, -                  'sinogram_geometry'  : sinogram_geometry, -                  'proj_geom'  : proj_geom, -                  'vol_geom'  : vol_geom, -                  'output_axes_order'  : output_axes_order -                  } -         -        #DataProcessor.__init__(self, **kwargs) -        super(AstraBackProjector3D, self).__init__(**kwargs) -         -        self.set_ImageGeometry(volume_geometry) -        self.set_AcquisitionGeometry(sinogram_geometry) -         -                # Set up ASTRA Volume and projection geometry, not to be stored in self -        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, -                                                        self.sinogram_geometry) -         -        # Also store ASTRA geometries -        self.vol_geom = vol_geom -        self.proj_geom = proj_geom -     -    def check_input(self, dataset): -        if dataset.number_of_dimensions == 3: -               return True -        else: -            raise ValueError("Expected input dimensions is 3, got {0}"\ -                             .format(dataset.number_of_dimensions)) -         -    def set_ImageGeometry(self, volume_geometry): -        self.volume_geometry = volume_geometry -         -    def set_AcquisitionGeometry(self, sinogram_geometry): -        self.sinogram_geometry = sinogram_geometry -     -    def process(self): -        DATA = self.get_input() -        IM = ImageData(geometry=self.volume_geometry, -                       dimension_labels=self.output_axes_order) -        rec_id, IM.array = astra.create_backprojection3d_gpu(DATA.as_array(), -                            self.proj_geom, -                            self.vol_geom) -        astra.data3d.delete(rec_id) -         -        # Scaling of 3D ASTRA backprojector, works both parallel and cone. -        scaling = 1/self.volume_geometry.voxel_size_x**2   -        return scaling*IM diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py new file mode 100644 index 0000000..d094e79 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py @@ -0,0 +1,84 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra +import astra + + +class AstraBackProjector(DataProcessor): +    '''AstraBackProjector +     +    Back project AcquisitionData to ImageData using ASTRA proj_id. +     +    Input: AcquisitionData +    Parameter: proj_id +    Output: ImageData +    ''' +     +    def __init__(self, +                 volume_geometry=None, +                 sinogram_geometry=None, +                 proj_id=None, +                 device='cpu'): +        kwargs = { +                  'volume_geometry'  : volume_geometry, +                  'sinogram_geometry'  : sinogram_geometry, +                  'proj_id'  : proj_id, +                  'device'  : device +                  } +         +        #DataProcessor.__init__(self, **kwargs) +        super(AstraBackProjector, self).__init__(**kwargs) +         +        self.set_ImageGeometry(volume_geometry) +        self.set_AcquisitionGeometry(sinogram_geometry) +         +                # Set up ASTRA Volume and projection geometry, not to be stored in self +        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, +                                                        self.sinogram_geometry) +         +        # ASTRA projector, to be stored +        if device == 'cpu': +            # Note that 'line' only one option +            if self.sinogram_geometry.geom_type == 'parallel': +                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) ) +            elif self.sinogram_geometry.geom_type == 'cone': +                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) ) +            else: +                NotImplemented  +        elif device == 'gpu': +            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) ) +        else: +            NotImplemented +     +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 3 or dataset.number_of_dimensions == 2: +               return True +        else: +            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +     +    def set_projector(self, proj_id): +        self.proj_id = proj_id +         +    def set_ImageGeometry(self, volume_geometry): +        self.volume_geometry = volume_geometry +         +    def set_AcquisitionGeometry(self, sinogram_geometry): +        self.sinogram_geometry = sinogram_geometry +     +    def process(self, out=None): +        DATA = self.get_input() +        IM = ImageData(geometry=self.volume_geometry) +        rec_id, IM.array = astra.create_backprojection(DATA.as_array(), +                            self.proj_id) +        astra.data2d.delete(rec_id) +         +        if self.device == 'cpu': +            ret = IM +        else: +            scaling = self.volume_geometry.voxel_size_x**3   +            ret = scaling*IM +         +        if out is None: +            return ret +        else: +            out.fill(ret)
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py new file mode 100644 index 0000000..26a549a --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py @@ -0,0 +1,72 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra +import astra + +class AstraBackProjector3D(DataProcessor): +    '''AstraBackProjector3D +     +    Back project AcquisitionData to ImageData using ASTRA proj_geom, vol_geom. +     +    Input: AcquisitionData +    Parameter: proj_geom, vol_geom +    Output: ImageData +    ''' +     +    def __init__(self, +                 volume_geometry=None, +                 sinogram_geometry=None, +                 proj_geom=None, +                 vol_geom=None, +                 output_axes_order=None): +        kwargs = { +                  'volume_geometry'  : volume_geometry, +                  'sinogram_geometry'  : sinogram_geometry, +                  'proj_geom'  : proj_geom, +                  'vol_geom'  : vol_geom, +                  'output_axes_order'  : output_axes_order +                  } +         +        #DataProcessor.__init__(self, **kwargs) +        super(AstraBackProjector3D, self).__init__(**kwargs) +         +        self.set_ImageGeometry(volume_geometry) +        self.set_AcquisitionGeometry(sinogram_geometry) +         +                # Set up ASTRA Volume and projection geometry, not to be stored in self +        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, +                                                        self.sinogram_geometry) +         +        # Also store ASTRA geometries +        self.vol_geom = vol_geom +        self.proj_geom = proj_geom +     +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 3: +               return True +        else: +            raise ValueError("Expected input dimensions is 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +         +    def set_ImageGeometry(self, volume_geometry): +        self.volume_geometry = volume_geometry +         +    def set_AcquisitionGeometry(self, sinogram_geometry): +        self.sinogram_geometry = sinogram_geometry +     +    def process(self, out=None): +        DATA = self.get_input() +        IM = ImageData(geometry=self.volume_geometry, +                       dimension_labels=self.output_axes_order) +        rec_id, IM.array = astra.create_backprojection3d_gpu(DATA.as_array(), +                            self.proj_geom, +                            self.vol_geom) +        astra.data3d.delete(rec_id) +         +        # Scaling of 3D ASTRA backprojector, works both parallel and cone. +        scaling = 1/self.volume_geometry.voxel_size_x**2   +        ret = scaling*IM +         +        if out is None: +            return ret +        else: +            out.fill(ret) diff --git a/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py new file mode 100644 index 0000000..ef8fe5d --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py @@ -0,0 +1,46 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra + +from ccpi.astra.processors import AstraBackProjector + +import astra + +class AstraBackProjectorMC(AstraBackProjector): +    '''AstraBackProjector Multi channel +     +    Back project AcquisitionData to ImageData using ASTRA proj_id. +     +    Input: AcquisitionData +    Parameter: proj_id +    Output: ImageData +    ''' +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 2 or \ +           dataset.number_of_dimensions == 3 or \ +           dataset.number_of_dimensions == 4: +               return True +        else: +            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +     +    def process(self, out=None): +        DATA = self.get_input() +         +        IM = ImageData(geometry=self.volume_geometry) +         +        for k in range(IM.geometry.channels): +            rec_id, IM.as_array()[k] = astra.create_backprojection( +                    DATA.as_array()[k],  +                    self.proj_id) +            astra.data2d.delete(rec_id) +         +        if self.device == 'cpu': +            ret = IM +        else: +            scaling = self.volume_geometry.voxel_size_x**3   +            ret = scaling*IM +         +        if out is None: +            return ret +        else: +            out.fill(ret) diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py new file mode 100644 index 0000000..2cf5716 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py @@ -0,0 +1,88 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra +import astra + + +class AstraForwardProjector(DataProcessor): +    '''AstraForwardProjector +     +    Forward project ImageData to AcquisitionData using ASTRA proj_id. +     +    Input: ImageData +    Parameter: proj_id +    Output: AcquisitionData +    ''' +     +    def __init__(self, +                 volume_geometry=None, +                 sinogram_geometry=None, +                 proj_id=None, +                 device='cpu'): +        kwargs = { +                  'volume_geometry'  : volume_geometry, +                  'sinogram_geometry'  : sinogram_geometry, +                  'proj_id'  : proj_id, +                  'device'  : device +                  } +         +        #DataProcessor.__init__(self, **kwargs) +        super(AstraForwardProjector, self).__init__(**kwargs) +         +        self.set_ImageGeometry(volume_geometry) +        self.set_AcquisitionGeometry(sinogram_geometry) +         +        # Set up ASTRA Volume and projection geometry, not to be stored in self +        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, +                                                        self.sinogram_geometry) +         +        # ASTRA projector, to be stored +        if device == 'cpu': +            # Note that 'line' only one option +            if self.sinogram_geometry.geom_type == 'parallel': +                self.set_projector(astra.create_projector('line', proj_geom, vol_geom) ) +            elif self.sinogram_geometry.geom_type == 'cone': +                self.set_projector(astra.create_projector('line_fanflat', proj_geom, vol_geom) ) +            else: +                NotImplemented     +        elif device == 'gpu': +            self.set_projector(astra.create_projector('cuda', proj_geom, vol_geom) ) +        else: +            NotImplemented +     +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 3 or\ +           dataset.number_of_dimensions == 2: +               return True +        else: +            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +     +    def set_projector(self, proj_id): +        self.proj_id = proj_id +     +    def set_ImageGeometry(self, volume_geometry): +        self.volume_geometry = volume_geometry +     +    def set_AcquisitionGeometry(self, sinogram_geometry): +        self.sinogram_geometry = sinogram_geometry +         +    def process(self, out=None): +        IM = self.get_input() +        DATA = AcquisitionData(geometry=self.sinogram_geometry) +        sinogram_id, DATA.array = astra.create_sino(IM.as_array(),  +                                                           self.proj_id) +        astra.data2d.delete(sinogram_id) +         +        if self.device == 'cpu': +            ret = DATA +        else: +            if self.sinogram_geometry.geom_type == 'cone': +                ret = DATA +            else: +                 scaling = 1.0/self.volume_geometry.voxel_size_x +                 ret = scaling*DATA +         +        if out is None: +            return ret +        else: +            out.fill(ret)
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py new file mode 100644 index 0000000..18b4078 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py @@ -0,0 +1,73 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra +import astra + +class AstraForwardProjector3D(DataProcessor): +    '''AstraForwardProjector3D +     +    Forward project ImageData to AcquisitionData using ASTRA proj_geom and  +    vol_geom. +     +    Input: ImageData +    Parameter: proj_geom, vol_geom +    Output: AcquisitionData +    ''' +     +    def __init__(self, +                 volume_geometry=None, +                 sinogram_geometry=None, +                 proj_geom=None, +                 vol_geom=None, +                 output_axes_order=None): +        kwargs = { +                  'volume_geometry'  : volume_geometry, +                  'sinogram_geometry'  : sinogram_geometry, +                  'proj_geom'  : proj_geom, +                  'vol_geom'  : vol_geom, +                  'output_axes_order'  : output_axes_order +                  } +         +        #DataProcessor.__init__(self, **kwargs) +        super(AstraForwardProjector3D, self).__init__(**kwargs) +         +        self.set_ImageGeometry(volume_geometry) +        self.set_AcquisitionGeometry(sinogram_geometry) +         +        # Set up ASTRA Volume and projection geometry, not to be stored in self +        vol_geom, proj_geom = convert_geometry_to_astra(self.volume_geometry, +                                                        self.sinogram_geometry) +         +        # Also store ASTRA geometries +        self.vol_geom = vol_geom +        self.proj_geom = proj_geom +     +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 3: +               return True +        else: +            raise ValueError("Expected input dimensions 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +     +    def set_ImageGeometry(self, volume_geometry): +        self.volume_geometry = volume_geometry +     +    def set_AcquisitionGeometry(self, sinogram_geometry): +        self.sinogram_geometry = sinogram_geometry +     +    def set_vol_geom(self, vol_geom): +        self.vol_geom = vol_geom +     +    def process(self, out=None): +        IM = self.get_input() +        DATA = AcquisitionData(geometry=self.sinogram_geometry, +                               dimension_labels=self.output_axes_order) +        sinogram_id, DATA.array = astra.create_sino3d_gpu(IM.as_array(),  +                                                           self.proj_geom, +                                                           self.vol_geom) +        astra.data3d.delete(sinogram_id) +        # 3D CUDA FP does not need scaling +         +        if out is None: +            return DATA +        else: +            out.fill(DATA)
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py new file mode 100644 index 0000000..34f4222 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py @@ -0,0 +1,48 @@ +from ccpi.framework import DataProcessor, ImageData, AcquisitionData +from ccpi.astra.utils import convert_geometry_to_astra + +from ccpi.astra.processors import AstraForwardProjector + +import astra + +class AstraForwardProjectorMC(AstraForwardProjector): +    '''AstraForwardProjector Multi channel +     +    Forward project ImageData to AcquisitionDataSet using ASTRA proj_id. +     +    Input: ImageDataSet +    Parameter: proj_id +    Output: AcquisitionData +    ''' +    def check_input(self, dataset): +        if dataset.number_of_dimensions == 2 or \ +           dataset.number_of_dimensions == 3 or \ +           dataset.number_of_dimensions == 4: +               return True +        else: +            raise ValueError("Expected input dimensions is 2 or 3, got {0}"\ +                             .format(dataset.number_of_dimensions)) +     +    def process(self, out=None): +        IM = self.get_input() +        #create the output AcquisitionData +        DATA = AcquisitionData(geometry=self.sinogram_geometry) +         +        for k in range(DATA.geometry.channels): +            sinogram_id, DATA.as_array()[k] = astra.create_sino(IM.as_array()[k],  +                                                           self.proj_id) +            astra.data2d.delete(sinogram_id) +         +        if self.device == 'cpu': +            ret = DATA +        else: +            if self.sinogram_geometry.geom_type == 'cone': +                ret = DATA +            else: +                 scaling = (1.0/self.volume_geometry.voxel_size_x)  +                 ret = scaling*DATA +         +        if out is None: +            return ret +        else: +            out.fill(ret)
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/processors/__init__.py b/Wrappers/Python/ccpi/astra/processors/__init__.py new file mode 100644 index 0000000..6bfd7f5 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/__init__.py @@ -0,0 +1,7 @@ + +from .AstraForwardProjector import AstraForwardProjector +from .AstraBackProjector import AstraBackProjector +from .AstraForwardProjectorMC import AstraForwardProjectorMC +from .AstraBackProjectorMC import AstraBackProjectorMC +from .AstraForwardProjector3D import AstraForwardProjector3D +from .AstraBackProjector3D import AstraBackProjector3D diff --git a/Wrappers/Python/ccpi/astra/utils/__init__.py b/Wrappers/Python/ccpi/astra/utils/__init__.py new file mode 100644 index 0000000..c740fba --- /dev/null +++ b/Wrappers/Python/ccpi/astra/utils/__init__.py @@ -0,0 +1,2 @@ + +from .convert_geometry_to_astra import convert_geometry_to_astra
\ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/utils.py b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py index 2b19305..2b19305 100755..100644 --- a/Wrappers/Python/ccpi/astra/utils.py +++ b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py | 
