From 6f094f37fd2503e104a0477ac01d7a5b825d351a Mon Sep 17 00:00:00 2001 From: "Jakob Jorgensen, WS at HMXIF" Date: Fri, 26 Apr 2019 15:53:10 +0100 Subject: Reorganise ops, processors and utils as directories --- .../ccpi/astra/operators/AstraProjector3DSimple.py | 75 +++++ .../ccpi/astra/operators/AstraProjectorMC.py | 112 +++++++ .../ccpi/astra/operators/AstraProjectorSimple.py | 71 ++++ Wrappers/Python/ccpi/astra/operators/__init__.py | 4 + Wrappers/Python/ccpi/astra/ops.py | 249 -------------- Wrappers/Python/ccpi/astra/processors.py | 363 --------------------- .../ccpi/astra/processors/AstraBackProjector.py | 80 +++++ .../ccpi/astra/processors/AstraBackProjector3D.py | 67 ++++ .../ccpi/astra/processors/AstraBackProjectorMC.py | 40 +++ .../ccpi/astra/processors/AstraForwardProjector.py | 85 +++++ .../astra/processors/AstraForwardProjector3D.py | 72 ++++ .../astra/processors/AstraForwardProjectorMC.py | 42 +++ Wrappers/Python/ccpi/astra/processors/__init__.py | 7 + Wrappers/Python/ccpi/astra/utils.py | 62 ---- Wrappers/Python/ccpi/astra/utils/__init__.py | 2 + .../ccpi/astra/utils/convert_geometry_to_astra.py | 62 ++++ Wrappers/Python/setup.py | 6 +- Wrappers/Python/wip/demo_astra_mc.py | 2 +- Wrappers/Python/wip/demo_astra_nexus.py | 2 +- Wrappers/Python/wip/demo_astra_simple.py | 2 +- Wrappers/Python/wip/demo_astra_sophiabeads.py | 2 +- Wrappers/Python/wip/demo_astra_sophiabeads3D.py | 2 +- Wrappers/Python/wip/work_out_adjoint.py | 2 +- Wrappers/Python/wip/work_out_adjoint3D.py | 2 +- .../Python/wip/work_out_adjoint_sophiabeads.py | 2 +- 25 files changed, 732 insertions(+), 683 deletions(-) create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py create mode 100644 Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py create mode 100644 Wrappers/Python/ccpi/astra/operators/__init__.py delete mode 100755 Wrappers/Python/ccpi/astra/ops.py delete mode 100644 Wrappers/Python/ccpi/astra/processors.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py create mode 100644 Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py create mode 100644 Wrappers/Python/ccpi/astra/processors/__init__.py delete mode 100755 Wrappers/Python/ccpi/astra/utils.py create mode 100644 Wrappers/Python/ccpi/astra/utils/__init__.py create mode 100644 Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py diff --git a/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py new file mode 100644 index 0000000..3240ee4 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjector3DSimple.py @@ -0,0 +1,75 @@ +# -*- 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 . + +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, \ + 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): + 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])) \ 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..51f51ca --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorMC.py @@ -0,0 +1,112 @@ +# -*- 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 . + +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): +# 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 + \ 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..b459e82 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/operators/AstraProjectorSimple.py @@ -0,0 +1,71 @@ +# -*- 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 . + +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 3cc8453..0000000 --- a/Wrappers/Python/ccpi/astra/ops.py +++ /dev/null @@ -1,249 +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 . - -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 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..476523a --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector.py @@ -0,0 +1,80 @@ +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): + 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 + \ 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..b1d139e --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjector3D.py @@ -0,0 +1,67 @@ +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): + 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/AstraBackProjectorMC.py b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py new file mode 100644 index 0000000..d48fb80 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraBackProjectorMC.py @@ -0,0 +1,40 @@ +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): + 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 \ No newline at end of file diff --git a/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py new file mode 100644 index 0000000..dd5bab4 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector.py @@ -0,0 +1,85 @@ +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 \ 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..d18b43e --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjector3D.py @@ -0,0 +1,72 @@ +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 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 \ 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..5a697ca --- /dev/null +++ b/Wrappers/Python/ccpi/astra/processors/AstraForwardProjectorMC.py @@ -0,0 +1,42 @@ +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): + 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 \ 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.py b/Wrappers/Python/ccpi/astra/utils.py deleted file mode 100755 index 2b19305..0000000 --- a/Wrappers/Python/ccpi/astra/utils.py +++ /dev/null @@ -1,62 +0,0 @@ -import astra -import numpy as np - -def convert_geometry_to_astra(volume_geometry, sinogram_geometry): - # Set up ASTRA Volume and projection geometry, not stored - if sinogram_geometry.dimension == '2D': - vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, - volume_geometry.voxel_num_y, - volume_geometry.get_min_x(), - volume_geometry.get_max_x(), - volume_geometry.get_min_y(), - volume_geometry.get_max_y()) - - if sinogram_geometry.geom_type == 'parallel': - proj_geom = astra.create_proj_geom('parallel', - sinogram_geometry.pixel_size_h, - sinogram_geometry.pixel_num_h, - sinogram_geometry.angles) - elif sinogram_geometry.geom_type == 'cone': - proj_geom = astra.create_proj_geom('fanflat', - sinogram_geometry.pixel_size_h, - sinogram_geometry.pixel_num_h, - sinogram_geometry.angles, - np.abs(sinogram_geometry.dist_source_center), - np.abs(sinogram_geometry.dist_center_detector)) - else: - NotImplemented - - elif sinogram_geometry.dimension == '3D': - vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, - volume_geometry.voxel_num_y, - volume_geometry.voxel_num_z, - volume_geometry.get_min_x(), - volume_geometry.get_max_x(), - volume_geometry.get_min_y(), - volume_geometry.get_max_y(), - volume_geometry.get_min_z(), - volume_geometry.get_max_z()) - - if sinogram_geometry.geom_type == 'parallel': - proj_geom = astra.create_proj_geom('parallel3d', - sinogram_geometry.pixel_size_h, - sinogram_geometry.pixel_size_v, - sinogram_geometry.pixel_num_v, - sinogram_geometry.pixel_num_h, - sinogram_geometry.angles) - elif sinogram_geometry.geom_type == 'cone': - proj_geom = astra.create_proj_geom('cone', - sinogram_geometry.pixel_size_h, - sinogram_geometry.pixel_size_v, - sinogram_geometry.pixel_num_v, - sinogram_geometry.pixel_num_h, - sinogram_geometry.angles, - np.abs(sinogram_geometry.dist_source_center), - np.abs(sinogram_geometry.dist_center_detector)) - else: - NotImplemented - - else: - NotImplemented - - return vol_geom, proj_geom \ No newline at end of file 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/convert_geometry_to_astra.py b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py new file mode 100644 index 0000000..2b19305 --- /dev/null +++ b/Wrappers/Python/ccpi/astra/utils/convert_geometry_to_astra.py @@ -0,0 +1,62 @@ +import astra +import numpy as np + +def convert_geometry_to_astra(volume_geometry, sinogram_geometry): + # Set up ASTRA Volume and projection geometry, not stored + if sinogram_geometry.dimension == '2D': + vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, + volume_geometry.voxel_num_y, + volume_geometry.get_min_x(), + volume_geometry.get_max_x(), + volume_geometry.get_min_y(), + volume_geometry.get_max_y()) + + if sinogram_geometry.geom_type == 'parallel': + proj_geom = astra.create_proj_geom('parallel', + sinogram_geometry.pixel_size_h, + sinogram_geometry.pixel_num_h, + sinogram_geometry.angles) + elif sinogram_geometry.geom_type == 'cone': + proj_geom = astra.create_proj_geom('fanflat', + sinogram_geometry.pixel_size_h, + sinogram_geometry.pixel_num_h, + sinogram_geometry.angles, + np.abs(sinogram_geometry.dist_source_center), + np.abs(sinogram_geometry.dist_center_detector)) + else: + NotImplemented + + elif sinogram_geometry.dimension == '3D': + vol_geom = astra.create_vol_geom(volume_geometry.voxel_num_x, + volume_geometry.voxel_num_y, + volume_geometry.voxel_num_z, + volume_geometry.get_min_x(), + volume_geometry.get_max_x(), + volume_geometry.get_min_y(), + volume_geometry.get_max_y(), + volume_geometry.get_min_z(), + volume_geometry.get_max_z()) + + if sinogram_geometry.geom_type == 'parallel': + proj_geom = astra.create_proj_geom('parallel3d', + sinogram_geometry.pixel_size_h, + sinogram_geometry.pixel_size_v, + sinogram_geometry.pixel_num_v, + sinogram_geometry.pixel_num_h, + sinogram_geometry.angles) + elif sinogram_geometry.geom_type == 'cone': + proj_geom = astra.create_proj_geom('cone', + sinogram_geometry.pixel_size_h, + sinogram_geometry.pixel_size_v, + sinogram_geometry.pixel_num_v, + sinogram_geometry.pixel_num_h, + sinogram_geometry.angles, + np.abs(sinogram_geometry.dist_source_center), + np.abs(sinogram_geometry.dist_center_detector)) + else: + NotImplemented + + else: + NotImplemented + + return vol_geom, proj_geom \ No newline at end of file diff --git a/Wrappers/Python/setup.py b/Wrappers/Python/setup.py index 85dde19..e854dee 100755 --- a/Wrappers/Python/setup.py +++ b/Wrappers/Python/setup.py @@ -32,7 +32,11 @@ cil_version='0.12.0' setup( name="ccpi-astra", version=cil_version, - packages=['ccpi' , 'ccpi.astra'], + packages=['ccpi' , + 'ccpi.astra', + 'ccpi.astra.operators', + 'ccpi.astra.processors', + 'ccpi.astra.utils'], # Project uses reStructuredText, so ensure that the docutils get # installed or upgraded on the target machine diff --git a/Wrappers/Python/wip/demo_astra_mc.py b/Wrappers/Python/wip/demo_astra_mc.py index f09dcb8..e5999de 100755 --- a/Wrappers/Python/wip/demo_astra_mc.py +++ b/Wrappers/Python/wip/demo_astra_mc.py @@ -8,7 +8,7 @@ from ccpi.framework import ImageData, AcquisitionData, ImageGeometry, AcquisitionGeometry from ccpi.optimisation.algs import FISTA from ccpi.optimisation.funcs import Norm2sq, Norm1 -from ccpi.astra.ops import AstraProjectorMC +from ccpi.astra.operators import AstraProjectorMC import numpy import matplotlib.pyplot as plt diff --git a/Wrappers/Python/wip/demo_astra_nexus.py b/Wrappers/Python/wip/demo_astra_nexus.py index 1db44c0..7892d24 100644 --- a/Wrappers/Python/wip/demo_astra_nexus.py +++ b/Wrappers/Python/wip/demo_astra_nexus.py @@ -15,7 +15,7 @@ from ccpi.plugins.ops import CCPiProjectorSimple from ccpi.processors import Normalizer, CenterOfRotationFinder from ccpi.plugins.processors import AcquisitionDataPadder from ccpi.io.reader import NexusReader -from ccpi.astra.ops import AstraProjector3DSimple +from ccpi.astra.operators import AstraProjector3DSimple # All external imports import numpy diff --git a/Wrappers/Python/wip/demo_astra_simple.py b/Wrappers/Python/wip/demo_astra_simple.py index c1dd877..57caaee 100755 --- a/Wrappers/Python/wip/demo_astra_simple.py +++ b/Wrappers/Python/wip/demo_astra_simple.py @@ -8,7 +8,7 @@ from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry from ccpi.optimisation.algs import FISTA, FBPD, CGLS from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D -from ccpi.astra.ops import AstraProjectorSimple +from ccpi.astra.operators import AstraProjectorSimple import numpy as np import matplotlib.pyplot as plt diff --git a/Wrappers/Python/wip/demo_astra_sophiabeads.py b/Wrappers/Python/wip/demo_astra_sophiabeads.py index bcc775e..b72a5f9 100755 --- a/Wrappers/Python/wip/demo_astra_sophiabeads.py +++ b/Wrappers/Python/wip/demo_astra_sophiabeads.py @@ -11,7 +11,7 @@ from ccpi.io.reader import XTEKReader import numpy as np import matplotlib.pyplot as plt from ccpi.framework import ImageGeometry, AcquisitionGeometry, AcquisitionData, ImageData -from ccpi.astra.ops import AstraProjectorSimple +from ccpi.astra.operators import AstraProjectorSimple from ccpi.optimisation.algs import CGLS # Set up reader object and read the data diff --git a/Wrappers/Python/wip/demo_astra_sophiabeads3D.py b/Wrappers/Python/wip/demo_astra_sophiabeads3D.py index edfe1b9..8c43657 100644 --- a/Wrappers/Python/wip/demo_astra_sophiabeads3D.py +++ b/Wrappers/Python/wip/demo_astra_sophiabeads3D.py @@ -11,7 +11,7 @@ from ccpi.io.reader import XTEKReader import numpy as np import matplotlib.pyplot as plt from ccpi.framework import ImageGeometry, AcquisitionData, ImageData -from ccpi.astra.ops import AstraProjector3DSimple +from ccpi.astra.operators import AstraProjector3DSimple from ccpi.optimisation.algs import CGLS import numpy diff --git a/Wrappers/Python/wip/work_out_adjoint.py b/Wrappers/Python/wip/work_out_adjoint.py index 34d58ff..276fb76 100644 --- a/Wrappers/Python/wip/work_out_adjoint.py +++ b/Wrappers/Python/wip/work_out_adjoint.py @@ -8,7 +8,7 @@ from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData from ccpi.optimisation.algs import FISTA, FBPD, CGLS from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D -from ccpi.astra.ops import AstraProjectorSimple +from ccpi.astra.operators import AstraProjectorSimple import numpy as np import matplotlib.pyplot as plt diff --git a/Wrappers/Python/wip/work_out_adjoint3D.py b/Wrappers/Python/wip/work_out_adjoint3D.py index 162e55a..0e4f847 100644 --- a/Wrappers/Python/wip/work_out_adjoint3D.py +++ b/Wrappers/Python/wip/work_out_adjoint3D.py @@ -8,7 +8,7 @@ from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData from ccpi.optimisation.algs import FISTA, FBPD, CGLS from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D -from ccpi.astra.ops import AstraProjector3DSimple +from ccpi.astra.operators import AstraProjector3DSimple import numpy as np import matplotlib.pyplot as plt diff --git a/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py b/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py index 2492826..7f35a16 100644 --- a/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py +++ b/Wrappers/Python/wip/work_out_adjoint_sophiabeads.py @@ -8,7 +8,7 @@ from ccpi.framework import ImageData , ImageGeometry, AcquisitionGeometry, AcquisitionData from ccpi.optimisation.algs import FISTA, FBPD, CGLS from ccpi.optimisation.funcs import Norm2sq, Norm1, TV2D -from ccpi.astra.ops import AstraProjectorSimple +from ccpi.astra.operators import AstraProjectorSimple import numpy as np import matplotlib.pyplot as plt -- cgit v1.2.3