diff options
Diffstat (limited to 'python/astra')
-rw-r--r-- | python/astra/PyIncludes.pxd | 6 | ||||
-rw-r--r-- | python/astra/PyIndexManager.pxd | 40 | ||||
-rw-r--r-- | python/astra/__init__.py | 9 | ||||
-rw-r--r-- | python/astra/algorithm_c.pyx | 41 | ||||
-rw-r--r-- | python/astra/astra.py | 24 | ||||
-rw-r--r-- | python/astra/astra_c.pyx | 113 | ||||
-rw-r--r-- | python/astra/creators.py | 49 | ||||
-rw-r--r-- | python/astra/data2d_c.pyx | 63 | ||||
-rw-r--r-- | python/astra/data3d.py | 2 | ||||
-rw-r--r-- | python/astra/data3d_c.pyx | 38 | ||||
-rw-r--r-- | python/astra/experimental.pyx | 86 | ||||
-rw-r--r-- | python/astra/extrautils.pyx | 37 | ||||
-rw-r--r-- | python/astra/functions.py | 2 | ||||
-rw-r--r-- | python/astra/log_c.pyx | 44 | ||||
-rw-r--r-- | python/astra/matrix_c.pyx | 36 | ||||
-rw-r--r-- | python/astra/optomo.py | 120 | ||||
-rw-r--r-- | python/astra/plugin.py | 121 | ||||
-rw-r--r-- | python/astra/plugin_c.pyx | 74 | ||||
-rw-r--r-- | python/astra/projector3d_c.pyx | 46 | ||||
-rw-r--r-- | python/astra/projector_c.pyx | 46 | ||||
-rw-r--r-- | python/astra/src/PythonPluginAlgorithm.cpp | 372 | ||||
-rw-r--r-- | python/astra/src/PythonPluginAlgorithm.h | 88 | ||||
-rw-r--r-- | python/astra/utils.pyx | 61 |
23 files changed, 1245 insertions, 273 deletions
diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd index 540aad4..61425c9 100644 --- a/python/astra/PyIncludes.pxd +++ b/python/astra/PyIncludes.pxd @@ -62,6 +62,7 @@ cdef extern from "astra/VolumeGeometry2D.h" namespace "astra": float32 getWindowMaxX() float32 getWindowMaxY() Config* getConfiguration() + bool isEqual(CVolumeGeometry2D*) cdef extern from "astra/Float32Data2D.h" namespace "astra": cdef cppclass CFloat32CustomMemory: @@ -89,6 +90,7 @@ cdef extern from "astra/ProjectionGeometry2D.h" namespace "astra": float32 getProjectionAngle(int) float32 getDetectorWidth() Config* getConfiguration() + bool isEqual(CProjectionGeometry2D*) cdef extern from "astra/Float32Data2D.h" namespace "astra::CFloat32Data2D": cdef enum TWOEDataType "astra::CFloat32Data2D::EDataType": @@ -147,7 +149,7 @@ cdef extern from "astra/Float32ProjectionData2D.h" namespace "astra": cdef extern from "astra/Algorithm.h" namespace "astra": cdef cppclass CAlgorithm: bool initialize(Config) - void run(int) + void run(int) nogil bool isInitialized() cdef extern from "astra/ReconstructionAlgorithm2D.h" namespace "astra": @@ -228,6 +230,7 @@ cdef extern from "astra/Float32VolumeData3DMemory.h" namespace "astra": int getRowCount() int getColCount() int getSliceCount() + bool isInitialized() @@ -259,6 +262,7 @@ cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra": int getDetectorColCount() int getDetectorRowCount() int getAngleCount() + bool isInitialized() cdef extern from "astra/Float32Data3D.h" namespace "astra": cdef cppclass CFloat32Data3D: diff --git a/python/astra/PyIndexManager.pxd b/python/astra/PyIndexManager.pxd new file mode 100644 index 0000000..c1ad502 --- /dev/null +++ b/python/astra/PyIndexManager.pxd @@ -0,0 +1,40 @@ +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam +# +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox +# +# This file is part of the ASTRA Toolbox. +# +# +# The ASTRA Toolbox 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. +# +# The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- + +from libcpp.string cimport string + +from .PyIncludes cimport * + +cdef extern from "astra/AstraObjectManager.h" namespace "astra": + cdef cppclass CAstraObjectManagerBase: + string getInfo(int) + void remove(int) + string getType() + cdef cppclass CAstraIndexManager: + CAstraObjectManagerBase* get(int) + +cdef extern from "astra/AstraObjectManager.h" namespace "astra::CAstraIndexManager": + cdef CAstraIndexManager* getSingletonPtr() + diff --git a/python/astra/__init__.py b/python/astra/__init__.py index 6c15d30..515d9a2 100644 --- a/python/astra/__init__.py +++ b/python/astra/__init__.py @@ -34,11 +34,12 @@ from . import algorithm from . import projector from . import projector3d from . import matrix +from . import plugin from . import log from .optomo import OpTomo import os -try: - astra.set_gpu_index(int(os.environ['ASTRA_GPU_INDEX'])) -except KeyError: - pass + +if 'ASTRA_GPU_INDEX' in os.environ: + L = [ int(x) for x in os.environ['ASTRA_GPU_INDEX'].split(',') ] + astra.set_gpu_index(L) diff --git a/python/astra/algorithm_c.pyx b/python/astra/algorithm_c.pyx index 966d3d7..4e96578 100644 --- a/python/astra/algorithm_c.pyx +++ b/python/astra/algorithm_c.pyx @@ -1,29 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- - # distutils: language = c++ # distutils: libraries = astra @@ -73,7 +72,9 @@ cdef CAlgorithm * getAlg(i) except NULL: def run(i, iterations=0): cdef CAlgorithm * alg = getAlg(i) - alg.run(iterations) + cdef int its = iterations + with nogil: + alg.run(its) def get_res_norm(i): diff --git a/python/astra/astra.py b/python/astra/astra.py index 26b1ff0..61c26ee 100644 --- a/python/astra/astra.py +++ b/python/astra/astra.py @@ -49,10 +49,30 @@ def version(printToScreen=False): """ return a.version(printToScreen) -def set_gpu_index(idx): +def set_gpu_index(idx, memory=0): """Set default GPU index to use. :param idx: GPU index :type idx: :class:`int` """ - a.set_gpu_index(idx) + a.set_gpu_index(idx, memory) + +def delete(ids): + """Delete an astra object. + + :param ids: ID or list of ID's to delete. + :type ids: :class:`int` or :class:`list` + + """ + return a.delete(ids) + +def info(ids): + """Print info about an astra object. + + :param ids: ID or list of ID's to show. + :type ids: :class:`int` or :class:`list` + + """ + return a.info(ids) + + diff --git a/python/astra/astra_c.pyx b/python/astra/astra_c.pyx index 342a214..8e30e69 100644 --- a/python/astra/astra_c.pyx +++ b/python/astra/astra_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -31,7 +31,11 @@ import six from .utils import wrap_from_bytes from libcpp.string cimport string +from libcpp.vector cimport vector from libcpp cimport bool +cimport PyIndexManager +from .PyIndexManager cimport CAstraObjectManagerBase + cdef extern from "astra/Globals.h" namespace "astra": int getVersion() string getVersionString() @@ -43,23 +47,28 @@ IF HAVE_CUDA==True: ELSE: def setGPUIndex(): pass +cdef extern from "astra/CompositeGeometryManager.h" namespace "astra": + cdef cppclass SGPUParams: + vector[int] GPUIndices + size_t memory +cdef extern from "astra/CompositeGeometryManager.h" namespace "astra::CCompositeGeometryManager": + void setGlobalGPUParams(SGPUParams&) -def credits(): - six.print_(""" -All Scale Tomographic Reconstruction Antwerp Toolbox (ASTRA-Toolbox) -was developed at the University of Antwerp by - * Prof. dr. Joost Batenburg - * Andrei Dabravolski - * Gert Merckx - * Willem Jan Palenstijn - * Tom Roelandts - * Prof. dr. Jan Sijbers - * dr. Wim van Aarle - * Sander van der Maar - * dr. Gert Van Gompel -Python interface written by - * Daniel M. Pelt (CWI, Amsterdam)""") +def credits(): + six.print_("""The ASTRA Toolbox has been developed at the University of Antwerp and CWI, Amsterdam by + * Prof. dr. Joost Batenburg + * Prof. dr. Jan Sijbers + * Dr. Jeroen Bedorf + * Dr. Folkert Bleichrodt + * Dr. Andrei Dabravolski + * Dr. Willem Jan Palenstijn + * Dr. Tom Roelandts + * Dr. Wim van Aarle + * Dr. Gert Van Gompel + * Sander van der Maar, MSc. + * Gert Merckx, MSc. + * Daan Pelt, MSc.""") def use_cuda(): @@ -72,8 +81,40 @@ def version(printToScreen=False): else: return getVersion() -def set_gpu_index(idx): +IF HAVE_CUDA==True: + def set_gpu_index(idx, memory=0): + import collections + cdef SGPUParams params if use_cuda()==True: - ret = setGPUIndex(idx) + if not isinstance(idx, collections.Iterable) or isinstance(idx, six.string_types + (six.text_type,six.binary_type)): + idx = (idx,) + params.memory = memory + params.GPUIndices = idx + setGlobalGPUParams(params) + ret = setGPUIndex(params.GPUIndices[0]) if not ret: - six.print_("Failed to set GPU " + str(idx)) + six.print_("Failed to set GPU " + str(params.GPUIndices[0])) +ELSE: + def set_gpu_index(idx, memory=0): + raise NotImplementedError("CUDA support is not enabled in ASTRA") + +def delete(ids): + import collections + cdef CAstraObjectManagerBase* ptr + if not isinstance(ids, collections.Iterable) or isinstance(ids, six.string_types + (six.text_type,six.binary_type)): + ids = (ids,) + for i in ids: + ptr = PyIndexManager.getSingletonPtr().get(i) + if ptr: + ptr.remove(i) + +def info(ids): + import collections + cdef CAstraObjectManagerBase* ptr + if not isinstance(ids, collections.Iterable) or isinstance(ids, six.string_types + (six.text_type,six.binary_type)): + ids = (ids,) + for i in ids: + ptr = PyIndexManager.getSingletonPtr().get(i) + if ptr: + s = ptr.getType() + six.b("\t") + ptr.getInfo(i) + six.print_(wrap_from_bytes(s)) diff --git a/python/astra/creators.py b/python/astra/creators.py index 4cd7f2d..82fd9d1 100644 --- a/python/astra/creators.py +++ b/python/astra/creators.py @@ -57,20 +57,24 @@ This method can be called in a number of ways: ``create_vol_geom(N)``: :returns: A 2D volume geometry of size :math:`N \\times N`. -``create_vol_geom((M, N))``: - :returns: A 2D volume geometry of size :math:`M \\times N`. +``create_vol_geom((Y, X))``: + :returns: A 2D volume geometry of size :math:`Y \\times X`. -``create_vol_geom(M, N)``: - :returns: A 2D volume geometry of size :math:`M \\times N`. +``create_vol_geom(Y, X)``: + :returns: A 2D volume geometry of size :math:`Y \\times X`. -``create_vol_geom(M, N, minx, maxx, miny, maxy)``: - :returns: A 2D volume geometry of size :math:`M \\times N`, windowed as :math:`minx \\leq x \\leq maxx` and :math:`miny \\leq y \\leq maxy`. +``create_vol_geom(Y, X, minx, maxx, miny, maxy)``: + :returns: A 2D volume geometry of size :math:`Y \\times X`, windowed as :math:`minx \\leq x \\leq maxx` and :math:`miny \\leq y \\leq maxy`. -``create_vol_geom((M, N, Z))``: - :returns: A 3D volume geometry of size :math:`M \\times N \\times Z`. +``create_vol_geom((Y, X, Z))``: + :returns: A 3D volume geometry of size :math:`Y \\times X \\times Z`. + +``create_vol_geom(Y, X, Z)``: + :returns: A 3D volume geometry of size :math:`Y \\times X \\times Z`. + +``create_vol_geom(Y, X, Z, minx, maxx, miny, maxy, minz, maxz)``: + :returns: A 3D volume geometry of size :math:`Y \\times X \\times Z`, windowed as :math:`minx \\leq x \\leq maxx` and :math:`miny \\leq y \\leq maxy` and :math:`minz \\leq z \\leq maxz` . -``create_vol_geom(M, N, Z)``: - :returns: A 3D volume geometry of size :math:`M \\times N \\times Z`. """ vol_geom = {'option': {}} @@ -122,6 +126,17 @@ This method can be called in a number of ways: vol_geom['GridRowCount'] = varargin[0] vol_geom['GridColCount'] = varargin[1] vol_geom['GridSliceCount'] = varargin[2] + # astra_create_vol_geom(row_count, col_count, slice_count, min_x, max_x, min_y, max_y, min_z, max_z) + elif len(varargin) == 9: + vol_geom['GridRowCount'] = varargin[0] + vol_geom['GridColCount'] = varargin[1] + vol_geom['GridSliceCount'] = varargin[2] + vol_geom['option']['WindowMinX'] = varargin[3] + vol_geom['option']['WindowMaxX'] = varargin[4] + vol_geom['option']['WindowMinY'] = varargin[5] + vol_geom['option']['WindowMaxY'] = varargin[6] + vol_geom['option']['WindowMinZ'] = varargin[7] + vol_geom['option']['WindowMaxZ'] = varargin[8] return vol_geom @@ -148,7 +163,7 @@ This method can be called in a number of ways: :type V: :class:`numpy.ndarray` :returns: A parallel-beam projection geometry. -``create_proj_geom('fanflat', det_width, det_count, angles, source_origin, source_det)``: +``create_proj_geom('fanflat', det_width, det_count, angles, source_origin, origin_det)``: :param det_width: Size of a detector pixel. :type det_width: :class:`float` @@ -157,7 +172,7 @@ This method can be called in a number of ways: :param angles: Array of angles in radians. :type angles: :class:`numpy.ndarray` :param source_origin: Position of the source. -:param source_det: Position of the detector +:param origin_det: Position of the detector :returns: A fan-beam projection geometry. ``create_proj_geom('fanflat_vec', det_count, V)``: @@ -180,7 +195,7 @@ This method can be called in a number of ways: :type angles: :class:`numpy.ndarray` :returns: A parallel projection geometry. -``create_proj_geom('cone', detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, source_det)``: +``create_proj_geom('cone', detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, origin_det)``: :param detector_spacing_*: Distance between two adjacent detector pixels. :type detector_spacing_*: :class:`float` @@ -192,8 +207,8 @@ This method can be called in a number of ways: :type angles: :class:`numpy.ndarray` :param source_origin: Distance between point source and origin. :type source_origin: :class:`float` -:param source_det: Distance between the detector and origin. -:type source_det: :class:`float` +:param origin_det: Distance between the detector and origin. +:type origin_det: :class:`float` :returns: A cone-beam projection geometry. ``create_proj_geom('cone_vec', det_row_count, det_col_count, V)``: @@ -242,7 +257,7 @@ This method can be called in a number of ways: return {'type':'parallel_vec', 'DetectorCount':args[0], 'Vectors':args[1]} elif intype == 'fanflat': if len(args) < 5: - raise Exception('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, source_det)') + raise Exception('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, origin_det)') return {'type': 'fanflat', 'DetectorWidth': args[0], 'DetectorCount': args[1], 'ProjectionAngles': args[2], 'DistanceOriginSource': args[3], 'DistanceOriginDetector': args[4]} elif intype == 'fanflat_vec': if len(args) < 2: @@ -256,7 +271,7 @@ This method can be called in a number of ways: return {'type':'parallel3d', 'DetectorSpacingX':args[0], 'DetectorSpacingY':args[1], 'DetectorRowCount':args[2], 'DetectorColCount':args[3],'ProjectionAngles':args[4]} elif intype == 'cone': if len(args) < 7: - raise Exception('not enough variables: astra_create_proj_geom(cone, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, source_det)') + raise Exception('not enough variables: astra_create_proj_geom(cone, detector_spacing_x, detector_spacing_y, det_row_count, det_col_count, angles, source_origin, origin_det)') return {'type': 'cone','DetectorSpacingX':args[0], 'DetectorSpacingY':args[1], 'DetectorRowCount':args[2],'DetectorColCount':args[3],'ProjectionAngles':args[4],'DistanceOriginSource': args[5],'DistanceOriginDetector':args[6]} elif intype == 'cone_vec': if len(args) < 3: diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx index 42854b3..2242d3b 100644 --- a/python/astra/data2d_c.pyx +++ b/python/astra/data2d_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -34,6 +34,9 @@ from cython cimport view cimport PyData2DManager from .PyData2DManager cimport CData2DManager +cimport PyProjector2DManager +from .PyProjector2DManager cimport CProjector2DManager + cimport PyXMLDocument from .PyXMLDocument cimport XMLDocument @@ -54,6 +57,8 @@ import operator from six.moves import reduce cdef CData2DManager * man2d = <CData2DManager * >PyData2DManager.getSingletonPtr() +cdef CProjector2DManager * manProj = <CProjector2DManager * >PyProjector2DManager.getSingletonPtr() + cdef extern from "CFloat32CustomPython.h": cdef cppclass CFloat32CustomPython: @@ -166,7 +171,6 @@ def store(i, data): cdef CFloat32Data2D * pDataObject = getObject(i) fillDataObject(pDataObject, data) - def get_geometry(i): cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 @@ -181,6 +185,27 @@ def get_geometry(i): raise Exception("Not a known data object") return geom +cdef CProjector2D * getProjector(i) except NULL: + cdef CProjector2D * proj = manProj.get(i) + if proj == NULL: + raise Exception("Projector not initialized.") + if not proj.isInitialized(): + raise Exception("Projector not initialized.") + return proj + +def check_compatible(i, proj_id): + cdef CProjector2D * proj = getProjector(proj_id) + cdef CFloat32Data2D * pDataObject = getObject(i) + cdef CFloat32ProjectionData2D * pDataObject2 + cdef CFloat32VolumeData2D * pDataObject3 + if pDataObject.getType() == TWOPROJECTION: + pDataObject2 = <CFloat32ProjectionData2D * >pDataObject + return pDataObject2.getGeometry().isEqual(proj.getProjectionGeometry()) + elif pDataObject.getType() == TWOVOLUME: + pDataObject3 = <CFloat32VolumeData2D * >pDataObject + return pDataObject3.getGeometry().isEqual(proj.getVolumeGeometry()) + else: + raise Exception("Not a known data object") def change_geometry(i, geom): cdef Config *cfg diff --git a/python/astra/data3d.py b/python/astra/data3d.py index e5ef6b0..f143659 100644 --- a/python/astra/data3d.py +++ b/python/astra/data3d.py @@ -89,7 +89,7 @@ def get_single(i): :returns: :class:`numpy.ndarray` -- The object data. """ - return g.get_single(i) + return d.get_single(i) def store(i,data): """Fill existing 3D object with data. diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx index 3b27ab7..811d1e4 100644 --- a/python/astra/data3d_c.pyx +++ b/python/astra/data3d_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -264,7 +264,7 @@ def store(i,data): def dimensions(i): cdef CFloat32Data3D * pDataObject = getObject(i) - return (pDataObject.getWidth(),pDataObject.getHeight(),pDataObject.getDepth()) + return (pDataObject.getDepth(),pDataObject.getHeight(),pDataObject.getWidth()) def delete(ids): try: diff --git a/python/astra/experimental.pyx b/python/astra/experimental.pyx new file mode 100644 index 0000000..9bb73a2 --- /dev/null +++ b/python/astra/experimental.pyx @@ -0,0 +1,86 @@ +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam +# +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox +# +# This file is part of the ASTRA Toolbox. +# +# +# The ASTRA Toolbox 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. +# +# The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- +# +# distutils: language = c++ +# distutils: libraries = astra + +include "config.pxi" + +IF HAVE_CUDA==True: + + import six + from .PyIncludes cimport * + from libcpp.vector cimport vector + + cdef extern from "astra/CompositeGeometryManager.h" namespace "astra": + cdef cppclass CCompositeGeometryManager: + bool doFP(CProjector3D *, vector[CFloat32VolumeData3DMemory *], vector[CFloat32ProjectionData3DMemory *]) + bool doBP(CProjector3D *, vector[CFloat32VolumeData3DMemory *], vector[CFloat32ProjectionData3DMemory *]) + + cdef extern from *: + CFloat32VolumeData3DMemory * dynamic_cast_vol_mem "dynamic_cast<astra::CFloat32VolumeData3DMemory*>" (CFloat32Data3D * ) except NULL + CFloat32ProjectionData3DMemory * dynamic_cast_proj_mem "dynamic_cast<astra::CFloat32ProjectionData3DMemory*>" (CFloat32Data3D * ) except NULL + + cimport PyProjector3DManager + from .PyProjector3DManager cimport CProjector3DManager + cimport PyData3DManager + from .PyData3DManager cimport CData3DManager + + cdef CProjector3DManager * manProj = <CProjector3DManager * >PyProjector3DManager.getSingletonPtr() + cdef CData3DManager * man3d = <CData3DManager * >PyData3DManager.getSingletonPtr() + + def do_composite(projector_id, vol_ids, proj_ids, t): + cdef vector[CFloat32VolumeData3DMemory *] vol + cdef CFloat32VolumeData3DMemory * pVolObject + cdef CFloat32ProjectionData3DMemory * pProjObject + for v in vol_ids: + pVolObject = dynamic_cast_vol_mem(man3d.get(v)) + if pVolObject == NULL: + raise Exception("Data object not found") + if not pVolObject.isInitialized(): + raise Exception("Data object not initialized properly") + vol.push_back(pVolObject) + cdef vector[CFloat32ProjectionData3DMemory *] proj + for v in proj_ids: + pProjObject = dynamic_cast_proj_mem(man3d.get(v)) + if pProjObject == NULL: + raise Exception("Data object not found") + if not pProjObject.isInitialized(): + raise Exception("Data object not initialized properly") + proj.push_back(pProjObject) + cdef CCompositeGeometryManager m + cdef CProjector3D * projector = manProj.get(projector_id) # may be NULL + if t == "FP": + if not m.doFP(projector, vol, proj): + raise Exception("Failed to perform FP") + else: + if not m.doBP(projector, vol, proj): + raise Exception("Failed to perform BP") + + def do_composite_FP(projector_id, vol_ids, proj_ids): + do_composite(projector_id, vol_ids, proj_ids, "FP") + + def do_composite_BP(projector_id, vol_ids, proj_ids): + do_composite(projector_id, vol_ids, proj_ids, "BP") diff --git a/python/astra/extrautils.pyx b/python/astra/extrautils.pyx index 998f5cb..2c7771e 100644 --- a/python/astra/extrautils.pyx +++ b/python/astra/extrautils.pyx @@ -1,28 +1,29 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. # -#----------------------------------------------------------------------- +# ----------------------------------------------------------------------- +# distutils: language = c++ + def clipCircle(img): cdef int i,j diff --git a/python/astra/functions.py b/python/astra/functions.py index 13ca911..9927eee 100644 --- a/python/astra/functions.py +++ b/python/astra/functions.py @@ -115,7 +115,7 @@ def add_noise_to_sino(sinogram_in, I0, seed=None): sinogram_out = -max_sinogramRaw * np.log(sinogramCT_D) if not isinstance(sinogram_in, np.ndarray): - at.data2d.store(sinogram_in, sinogram_out) + data2d.store(sinogram_in, sinogram_out) if not seed==None: np.random.set_state(curstate) diff --git a/python/astra/log_c.pyx b/python/astra/log_c.pyx index f16329f..0d187e9 100644 --- a/python/astra/log_c.pyx +++ b/python/astra/log_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -53,19 +53,19 @@ cdef extern from "astra/Logging.h" namespace "astra::CLogger": def log_debug(sfile, sline, message): cstr = list(map(six.b,(sfile,message))) - debug(cstr[0],sline,cstr[1]) + debug(cstr[0],sline,"%s",<char*>cstr[1]) def log_info(sfile, sline, message): cstr = list(map(six.b,(sfile,message))) - info(cstr[0],sline,cstr[1]) + info(cstr[0],sline,"%s",<char*>cstr[1]) def log_warn(sfile, sline, message): cstr = list(map(six.b,(sfile,message))) - warn(cstr[0],sline,cstr[1]) + warn(cstr[0],sline,"%s",<char*>cstr[1]) def log_error(sfile, sline, message): cstr = list(map(six.b,(sfile,message))) - error(cstr[0],sline,cstr[1]) + error(cstr[0],sline,"%s",<char*>cstr[1]) def log_enable(): enable() diff --git a/python/astra/matrix_c.pyx b/python/astra/matrix_c.pyx index d099a75..f5c0938 100644 --- a/python/astra/matrix_c.pyx +++ b/python/astra/matrix_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra diff --git a/python/astra/optomo.py b/python/astra/optomo.py index 2937d9c..dde719e 100644 --- a/python/astra/optomo.py +++ b/python/astra/optomo.py @@ -86,7 +86,15 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): self.proj_id = proj_id - self.T = OpTomoTranspose(self) + self.transposeOpTomo = OpTomoTranspose(self) + try: + self.T = self.transposeOpTomo + except AttributeError: + # Scipy >= 0.16 defines self.T using self._transpose() + pass + + def _transpose(self): + return self.transposeOpTomo def __checkArray(self, arr, shp): if len(arr.shape)==1: @@ -103,21 +111,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): :param v: Volume to forward project. :type v: :class:`numpy.ndarray` """ - v = self.__checkArray(v, self.vshape) - vid = self.data_mod.link('-vol',self.vg,v) - s = np.zeros(self.sshape,dtype=np.float32) - sid = self.data_mod.link('-sino',self.pg,s) - - cfg = creators.astra_dict('FP'+self.appendString) - cfg['ProjectionDataId'] = sid - cfg['VolumeDataId'] = vid - cfg['ProjectorId'] = self.proj_id - fp_id = algorithm.create(cfg) - algorithm.run(fp_id) - - algorithm.delete(fp_id) - self.data_mod.delete([vid,sid]) - return s.flatten() + return self.FP(v, out=None).ravel() def rmatvec(self,s): """Implements the transpose operator. @@ -125,21 +119,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): :param s: The projection data. :type s: :class:`numpy.ndarray` """ - s = self.__checkArray(s, self.sshape) - sid = self.data_mod.link('-sino',self.pg,s) - v = np.zeros(self.vshape,dtype=np.float32) - vid = self.data_mod.link('-vol',self.vg,v) - - cfg = creators.astra_dict('BP'+self.appendString) - cfg['ProjectionDataId'] = sid - cfg['ReconstructionDataId'] = vid - cfg['ProjectorId'] = self.proj_id - bp_id = algorithm.create(cfg) - algorithm.run(bp_id) - - algorithm.delete(bp_id) - self.data_mod.delete([vid,sid]) - return v.flatten() + return self.BP(s, out=None).ravel() def __mul__(self,v): """Provides easy forward operator by *. @@ -152,7 +132,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): return self._matvec(v) return scipy.sparse.linalg.LinearOperator.__mul__(self, v) - def reconstruct(self, method, s, iterations=1, extraOptions = {}): + def reconstruct(self, method, s, iterations=1, extraOptions = None): """Reconstruct an object. :param method: Method to use for reconstruction. @@ -164,7 +144,9 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): :param extraOptions: Extra options to use during reconstruction (i.e. for cfg['option']). :type extraOptions: :class:`dict` """ - self.__checkArray(s, self.sshape) + if extraOptions is None: + extraOptions={} + s = self.__checkArray(s, self.sshape) sid = self.data_mod.link('-sino',self.pg,s) v = np.zeros(self.vshape,dtype=np.float32) vid = self.data_mod.link('-vol',self.vg,v) @@ -179,6 +161,70 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): self.data_mod.delete([vid,sid]) return v + def FP(self,v,out=None): + """Perform forward projection. + + Output must have the right 2D/3D shape. Input may also be flattened. + + Output must also be contiguous and float32. This isn't required for the + input, but it is more efficient if it is. + + :param v: Volume to forward project. + :type v: :class:`numpy.ndarray` + :param out: Array to store result in. + :type out: :class:`numpy.ndarray` + """ + + v = self.__checkArray(v, self.vshape) + vid = self.data_mod.link('-vol',self.vg,v) + if out is None: + out = np.zeros(self.sshape,dtype=np.float32) + sid = self.data_mod.link('-sino',self.pg,out) + + cfg = creators.astra_dict('FP'+self.appendString) + cfg['ProjectionDataId'] = sid + cfg['VolumeDataId'] = vid + cfg['ProjectorId'] = self.proj_id + fp_id = algorithm.create(cfg) + algorithm.run(fp_id) + + algorithm.delete(fp_id) + self.data_mod.delete([vid,sid]) + return out + + def BP(self,s,out=None): + """Perform backprojection. + + Output must have the right 2D/3D shape. Input may also be flattened. + + Output must also be contiguous and float32. This isn't required for the + input, but it is more efficient if it is. + + :param : The projection data. + :type s: :class:`numpy.ndarray` + :param out: Array to store result in. + :type out: :class:`numpy.ndarray` + """ + s = self.__checkArray(s, self.sshape) + sid = self.data_mod.link('-sino',self.pg,s) + if out is None: + out = np.zeros(self.vshape,dtype=np.float32) + vid = self.data_mod.link('-vol',self.vg,out) + + cfg = creators.astra_dict('BP'+self.appendString) + cfg['ProjectionDataId'] = sid + cfg['ReconstructionDataId'] = vid + cfg['ProjectorId'] = self.proj_id + bp_id = algorithm.create(cfg) + algorithm.run(bp_id) + + algorithm.delete(bp_id) + self.data_mod.delete([vid,sid]) + return out + + + + class OpTomoTranspose(scipy.sparse.linalg.LinearOperator): """This object provides the transpose operation (``.T``) of the OpTomo object. @@ -189,6 +235,11 @@ class OpTomoTranspose(scipy.sparse.linalg.LinearOperator): self.parent = parent self.dtype = np.float32 self.shape = (parent.shape[1], parent.shape[0]) + try: + self.T = self.parent + except AttributeError: + # Scipy >= 0.16 defines self.T using self._transpose() + pass def _matvec(self, s): return self.parent.rmatvec(s) @@ -196,6 +247,9 @@ class OpTomoTranspose(scipy.sparse.linalg.LinearOperator): def rmatvec(self, v): return self.parent.matvec(v) + def _transpose(self): + return self.parent + def __mul__(self,s): # Catch the case of a backprojection of 2D/3D data if isinstance(s, np.ndarray) and s.shape==self.parent.sshape: diff --git a/python/astra/plugin.py b/python/astra/plugin.py new file mode 100644 index 0000000..3e3528d --- /dev/null +++ b/python/astra/plugin.py @@ -0,0 +1,121 @@ +#----------------------------------------------------------------------- +#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# +#Author: Daniel M. Pelt +#Contact: D.M.Pelt@cwi.nl +#Website: http://dmpelt.github.io/pyastratoolbox/ +# +# +#This file is part of the Python interface to the +#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). +# +#The Python interface to the ASTRA Toolbox 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. +# +#The Python interface to the ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +#----------------------------------------------------------------------- + +from . import plugin_c as p +from . import log +from . import data2d +from . import data2d_c +from . import data3d +from . import projector +import inspect +import traceback + +class base(object): + + def astra_init(self, cfg): + args, varargs, varkw, defaults = inspect.getargspec(self.initialize) + if not defaults is None: + nopt = len(defaults) + else: + nopt = 0 + if nopt>0: + req = args[2:-nopt] + opt = args[-nopt:] + else: + req = args[2:] + opt = [] + + try: + optDict = cfg['options'] + except KeyError: + optDict = {} + + cfgKeys = set(optDict.keys()) + reqKeys = set(req) + optKeys = set(opt) + + if not reqKeys.issubset(cfgKeys): + for key in reqKeys.difference(cfgKeys): + log.error("Required option '" + key + "' for plugin '" + self.__class__.__name__ + "' not specified") + raise ValueError("Missing required options") + + if not cfgKeys.issubset(reqKeys | optKeys): + log.warn(self.__class__.__name__ + ": unused configuration option: " + str(list(cfgKeys.difference(reqKeys | optKeys)))) + + args = [optDict[k] for k in req] + kwargs = dict((k,optDict[k]) for k in opt if k in optDict) + self.initialize(cfg, *args, **kwargs) + +class ReconstructionAlgorithm2D(base): + + def astra_init(self, cfg): + self.pid = cfg['ProjectorId'] + self.s = data2d.get_shared(cfg['ProjectionDataId']) + self.v = data2d.get_shared(cfg['ReconstructionDataId']) + self.vg = projector.volume_geometry(self.pid) + self.pg = projector.projection_geometry(self.pid) + if not data2d_c.check_compatible(cfg['ProjectionDataId'], self.pid): + raise ValueError("Projection data and projector not compatible") + if not data2d_c.check_compatible(cfg['ReconstructionDataId'], self.pid): + raise ValueError("Reconstruction data and projector not compatible") + super(ReconstructionAlgorithm2D,self).astra_init(cfg) + +class ReconstructionAlgorithm3D(base): + + def astra_init(self, cfg): + self.pid = cfg['ProjectorId'] + self.s = data3d.get_shared(cfg['ProjectionDataId']) + self.v = data3d.get_shared(cfg['ReconstructionDataId']) + self.vg = data3d.get_geometry(cfg['ReconstructionDataId']) + self.pg = data3d.get_geometry(cfg['ProjectionDataId']) + super(ReconstructionAlgorithm3D,self).astra_init(cfg) + +def register(className): + """Register plugin with ASTRA. + + :param className: Class name or class object to register + :type className: :class:`str` or :class:`class` + + """ + p.register(className) + +def get_registered(): + """Get dictionary of registered plugins. + + :returns: :class:`dict` -- Registered plugins. + + """ + return p.get_registered() + +def get_help(name): + """Get help for registered plugin. + + :param name: Plugin name to get help for + :type name: :class:`str` + :returns: :class:`str` -- Help string (docstring). + + """ + return p.get_help(name)
\ No newline at end of file diff --git a/python/astra/plugin_c.pyx b/python/astra/plugin_c.pyx new file mode 100644 index 0000000..ee04853 --- /dev/null +++ b/python/astra/plugin_c.pyx @@ -0,0 +1,74 @@ +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam +# +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox +# +# This file is part of the ASTRA Toolbox. +# +# +# The ASTRA Toolbox 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. +# +# The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- +# +# distutils: language = c++ +# distutils: libraries = astra + +import six +import inspect + +from libcpp.string cimport string +from libcpp cimport bool + +cdef CPythonPluginAlgorithmFactory *fact = getSingletonPtr() + +from . import utils + +cdef extern from "src/PythonPluginAlgorithm.h" namespace "astra": + cdef cppclass CPythonPluginAlgorithmFactory: + bool registerPlugin(string className) + bool registerPlugin(string name, string className) + bool registerPluginClass(object className) + bool registerPluginClass(string name, object className) + object getRegistered() + string getHelp(string &name) + +cdef extern from "src/PythonPluginAlgorithm.h" namespace "astra::CPythonPluginAlgorithmFactory": + cdef CPythonPluginAlgorithmFactory* getSingletonPtr() + +cdef extern from "astra/PluginAlgorithm.h" namespace "astra::CPluginAlgorithmFactory": + # NB: Using wrong pointer type here for convenience + cdef void registerFactory(CPythonPluginAlgorithmFactory *) + +def register(className, name=None): + if inspect.isclass(className): + if name==None: + fact.registerPluginClass(className) + else: + fact.registerPluginClass(six.b(name), className) + else: + if name==None: + fact.registerPlugin(six.b(className)) + else: + fact.registerPlugin(six.b(name), six.b(className)) + +def get_registered(): + return fact.getRegistered() + +def get_help(name): + return utils.wrap_from_bytes(fact.getHelp(six.b(name))) + +# Register python plugin factory with astra +registerFactory(fact) diff --git a/python/astra/projector3d_c.pyx b/python/astra/projector3d_c.pyx index 8b978d7..e355e38 100644 --- a/python/astra/projector3d_c.pyx +++ b/python/astra/projector3d_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -87,12 +87,18 @@ cdef CProjector3D * getObject(i) except NULL: def projection_geometry(i): cdef CProjector3D * proj = getObject(i) - return utils.configToDict(proj.getProjectionGeometry().getConfiguration()) + cdef Config * cfg = proj.getProjectionGeometry().getConfiguration() + dct = utils.configToDict(cfg) + del cfg + return dct def volume_geometry(i): cdef CProjector3D * proj = getObject(i) - return utils.configToDict(proj.getVolumeGeometry().getConfiguration()) + cdef Config * cfg = proj.getVolumeGeometry().getConfiguration() + dct = utils.configToDict(cfg) + del cfg + return dct def weights_single_ray(i, projection_index, detector_index): diff --git a/python/astra/projector_c.pyx b/python/astra/projector_c.pyx index 9aa868e..53d38c3 100644 --- a/python/astra/projector_c.pyx +++ b/python/astra/projector_c.pyx @@ -1,28 +1,28 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra @@ -91,12 +91,18 @@ cdef CProjector2D * getObject(i) except NULL: def projection_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.configToDict(proj.getProjectionGeometry().getConfiguration()) + cdef Config * cfg = proj.getProjectionGeometry().getConfiguration() + dct = utils.configToDict(cfg) + del cfg + return dct def volume_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.configToDict(proj.getVolumeGeometry().getConfiguration()) + cdef Config * cfg = proj.getVolumeGeometry().getConfiguration() + dct = utils.configToDict(cfg) + del cfg + return dct def weights_single_ray(i, projection_index, detector_index): diff --git a/python/astra/src/PythonPluginAlgorithm.cpp b/python/astra/src/PythonPluginAlgorithm.cpp new file mode 100644 index 0000000..617c0f4 --- /dev/null +++ b/python/astra/src/PythonPluginAlgorithm.cpp @@ -0,0 +1,372 @@ +/* +----------------------------------------------------------------------- +Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp + 2014-2016, CWI, Amsterdam + +Contact: astra@uantwerpen.be +Website: http://sf.net/projects/astra-toolbox + +This file is part of the ASTRA Toolbox. + + +The ASTRA Toolbox 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. + +The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +*/ + +#ifdef ASTRA_PYTHON + +#include "PythonPluginAlgorithm.h" + +#include "astra/Logging.h" +#include "astra/Utilities.h" +#include <boost/algorithm/string.hpp> +#include <boost/algorithm/string/split.hpp> +#include <iostream> +#include <fstream> +#include <string> + +#include <Python.h> +#include "bytesobject.h" + +namespace astra { + + + +void logPythonError(){ + if(PyErr_Occurred()){ + PyObject *ptype, *pvalue, *ptraceback; + PyErr_Fetch(&ptype, &pvalue, &ptraceback); + PyErr_NormalizeException(&ptype, &pvalue, &ptraceback); + PyObject *traceback = PyImport_ImportModule("traceback"); + if(traceback!=NULL){ + PyObject *exc; + if(ptraceback==NULL){ + exc = PyObject_CallMethod(traceback,"format_exception_only","OO",ptype, pvalue); + }else{ + exc = PyObject_CallMethod(traceback,"format_exception","OOO",ptype, pvalue, ptraceback); + } + if(exc!=NULL){ + PyObject *six = PyImport_ImportModule("six"); + if(six!=NULL){ + PyObject *iter = PyObject_GetIter(exc); + if(iter!=NULL){ + PyObject *line; + std::string errStr = ""; + while(line = PyIter_Next(iter)){ + PyObject *retb = PyObject_CallMethod(six,"b","O",line); + if(retb!=NULL){ + errStr += std::string(PyBytes_AsString(retb)); + Py_DECREF(retb); + } + Py_DECREF(line); + } + ASTRA_ERROR("%s",errStr.c_str()); + Py_DECREF(iter); + } + Py_DECREF(six); + } + Py_DECREF(exc); + } + Py_DECREF(traceback); + } + if(ptype!=NULL) Py_DECREF(ptype); + if(pvalue!=NULL) Py_DECREF(pvalue); + if(ptraceback!=NULL) Py_DECREF(ptraceback); + } +} + + +CPluginAlgorithm::CPluginAlgorithm(PyObject* pyclass){ + instance = PyObject_CallObject(pyclass, NULL); + if(instance==NULL) logPythonError(); +} + +CPluginAlgorithm::~CPluginAlgorithm(){ + if(instance!=NULL){ + Py_DECREF(instance); + instance = NULL; + } +} + +bool CPluginAlgorithm::initialize(const Config& _cfg){ + if(instance==NULL) return false; + PyObject *cfgDict = XMLNode2dict(_cfg.self); + PyObject *retVal = PyObject_CallMethod(instance, "astra_init", "O",cfgDict); + Py_DECREF(cfgDict); + if(retVal==NULL){ + logPythonError(); + return false; + } + m_bIsInitialized = true; + Py_DECREF(retVal); + return m_bIsInitialized; +} + +void CPluginAlgorithm::run(int _iNrIterations){ + if(instance==NULL) return; + PyGILState_STATE state = PyGILState_Ensure(); + PyObject *retVal = PyObject_CallMethod(instance, "run", "i",_iNrIterations); + if(retVal==NULL){ + logPythonError(); + }else{ + Py_DECREF(retVal); + } + PyGILState_Release(state); +} + +CPythonPluginAlgorithmFactory::CPythonPluginAlgorithmFactory(){ + if(!Py_IsInitialized()){ + Py_Initialize(); + PyEval_InitThreads(); + } + pluginDict = PyDict_New(); + inspect = PyImport_ImportModule("inspect"); + six = PyImport_ImportModule("six"); +} + +CPythonPluginAlgorithmFactory::~CPythonPluginAlgorithmFactory(){ + if(pluginDict!=NULL){ + Py_DECREF(pluginDict); + } + if(inspect!=NULL) Py_DECREF(inspect); + if(six!=NULL) Py_DECREF(six); +} + +PyObject * getClassFromString(std::string str){ + std::vector<std::string> items; + boost::split(items, str, boost::is_any_of(".")); + PyObject *pyclass = PyImport_ImportModule(items[0].c_str()); + if(pyclass==NULL){ + logPythonError(); + return NULL; + } + PyObject *submod = pyclass; + for(unsigned int i=1;i<items.size();i++){ + submod = PyObject_GetAttrString(submod,items[i].c_str()); + Py_DECREF(pyclass); + pyclass = submod; + if(pyclass==NULL){ + logPythonError(); + return NULL; + } + } + return pyclass; +} + +bool CPythonPluginAlgorithmFactory::registerPlugin(std::string name, std::string className){ + PyObject *str = PyBytes_FromString(className.c_str()); + PyDict_SetItemString(pluginDict, name.c_str(), str); + Py_DECREF(str); + return true; +} + +bool CPythonPluginAlgorithmFactory::registerPlugin(std::string className){ + PyObject *pyclass = getClassFromString(className); + if(pyclass==NULL) return false; + bool ret = registerPluginClass(pyclass); + Py_DECREF(pyclass); + return ret; +} + +bool CPythonPluginAlgorithmFactory::registerPluginClass(std::string name, PyObject * className){ + PyDict_SetItemString(pluginDict, name.c_str(), className); + return true; +} + +bool CPythonPluginAlgorithmFactory::registerPluginClass(PyObject * className){ + PyObject *astra_name = PyObject_GetAttrString(className,"astra_name"); + if(astra_name==NULL){ + logPythonError(); + return false; + } + PyObject *retb = PyObject_CallMethod(six,"b","O",astra_name); + if(retb!=NULL){ + PyDict_SetItemString(pluginDict,PyBytes_AsString(retb),className); + Py_DECREF(retb); + }else{ + logPythonError(); + } + Py_DECREF(astra_name); + return true; +} + +CAlgorithm * CPythonPluginAlgorithmFactory::getPlugin(const std::string &name){ + PyObject *className = PyDict_GetItemString(pluginDict, name.c_str()); + if(className==NULL) return NULL; + CPluginAlgorithm *alg = NULL; + if(PyBytes_Check(className)){ + std::string str = std::string(PyBytes_AsString(className)); + PyObject *pyclass = getClassFromString(str); + if(pyclass!=NULL){ + alg = new CPluginAlgorithm(pyclass); + Py_DECREF(pyclass); + } + }else{ + alg = new CPluginAlgorithm(className); + } + return alg; +} + +PyObject * CPythonPluginAlgorithmFactory::getRegistered(){ + Py_INCREF(pluginDict); + return pluginDict; +} + +std::map<std::string, std::string> CPythonPluginAlgorithmFactory::getRegisteredMap(){ + std::map<std::string, std::string> ret; + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(pluginDict, &pos, &key, &value)) { + PyObject *keystr = PyObject_Str(key); + if(keystr!=NULL){ + PyObject *valstr = PyObject_Str(value); + if(valstr!=NULL){ + PyObject * keyb = PyObject_CallMethod(six,"b","O",keystr); + if(keyb!=NULL){ + PyObject * valb = PyObject_CallMethod(six,"b","O",valstr); + if(valb!=NULL){ + ret[PyBytes_AsString(keyb)] = PyBytes_AsString(valb); + Py_DECREF(valb); + } + Py_DECREF(keyb); + } + Py_DECREF(valstr); + } + Py_DECREF(keystr); + } + logPythonError(); + } + return ret; +} + +std::string CPythonPluginAlgorithmFactory::getHelp(const std::string &name){ + PyObject *className = PyDict_GetItemString(pluginDict, name.c_str()); + if(className==NULL){ + ASTRA_ERROR("Plugin %s not found!",name.c_str()); + PyErr_Clear(); + return ""; + } + std::string ret = ""; + PyObject *pyclass; + if(PyBytes_Check(className)){ + std::string str = std::string(PyBytes_AsString(className)); + pyclass = getClassFromString(str); + }else{ + pyclass = className; + } + if(pyclass==NULL) return ""; + if(inspect!=NULL && six!=NULL){ + PyObject *retVal = PyObject_CallMethod(inspect,"getdoc","O",pyclass); + if(retVal!=NULL){ + if(retVal!=Py_None){ + PyObject *retb = PyObject_CallMethod(six,"b","O",retVal); + if(retb!=NULL){ + ret = std::string(PyBytes_AsString(retb)); + Py_DECREF(retb); + } + } + Py_DECREF(retVal); + }else{ + logPythonError(); + } + } + if(PyBytes_Check(className)){ + Py_DECREF(pyclass); + } + return ret; +} + +DEFINE_SINGLETON(CPythonPluginAlgorithmFactory); + +#if PY_MAJOR_VERSION >= 3 +PyObject * pyStringFromString(std::string str){ + return PyUnicode_FromString(str.c_str()); +} +#else +PyObject * pyStringFromString(std::string str){ + return PyBytes_FromString(str.c_str()); +} +#endif + +PyObject* stringToPythonValue(std::string str){ + if(str.find(";")!=std::string::npos){ + std::vector<std::string> rows, row; + boost::split(rows, str, boost::is_any_of(";")); + PyObject *mat = PyList_New(rows.size()); + for(unsigned int i=0; i<rows.size(); i++){ + boost::split(row, rows[i], boost::is_any_of(",")); + PyObject *rowlist = PyList_New(row.size()); + for(unsigned int j=0;j<row.size();j++){ + PyList_SetItem(rowlist, j, PyFloat_FromDouble(StringUtil::stringToDouble(row[j]))); + } + PyList_SetItem(mat, i, rowlist); + } + return mat; + } + if(str.find(",")!=std::string::npos){ + std::vector<std::string> vec; + boost::split(vec, str, boost::is_any_of(",")); + PyObject *veclist = PyList_New(vec.size()); + for(unsigned int i=0;i<vec.size();i++){ + PyList_SetItem(veclist, i, PyFloat_FromDouble(StringUtil::stringToDouble(vec[i]))); + } + return veclist; + } + try{ + return PyLong_FromLong(StringUtil::stringToInt(str)); + }catch(const StringUtil::bad_cast &){ + try{ + return PyFloat_FromDouble(StringUtil::stringToDouble(str)); + }catch(const StringUtil::bad_cast &){ + return pyStringFromString(str); + } + } +} + +PyObject* XMLNode2dict(XMLNode node){ + PyObject *dct = PyDict_New(); + PyObject *opts = PyDict_New(); + if(node.hasAttribute("type")){ + PyObject *obj = pyStringFromString(node.getAttribute("type").c_str()); + PyDict_SetItemString(dct, "type", obj); + Py_DECREF(obj); + } + std::list<XMLNode> nodes = node.getNodes(); + std::list<XMLNode>::iterator it = nodes.begin(); + while(it!=nodes.end()){ + XMLNode subnode = *it; + if(subnode.getName()=="Option"){ + PyObject *obj; + if(subnode.hasAttribute("value")){ + obj = stringToPythonValue(subnode.getAttribute("value")); + }else{ + obj = stringToPythonValue(subnode.getContent()); + } + PyDict_SetItemString(opts, subnode.getAttribute("key").c_str(), obj); + Py_DECREF(obj); + }else{ + PyObject *obj = stringToPythonValue(subnode.getContent()); + PyDict_SetItemString(dct, subnode.getName().c_str(), obj); + Py_DECREF(obj); + } + ++it; + } + PyDict_SetItemString(dct, "options", opts); + Py_DECREF(opts); + return dct; +} + +} +#endif diff --git a/python/astra/src/PythonPluginAlgorithm.h b/python/astra/src/PythonPluginAlgorithm.h new file mode 100644 index 0000000..ea4c6fb --- /dev/null +++ b/python/astra/src/PythonPluginAlgorithm.h @@ -0,0 +1,88 @@ +/* +----------------------------------------------------------------------- +Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp + 2014-2016, CWI, Amsterdam + +Contact: astra@uantwerpen.be +Website: http://sf.net/projects/astra-toolbox + +This file is part of the ASTRA Toolbox. + + +The ASTRA Toolbox 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. + +The ASTRA Toolbox 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 the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. + +----------------------------------------------------------------------- +*/ + +#ifndef _INC_PYTHONPLUGINALGORITHM +#define _INC_PYTHONPLUGINALGORITHM + +#ifdef ASTRA_PYTHON + +#include "astra/Algorithm.h" +#include "astra/Singleton.h" +#include "astra/XMLDocument.h" +#include "astra/XMLNode.h" +#include "astra/PluginAlgorithm.h" + +#include <Python.h> + +namespace astra { +class CPluginAlgorithm : public CAlgorithm { + +public: + + CPluginAlgorithm(PyObject* pyclass); + ~CPluginAlgorithm(); + + bool initialize(const Config& _cfg); + void run(int _iNrIterations); + +private: + PyObject * instance; + +}; + +class CPythonPluginAlgorithmFactory : public CPluginAlgorithmFactory, public Singleton<CPythonPluginAlgorithmFactory> { + +public: + + CPythonPluginAlgorithmFactory(); + virtual ~CPythonPluginAlgorithmFactory(); + + virtual CAlgorithm * getPlugin(const std::string &name); + + virtual bool registerPlugin(std::string name, std::string className); + virtual bool registerPlugin(std::string className); + bool registerPluginClass(std::string name, PyObject * className); + bool registerPluginClass(PyObject * className); + + PyObject * getRegistered(); + virtual std::map<std::string, std::string> getRegisteredMap(); + + virtual std::string getHelp(const std::string &name); + +private: + PyObject * pluginDict; + PyObject *inspect, *six; +}; + +PyObject* XMLNode2dict(XMLNode node); + +} + + +#endif + +#endif diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index ddb37aa..34d1902 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.pyx @@ -1,37 +1,41 @@ -#----------------------------------------------------------------------- -#Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # -#Author: Daniel M. Pelt -#Contact: D.M.Pelt@cwi.nl -#Website: http://dmpelt.github.io/pyastratoolbox/ +# Contact: astra@uantwerpen.be +# Website: http://sf.net/projects/astra-toolbox # +# This file is part of the ASTRA Toolbox. # -#This file is part of the Python interface to the -#All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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. # -#The Python interface to the ASTRA Toolbox 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. +# The ASTRA Toolbox 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 the Python interface to the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# You should have received a copy of the GNU General Public License +# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. +# +# ----------------------------------------------------------------------- # -#----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra cimport numpy as np import numpy as np import six +if six.PY3: + import builtins +else: + import __builtin__ as builtins from libcpp.string cimport string -from libcpp.list cimport list from libcpp.vector cimport vector +from libcpp.list cimport list from cython.operator cimport dereference as deref, preincrement as inc from cpython.version cimport PY_MAJOR_VERSION @@ -91,11 +95,14 @@ cdef void readDict(XMLNode root, _dc): dc = convert_item(_dc) for item in dc: val = dc[item] + if isinstance(val, builtins.list) or isinstance(val, tuple): + val = np.array(val,dtype=np.float64) if isinstance(val, np.ndarray): if val.size == 0: break listbase = root.addChildNode(item) - data = <double*>np.PyArray_DATA(np.ascontiguousarray(val,dtype=np.float64)) + contig_data = np.ascontiguousarray(val,dtype=np.float64) + data = <double*>np.PyArray_DATA(contig_data) if val.ndim == 2: listbase.setContent(data, val.shape[1], val.shape[0], False) elif val.ndim == 1: @@ -112,6 +119,8 @@ cdef void readDict(XMLNode root, _dc): if item == six.b('type'): root.addAttribute(< string > six.b('type'), <string> wrap_to_bytes(val)) else: + if isinstance(val, builtins.bool): + val = int(val) itm = root.addChildNode(item, wrap_to_bytes(val)) cdef void readOptions(XMLNode node, dc): @@ -124,12 +133,15 @@ cdef void readOptions(XMLNode node, dc): val = dc[item] if node.hasOption(item): raise Exception('Duplicate Option: %s' % item) + if isinstance(val, builtins.list) or isinstance(val, tuple): + val = np.array(val,dtype=np.float64) if isinstance(val, np.ndarray): if val.size == 0: break listbase = node.addChildNode(six.b('Option')) listbase.addAttribute(< string > six.b('key'), < string > item) - data = <double*>np.PyArray_DATA(np.ascontiguousarray(val,dtype=np.float64)) + contig_data = np.ascontiguousarray(val,dtype=np.float64) + data = <double*>np.PyArray_DATA(contig_data) if val.ndim == 2: listbase.setContent(data, val.shape[1], val.shape[0], False) elif val.ndim == 1: @@ -137,6 +149,8 @@ cdef void readOptions(XMLNode node, dc): else: raise Exception("Only 1 or 2 dimensions are allowed") else: + if isinstance(val, builtins.bool): + val = int(val) node.addOption(item, wrap_to_bytes(val)) cdef configToDict(Config *cfg): @@ -202,7 +216,10 @@ cdef XMLNode2dict(XMLNode node): while it != nodes.end(): subnode = deref(it) if castString(subnode.getName())=="Option": - opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getAttribute('value')) + if subnode.hasAttribute('value'): + opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getAttribute('value')) + else: + opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getContent()) else: dct[castString(subnode.getName())] = stringToPythonValue(subnode.getContent()) inc(it) |