diff options
author | Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl> | 2016-03-01 14:47:43 +0100 |
---|---|---|
committer | Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl> | 2016-03-01 14:47:43 +0100 |
commit | 0db21a84dd3cb0f6a78bd462a4a60a4b4a3c6fae (patch) | |
tree | a833d4787504e8612282a82c60d3984be51bdffe | |
parent | da11f9e7c7559eb01cc422ac55c9f7a1cd4bb803 (diff) | |
parent | b74e64aef7845666d27cbf7e876a6a360eefed7f (diff) | |
download | astra-0db21a84dd3cb0f6a78bd462a4a60a4b4a3c6fae.tar.gz astra-0db21a84dd3cb0f6a78bd462a4a60a4b4a3c6fae.tar.bz2 astra-0db21a84dd3cb0f6a78bd462a4a60a4b4a3c6fae.tar.xz astra-0db21a84dd3cb0f6a78bd462a4a60a4b4a3c6fae.zip |
Merge branch 'master' into indexmanager
25 files changed, 1097 insertions, 677 deletions
diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in index 3018674..9535b4c 100644 --- a/build/linux/Makefile.in +++ b/build/linux/Makefile.in @@ -62,8 +62,6 @@ PYCPPFLAGS := $(CPPFLAGS) PYCPPFLAGS += -I../include PYLDFLAGS = $(LDFLAGS) PYLDFLAGS += -L$(abs_top_builddir)/.libs -LIBS += -l$(PYLIBVER) -LDFLAGS += -L$(PYLIBDIR) endif # This is below where PYCPPFLAGS copies CPPFLAGS. The python code is built @@ -97,6 +95,11 @@ ifeq ($(cuda),yes) MEXFLAGS += -DASTRA_CUDA endif +ifeq ($(python),yes) +MEXPYLDFLAGS='$$LDFLAGS $(LDFLAGS) -L$(PYLIBDIR)' +MEXPYLIBS=$(MEXLIBS) -l$(PYLIBVER) +endif + endif LIBDIR=/usr/local/lib @@ -267,6 +270,11 @@ mex: $(MATLAB_MEX) %.$(MEXSUFFIX): %.o $(MATLAB_CXX_OBJECTS) libastra.la $(MEX) LDFLAGS=$(MEXLDFLAGS) $(MEXFLAGS) $(LIBS) $(MEXLIBS) -lastra -output $* $*.o $(MATLAB_CXX_OBJECTS) + +ifeq ($(python),yes) +matlab/mex/astra_mex_plugin_c.$(MEXSUFFIX): matlab/mex/astra_mex_plugin_c.o $(MATLAB_CXX_OBJECTS) libastra.la + $(MEX) LDFLAGS=$(MEXPYLDFLAGS) $(MEXFLAGS) $(LIBS) $(MEXPYLIBS) -lastra -output matlab/mex/astra_mex_plugin_c $< $(MATLAB_CXX_OBJECTS) +endif endif ifeq ($(python),yes) @@ -411,7 +419,7 @@ $(srcdir)/configure: $(srcdir)/configure.ac @echo "configure.ac has been changed. Regenerating configure script" cd $(srcdir) && $(SHELL) ./autogen.sh -.PHONY: all mex test clean distclean install install-libraries +.PHONY: all mex test clean distclean install install-libraries py python-root-install install-python # don't remove intermediate files: .SECONDARY: diff --git a/cuda/3d/mem3d.cu b/cuda/3d/mem3d.cu index 6d81dc0..0320117 100644 --- a/cuda/3d/mem3d.cu +++ b/cuda/3d/mem3d.cu @@ -62,6 +62,25 @@ size_t availableGPUMemory() return free; } +int maxBlockDimension() +{ + int dev; + cudaError_t err = cudaGetDevice(&dev); + if (err != cudaSuccess) { + ASTRA_WARN("Error querying device"); + return 0; + } + + cudaDeviceProp props; + err = cudaGetDeviceProperties(&props, dev); + if (err != cudaSuccess) { + ASTRA_WARN("Error querying device %d properties", dev); + return 0; + } + + return std::min(props.maxTexture3D[0], std::min(props.maxTexture3D[1], props.maxTexture3D[2])); +} + MemHandle3D allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, Mem3DZeroMode zero) { SMemHandle3D_internal hnd; diff --git a/cuda/3d/mem3d.h b/cuda/3d/mem3d.h index acb72cb..6fff80b 100644 --- a/cuda/3d/mem3d.h +++ b/cuda/3d/mem3d.h @@ -78,6 +78,7 @@ enum Mem3DZeroMode { }; size_t availableGPUMemory(); +int maxBlockDimension(); MemHandle3D allocateGPUMemory(unsigned int x, unsigned int y, unsigned int z, Mem3DZeroMode zero); diff --git a/include/astra/AstraObjectFactory.h b/include/astra/AstraObjectFactory.h index 325989e..6af9cd8 100644 --- a/include/astra/AstraObjectFactory.h +++ b/include/astra/AstraObjectFactory.h @@ -155,8 +155,11 @@ class _AstraExport CAlgorithmFactory : public CAstraObjectFactory<CAlgorithm, Al template <> inline CAlgorithm* CAstraObjectFactory<CAlgorithm, AlgorithmTypeList>::findPlugin(std::string _sType) { - CPluginAlgorithmFactory *fac = CPluginAlgorithmFactory::getSingletonPtr(); - return fac->getPlugin(_sType); + CPluginAlgorithmFactory *fac = CPluginAlgorithmFactory::getFactory(); + if (fac) + return fac->getPlugin(_sType); + else + return 0; } #endif diff --git a/include/astra/CompositeGeometryManager.h b/include/astra/CompositeGeometryManager.h index 4338994..18dd72f 100644 --- a/include/astra/CompositeGeometryManager.h +++ b/include/astra/CompositeGeometryManager.h @@ -79,7 +79,9 @@ public: bool uploadToGPU(); bool downloadFromGPU(/*mode?*/); - virtual TPartList split(size_t maxSize, int div) = 0; + virtual void splitX(TPartList& out, size_t maxSize, size_t maxDim, int div) = 0; + virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div) = 0; + virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div) = 0; virtual CPart* reduce(const CPart *other) = 0; virtual void getDims(size_t &x, size_t &y, size_t &z) = 0; size_t getSize(); @@ -93,7 +95,9 @@ public: CVolumeGeometry3D* pGeom; - virtual TPartList split(size_t maxSize, int div); + virtual void splitX(TPartList& out, size_t maxSize, size_t maxDim, int div); + virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div); + virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div); virtual CPart* reduce(const CPart *other); virtual void getDims(size_t &x, size_t &y, size_t &z); @@ -107,7 +111,9 @@ public: CProjectionGeometry3D* pGeom; - virtual TPartList split(size_t maxSize, int div); + virtual void splitX(TPartList& out, size_t maxSize, size_t maxDim, int div); + virtual void splitY(TPartList& out, size_t maxSize, size_t maxDim, int div); + virtual void splitZ(TPartList& out, size_t maxSize, size_t maxDim, int div); virtual CPart* reduce(const CPart *other); virtual void getDims(size_t &x, size_t &y, size_t &z); diff --git a/include/astra/PluginAlgorithm.h b/include/astra/PluginAlgorithm.h index 667e813..cbd80fc 100644 --- a/include/astra/PluginAlgorithm.h +++ b/include/astra/PluginAlgorithm.h @@ -29,62 +29,37 @@ $Id$ #ifndef _INC_ASTRA_PLUGINALGORITHM #define _INC_ASTRA_PLUGINALGORITHM -#ifdef ASTRA_PYTHON - -#include "astra/Algorithm.h" -#include "astra/Singleton.h" -#include "astra/XMLDocument.h" -#include "astra/XMLNode.h" - -// Slightly hackish forward declaration of PyObject -struct _object; -typedef _object PyObject; +#include "astra/Globals.h" +#include <map> +#include <string> namespace astra { -class _AstraExport CPluginAlgorithm : public CAlgorithm { - -public: - - CPluginAlgorithm(PyObject* pyclass); - ~CPluginAlgorithm(); - - bool initialize(const Config& _cfg); - void run(int _iNrIterations); - -private: - PyObject * instance; -}; +class CAlgorithm; -class _AstraExport CPluginAlgorithmFactory : public Singleton<CPluginAlgorithmFactory> { +class _AstraExport CPluginAlgorithmFactory { public: + CPluginAlgorithmFactory() { } + virtual ~CPluginAlgorithmFactory() { } - CPluginAlgorithmFactory(); - ~CPluginAlgorithmFactory(); + virtual CAlgorithm * getPlugin(const std::string &name) = 0; - CPluginAlgorithm * getPlugin(std::string name); + virtual bool registerPlugin(std::string name, std::string className) = 0; + virtual bool registerPlugin(std::string className) = 0; - bool registerPlugin(std::string name, std::string className); - bool registerPlugin(std::string className); - bool registerPluginClass(std::string name, PyObject * className); - bool registerPluginClass(PyObject * className); + virtual std::map<std::string, std::string> getRegisteredMap() = 0; - PyObject * getRegistered(); - std::map<std::string, std::string> getRegisteredMap(); - - std::string getHelp(std::string name); + virtual std::string getHelp(const std::string &name) = 0; + + static void registerFactory(CPluginAlgorithmFactory *factory) { m_factory = factory; } + static CPluginAlgorithmFactory* getFactory() { return m_factory; } private: - PyObject * pluginDict; - PyObject *inspect, *six; + static CPluginAlgorithmFactory *m_factory; }; -PyObject* XMLNode2dict(XMLNode node); - } #endif - -#endif diff --git a/matlab/mex/astra_mex_plugin_c.cpp b/matlab/mex/astra_mex_plugin_c.cpp index 177fcf4..4ed534e 100644 --- a/matlab/mex/astra_mex_plugin_c.cpp +++ b/matlab/mex/astra_mex_plugin_c.cpp @@ -37,9 +37,63 @@ $Id$ #include "astra/PluginAlgorithm.h" +#include <Python.h> + using namespace std; using namespace astra; +static void fixLapackLoading() +{ + // When running in Matlab, we need to force numpy + // to use its internal lapack library instead of + // Matlab's MKL library to avoid errors. To do this, + // we set Python's dlopen flags to RTLD_NOW|RTLD_DEEPBIND + // and import 'numpy.linalg.lapack_lite' here. We reset + // Python's dlopen flags afterwards. + PyObject *sys = PyImport_ImportModule("sys"); + if (sys != NULL) { + PyObject *curFlags = PyObject_CallMethod(sys, "getdlopenflags", NULL); + if (curFlags != NULL) { + PyObject *retVal = PyObject_CallMethod(sys, "setdlopenflags", "i", 10); // RTLD_NOW|RTLD_DEEPBIND + if (retVal != NULL) { + PyObject *lapack = PyImport_ImportModule("numpy.linalg.lapack_lite"); + if (lapack != NULL) { + Py_DECREF(lapack); + } + PyObject *retVal2 = PyObject_CallMethod(sys, "setdlopenflags", "O",curFlags); + if (retVal2 != NULL) { + Py_DECREF(retVal2); + } + Py_DECREF(retVal); + } + Py_DECREF(curFlags); + } + Py_DECREF(sys); + } +} + +//----------------------------------------------------------------------------------------- +/** astra_mex_plugin('init'); + * + * Initialize plugin support by initializing python and importing astra + */ +void astra_mex_plugin_init() +{ + if(!Py_IsInitialized()){ + Py_Initialize(); + PyEval_InitThreads(); + } + +#ifndef _MSC_VER + fixLapackLoading(); +#endif + + // Importing astra may be overkill, since we only need to initialize + // PythonPluginAlgorithmFactory from astra.plugin_c. + PyObject *mod = PyImport_ImportModule("astra"); + Py_XDECREF(mod); +} + //----------------------------------------------------------------------------------------- /** astra_mex_plugin('get_registered'); @@ -48,7 +102,11 @@ using namespace astra; */ void astra_mex_plugin_get_registered(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { - astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr(); + astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory(); + if (!fact) { + mexPrintf("Plugin support not initialized."); + return; + } std::map<std::string, std::string> mp = fact->getRegisteredMap(); for(std::map<std::string,std::string>::iterator it=mp.begin();it!=mp.end();it++){ mexPrintf("%s: %s\n",it->first.c_str(), it->second.c_str()); @@ -62,9 +120,13 @@ void astra_mex_plugin_get_registered(int nlhs, mxArray* plhs[], int nrhs, const */ void astra_mex_plugin_register(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { + astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory(); + if (!fact) { + mexPrintf("Plugin support not initialized."); + return; + } if (2 <= nrhs) { string class_name = mexToString(prhs[1]); - astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr(); fact->registerPlugin(class_name); }else{ mexPrintf("astra_mex_plugin('register', class_name);\n"); @@ -78,9 +140,13 @@ void astra_mex_plugin_register(int nlhs, mxArray* plhs[], int nrhs, const mxArra */ void astra_mex_plugin_get_help(int nlhs, mxArray* plhs[], int nrhs, const mxArray* prhs[]) { + astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getFactory(); + if (!fact) { + mexPrintf("Plugin support not initialized."); + return; + } if (2 <= nrhs) { string name = mexToString(prhs[1]); - astra::CPluginAlgorithmFactory *fact = astra::CPluginAlgorithmFactory::getSingletonPtr(); mexPrintf((fact->getHelp(name)+"\n").c_str()); }else{ mexPrintf("astra_mex_plugin('get_help', name);\n"); @@ -116,12 +182,14 @@ void mexFunction(int nlhs, mxArray* plhs[], initASTRAMex(); // SWITCH (MODE) - if (sMode == std::string("get_registered")) { - astra_mex_plugin_get_registered(nlhs, plhs, nrhs, prhs); - }else if (sMode == std::string("get_help")) { - astra_mex_plugin_get_help(nlhs, plhs, nrhs, prhs); - }else if (sMode == std::string("register")) { - astra_mex_plugin_register(nlhs, plhs, nrhs, prhs); + if (sMode == "init") { + astra_mex_plugin_init(); + } else if (sMode == std::string("get_registered")) { + astra_mex_plugin_get_registered(nlhs, plhs, nrhs, prhs); + }else if (sMode == std::string("get_help")) { + astra_mex_plugin_get_help(nlhs, plhs, nrhs, prhs); + }else if (sMode == std::string("register")) { + astra_mex_plugin_register(nlhs, plhs, nrhs, prhs); } else { printHelp(); } diff --git a/matlab/mex/mexInitFunctions.cpp b/matlab/mex/mexInitFunctions.cpp index bd3df2c..7245af2 100644 --- a/matlab/mex/mexInitFunctions.cpp +++ b/matlab/mex/mexInitFunctions.cpp @@ -23,5 +23,13 @@ void initASTRAMex(){ if(!astra::CLogger::setCallbackScreen(&logCallBack)){ mexErrMsgTxt("Error initializing mex functions."); } + mexIsInitialized=true; + + + // If we have support for plugins, initialize them. + // (NB: Call this after setting mexIsInitialized, to avoid recursively + // calling initASTRAMex) + mexEvalString("if exist('astra_mex_plugin_c') == 3; astra_mex_plugin_c('init'); end"); + } diff --git a/python/astra/algorithm_c.pyx b/python/astra/algorithm_c.pyx index 3231c1f..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 diff --git a/python/astra/astra_c.pyx b/python/astra/astra_c.pyx index c70bb8e..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 @@ -81,7 +81,8 @@ def version(printToScreen=False): else: return getVersion() -def set_gpu_index(idx, memory=0): +IF HAVE_CUDA==True: + def set_gpu_index(idx, memory=0): import collections cdef SGPUParams params if use_cuda()==True: @@ -93,6 +94,9 @@ def set_gpu_index(idx, memory=0): ret = setGPUIndex(params.GPUIndices[0]) if not ret: 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 @@ -114,5 +118,3 @@ def info(ids): if ptr: s = ptr.getType() + six.b("\t") + ptr.getInfo(i) six.print_(wrap_from_bytes(s)) - - diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx index 801fd8e..65e80ce 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 diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx index 3b27ab7..207d9a5 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 diff --git a/python/astra/experimental.pyx b/python/astra/experimental.pyx index aafc002..9bb73a2 100644 --- a/python/astra/experimental.pyx +++ b/python/astra/experimental.pyx @@ -1,6 +1,6 @@ -#----------------------------------------------------------------------- -# Copyright: 2010-2015, iMinds-Vision Lab, University of Antwerp -# 2014-2015, CWI, Amsterdam +# ----------------------------------------------------------------------- +# Copyright: 2010-2016, iMinds-Vision Lab, University of Antwerp +# 2013-2016, CWI, Amsterdam # # Contact: astra@uantwerpen.be # Website: http://sf.net/projects/astra-toolbox @@ -21,8 +21,8 @@ # 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/extrautils.pyx b/python/astra/extrautils.pyx index 998f5cb..5bc315f 100644 --- a/python/astra/extrautils.pyx +++ b/python/astra/extrautils.pyx @@ -1,28 +1,27 @@ -#----------------------------------------------------------------------- -#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/>. # -#----------------------------------------------------------------------- +# ----------------------------------------------------------------------- def clipCircle(img): cdef int i,j diff --git a/python/astra/log_c.pyx b/python/astra/log_c.pyx index 55c63e6..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 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/plugin_c.pyx b/python/astra/plugin_c.pyx index 8d6816b..ee04853 100644 --- a/python/astra/plugin_c.pyx +++ b/python/astra/plugin_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 @@ -32,21 +32,25 @@ import inspect from libcpp.string cimport string from libcpp cimport bool -cdef CPluginAlgorithmFactory *fact = getSingletonPtr() +cdef CPythonPluginAlgorithmFactory *fact = getSingletonPtr() from . import utils -cdef extern from "astra/PluginAlgorithm.h" namespace "astra": - cdef cppclass CPluginAlgorithmFactory: +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) + 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": - cdef CPluginAlgorithmFactory* getSingletonPtr() + # NB: Using wrong pointer type here for convenience + cdef void registerFactory(CPythonPluginAlgorithmFactory *) def register(className, name=None): if inspect.isclass(className): @@ -65,3 +69,6 @@ def get_registered(): 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 aec9cde..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 diff --git a/python/astra/projector_c.pyx b/python/astra/projector_c.pyx index 77c64a4..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 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 07727ce..52c2a8d 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.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/builder.py b/python/builder.py index 018b26b..dcd62d8 100644 --- a/python/builder.py +++ b/python/builder.py @@ -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/>. # #----------------------------------------------------------------------- + import sys import os import numpy as np @@ -70,12 +70,16 @@ ext_modules = [ ] ext_modules = cythonize("astra/*.pyx", language_level=2) cmdclass = { 'build_ext': build_ext } +for m in ext_modules: + if m.name == 'astra.plugin_c': + m.sources.append('astra/src/PythonPluginAlgorithm.cpp') + setup (name = 'PyASTRAToolbox', version = '1.7.1', description = 'Python interface to the ASTRA-Toolbox', author='D.M. Pelt', author_email='D.M.Pelt@cwi.nl', - url='http://dmpelt.github.io/pyastratoolbox/', + url='http://sf.net/projects/astra-toolbox', #ext_package='astra', #ext_modules = cythonize(Extension("astra/*.pyx",extra_compile_args=extra_compile_args,extra_linker_args=extra_compile_args)), license='GPLv3', diff --git a/src/CompositeGeometryManager.cpp b/src/CompositeGeometryManager.cpp index 96b28e9..c9cbaaa 100644 --- a/src/CompositeGeometryManager.cpp +++ b/src/CompositeGeometryManager.cpp @@ -45,14 +45,15 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. #include <cstring> #include <sstream> +#include <stdint.h> #ifndef USE_PTHREADS #include <boost/thread/mutex.hpp> #include <boost/thread.hpp> #endif -namespace astra { +namespace astra { SGPUParams* CCompositeGeometryManager::s_params = 0; @@ -98,6 +99,9 @@ CCompositeGeometryManager::CCompositeGeometryManager() bool CCompositeGeometryManager::splitJobs(TJobSet &jobs, size_t maxSize, int div, TJobSet &split) { + int maxBlockDim = astraCUDA3d::maxBlockDimension(); + ASTRA_DEBUG("Found max block dim %d", maxBlockDim); + split.clear(); for (TJobSet::const_iterator i = jobs.begin(); i != jobs.end(); ++i) @@ -111,7 +115,22 @@ bool CCompositeGeometryManager::splitJobs(TJobSet &jobs, size_t maxSize, int div // b. split input part // c. create jobs for new (input,output) subparts - TPartList splitOutput = pOutput->split(maxSize/3, div); + TPartList splitOutput; + pOutput->splitZ(splitOutput, maxSize/3, SIZE_MAX, div); +#if 0 + TPartList splitOutput2; + for (TPartList::iterator i_out = splitOutput.begin(); i_out != splitOutput.end(); ++i_out) { + boost::shared_ptr<CPart> outputPart = *i_out; + outputPart.get()->splitX(splitOutput2, SIZE_MAX, SIZE_MAX, 1); + } + splitOutput.clear(); + for (TPartList::iterator i_out = splitOutput2.begin(); i_out != splitOutput2.end(); ++i_out) { + boost::shared_ptr<CPart> outputPart = *i_out; + outputPart.get()->splitY(splitOutput, SIZE_MAX, SIZE_MAX, 1); + } + splitOutput2.clear(); +#endif + for (TJobList::const_iterator j = L.begin(); j != L.end(); ++j) { @@ -139,8 +158,21 @@ bool CCompositeGeometryManager::splitJobs(TJobSet &jobs, size_t maxSize, int div size_t remainingSize = ( maxSize - outputPart->getSize() ) / 2; - TPartList splitInput = input->split(remainingSize, 1); + TPartList splitInput; + input->splitZ(splitInput, remainingSize, maxBlockDim, 1); delete input; + TPartList splitInput2; + for (TPartList::iterator i_in = splitInput.begin(); i_in != splitInput.end(); ++i_in) { + boost::shared_ptr<CPart> inputPart = *i_in; + inputPart.get()->splitX(splitInput2, SIZE_MAX, maxBlockDim, 1); + } + splitInput.clear(); + for (TPartList::iterator i_in = splitInput2.begin(); i_in != splitInput2.end(); ++i_in) { + boost::shared_ptr<CPart> inputPart = *i_in; + inputPart.get()->splitY(splitInput, SIZE_MAX, maxBlockDim, 1); + } + splitInput2.clear(); + ASTRA_DEBUG("Input split into %d parts", splitInput.size()); for (TPartList::iterator i_in = splitInput.begin(); @@ -327,10 +359,14 @@ static size_t ceildiv(size_t a, size_t b) { return (a + b - 1) / b; } -static size_t computeVerticalSplit(size_t maxBlock, int div, size_t sliceCount) +static size_t computeLinearSplit(size_t maxBlock, int div, size_t sliceCount) { size_t blockSize = maxBlock; - size_t blockCount = ceildiv(sliceCount, blockSize); + size_t blockCount; + if (sliceCount <= blockSize) + blockCount = 1; + else + blockCount = ceildiv(sliceCount, blockSize); // Increase number of blocks to be divisible by div size_t divCount = div * ceildiv(blockCount, div); @@ -410,7 +446,17 @@ SPar3DProjection* getProjectionVectors(const CParallelVecProjectionGeometry3D* p template<class V> -static void translateProjectionVectors(V* pProjs, int count, double dv) +static void translateProjectionVectorsU(V* pProjs, int count, double du) +{ + for (int i = 0; i < count; ++i) { + pProjs[i].fDetSX += du * pProjs[i].fDetUX; + pProjs[i].fDetSY += du * pProjs[i].fDetUY; + pProjs[i].fDetSZ += du * pProjs[i].fDetUZ; + } +} + +template<class V> +static void translateProjectionVectorsV(V* pProjs, int count, double dv) { for (int i = 0; i < count; ++i) { pProjs[i].fDetSX += dv * pProjs[i].fDetVX; @@ -420,8 +466,58 @@ static void translateProjectionVectors(V* pProjs, int count, double dv) } +static CProjectionGeometry3D* getSubProjectionGeometryU(const CProjectionGeometry3D* pProjGeom, int u, int size) +{ + // First convert to vectors, then translate, then convert into new object -static CProjectionGeometry3D* getSubProjectionGeometry(const CProjectionGeometry3D* pProjGeom, int v, int size) + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(pProjGeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(pProjGeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(pProjGeom); + const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(pProjGeom); + + if (conegeom || conevec3dgeom) { + SConeProjection* pConeProjs; + if (conegeom) { + pConeProjs = getProjectionVectors<SConeProjection>(conegeom); + } else { + pConeProjs = getProjectionVectors<SConeProjection>(conevec3dgeom); + } + + translateProjectionVectorsU(pConeProjs, pProjGeom->getProjectionCount(), u); + + CProjectionGeometry3D* ret = new CConeVecProjectionGeometry3D(pProjGeom->getProjectionCount(), + pProjGeom->getDetectorRowCount(), + size, + pConeProjs); + + + delete[] pConeProjs; + return ret; + } else { + assert(par3dgeom || parvec3dgeom); + SPar3DProjection* pParProjs; + if (par3dgeom) { + pParProjs = getProjectionVectors<SPar3DProjection>(par3dgeom); + } else { + pParProjs = getProjectionVectors<SPar3DProjection>(parvec3dgeom); + } + + translateProjectionVectorsU(pParProjs, pProjGeom->getProjectionCount(), u); + + CProjectionGeometry3D* ret = new CParallelVecProjectionGeometry3D(pProjGeom->getProjectionCount(), + pProjGeom->getDetectorRowCount(), + size, + pParProjs); + + delete[] pParProjs; + return ret; + } + +} + + + +static CProjectionGeometry3D* getSubProjectionGeometryV(const CProjectionGeometry3D* pProjGeom, int v, int size) { // First convert to vectors, then translate, then convert into new object @@ -438,7 +534,7 @@ static CProjectionGeometry3D* getSubProjectionGeometry(const CProjectionGeometry pConeProjs = getProjectionVectors<SConeProjection>(conevec3dgeom); } - translateProjectionVectors(pConeProjs, pProjGeom->getProjectionCount(), v); + translateProjectionVectorsV(pConeProjs, pProjGeom->getProjectionCount(), v); CProjectionGeometry3D* ret = new CConeVecProjectionGeometry3D(pProjGeom->getProjectionCount(), size, @@ -457,7 +553,7 @@ static CProjectionGeometry3D* getSubProjectionGeometry(const CProjectionGeometry pParProjs = getProjectionVectors<SPar3DProjection>(parvec3dgeom); } - translateProjectionVectors(pParProjs, pProjGeom->getProjectionCount(), v); + translateProjectionVectorsV(pParProjs, pProjGeom->getProjectionCount(), v); CProjectionGeometry3D* ret = new CParallelVecProjectionGeometry3D(pProjGeom->getProjectionCount(), size, @@ -476,17 +572,110 @@ static CProjectionGeometry3D* getSubProjectionGeometry(const CProjectionGeometry // - each no bigger than maxSize // - number of sub-parts is divisible by div // - maybe all approximately the same size? -CCompositeGeometryManager::TPartList CCompositeGeometryManager::CVolumePart::split(size_t maxSize, int div) +void CCompositeGeometryManager::CVolumePart::splitX(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div) +{ + if (true) { + // Split in vertical direction only at first, until we figure out + // a model for splitting in other directions + + size_t sliceSize = ((size_t) pGeom->getGridSliceCount()) * pGeom->getGridRowCount(); + int sliceCount = pGeom->getGridColCount(); + size_t m = std::min(maxSize / sliceSize, maxDim); + size_t blockSize = computeLinearSplit(m, div, sliceCount); + + int rem = sliceCount % blockSize; + + ASTRA_DEBUG("From %d to %d step %d", -(rem / 2), sliceCount, blockSize); + + for (int x = -(rem / 2); x < sliceCount; x += blockSize) { + int newsubX = x; + if (newsubX < 0) newsubX = 0; + int endX = x + blockSize; + if (endX > sliceCount) endX = sliceCount; + int size = endX - newsubX; + + CVolumePart *sub = new CVolumePart(); + sub->subX = this->subX + newsubX; + sub->subY = this->subY; + sub->subZ = this->subZ; + + ASTRA_DEBUG("VolumePart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub); + + double shift = pGeom->getPixelLengthX() * newsubX; + + sub->pData = pData; + sub->pGeom = new CVolumeGeometry3D(size, + pGeom->getGridRowCount(), + pGeom->getGridSliceCount(), + pGeom->getWindowMinX() + shift, + pGeom->getWindowMinY(), + pGeom->getWindowMinZ(), + pGeom->getWindowMinX() + shift + size * pGeom->getPixelLengthX(), + pGeom->getWindowMaxY(), + pGeom->getWindowMaxZ()); + + out.push_back(boost::shared_ptr<CPart>(sub)); + } + } +} + +void CCompositeGeometryManager::CVolumePart::splitY(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div) { - TPartList ret; + if (true) { + // Split in vertical direction only at first, until we figure out + // a model for splitting in other directions + + size_t sliceSize = ((size_t) pGeom->getGridColCount()) * pGeom->getGridSliceCount(); + int sliceCount = pGeom->getGridRowCount(); + size_t m = std::min(maxSize / sliceSize, maxDim); + size_t blockSize = computeLinearSplit(m, div, sliceCount); + + int rem = sliceCount % blockSize; + + ASTRA_DEBUG("From %d to %d step %d", -(rem / 2), sliceCount, blockSize); + + for (int y = -(rem / 2); y < sliceCount; y += blockSize) { + int newsubY = y; + if (newsubY < 0) newsubY = 0; + int endY = y + blockSize; + if (endY > sliceCount) endY = sliceCount; + int size = endY - newsubY; + CVolumePart *sub = new CVolumePart(); + sub->subX = this->subX; + sub->subY = this->subY + newsubY; + sub->subZ = this->subZ; + + ASTRA_DEBUG("VolumePart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub); + + double shift = pGeom->getPixelLengthY() * newsubY; + + sub->pData = pData; + sub->pGeom = new CVolumeGeometry3D(pGeom->getGridColCount(), + size, + pGeom->getGridSliceCount(), + pGeom->getWindowMinX(), + pGeom->getWindowMinY() + shift, + pGeom->getWindowMinZ(), + pGeom->getWindowMaxX(), + pGeom->getWindowMinY() + shift + size * pGeom->getPixelLengthY(), + pGeom->getWindowMaxZ()); + + out.push_back(boost::shared_ptr<CPart>(sub)); + } + } +} + +void CCompositeGeometryManager::CVolumePart::splitZ(CCompositeGeometryManager::TPartList& out, size_t maxSize, size_t maxDim, int div) +{ if (true) { // Split in vertical direction only at first, until we figure out // a model for splitting in other directions size_t sliceSize = ((size_t) pGeom->getGridColCount()) * pGeom->getGridRowCount(); int sliceCount = pGeom->getGridSliceCount(); - size_t blockSize = computeVerticalSplit(maxSize / sliceSize, div, sliceCount); + size_t m = std::min(maxSize / sliceSize, maxDim); + size_t blockSize = computeLinearSplit(m, div, sliceCount); int rem = sliceCount % blockSize; @@ -519,11 +708,9 @@ CCompositeGeometryManager::TPartList CCompositeGeometryManager::CVolumePart::spl pGeom->getWindowMaxY(), pGeom->getWindowMinZ() + shift + size * pGeom->getPixelLengthZ()); - ret.push_back(boost::shared_ptr<CPart>(sub)); + out.push_back(boost::shared_ptr<CPart>(sub)); } } - - return ret; } CCompositeGeometryManager::CVolumePart* CCompositeGeometryManager::CVolumePart::clone() const @@ -630,7 +817,7 @@ CCompositeGeometryManager::CPart* CCompositeGeometryManager::CProjectionPart::re if (_vmin == _vmax) { sub->pGeom = 0; } else { - sub->pGeom = getSubProjectionGeometry(pGeom, _vmin, _vmax - _vmin); + sub->pGeom = getSubProjectionGeometryV(pGeom, _vmin, _vmax - _vmin); } ASTRA_DEBUG("Reduce projection from %d - %d to %d - %d", this->subZ, this->subZ + pGeom->getDetectorRowCount(), this->subZ + _vmin, this->subZ + _vmax); @@ -639,17 +826,58 @@ CCompositeGeometryManager::CPart* CCompositeGeometryManager::CProjectionPart::re } -CCompositeGeometryManager::TPartList CCompositeGeometryManager::CProjectionPart::split(size_t maxSize, int div) +void CCompositeGeometryManager::CProjectionPart::splitX(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div) +{ + if (true) { + // Split in vertical direction only at first, until we figure out + // a model for splitting in other directions + + size_t sliceSize = ((size_t) pGeom->getDetectorRowCount()) * pGeom->getProjectionCount(); + int sliceCount = pGeom->getDetectorColCount(); + size_t m = std::min(maxSize / sliceSize, maxDim); + size_t blockSize = computeLinearSplit(m, div, sliceCount); + + int rem = sliceCount % blockSize; + + for (int x = -(rem / 2); x < sliceCount; x += blockSize) { + int newsubX = x; + if (newsubX < 0) newsubX = 0; + int endX = x + blockSize; + if (endX > sliceCount) endX = sliceCount; + int size = endX - newsubX; + + CProjectionPart *sub = new CProjectionPart(); + sub->subX = this->subX + newsubX; + sub->subY = this->subY; + sub->subZ = this->subZ; + + ASTRA_DEBUG("ProjectionPart split %d %d %d -> %p", sub->subX, sub->subY, sub->subZ, (void*)sub); + + sub->pData = pData; + + sub->pGeom = getSubProjectionGeometryU(pGeom, newsubX, size); + + out.push_back(boost::shared_ptr<CPart>(sub)); + } + } +} + +void CCompositeGeometryManager::CProjectionPart::splitY(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div) { - TPartList ret; + // TODO + out.push_back(boost::shared_ptr<CPart>(clone())); +} +void CCompositeGeometryManager::CProjectionPart::splitZ(CCompositeGeometryManager::TPartList &out, size_t maxSize, size_t maxDim, int div) +{ if (true) { // Split in vertical direction only at first, until we figure out // a model for splitting in other directions size_t sliceSize = ((size_t) pGeom->getDetectorColCount()) * pGeom->getProjectionCount(); int sliceCount = pGeom->getDetectorRowCount(); - size_t blockSize = computeVerticalSplit(maxSize / sliceSize, div, sliceCount); + size_t m = std::min(maxSize / sliceSize, maxDim); + size_t blockSize = computeLinearSplit(m, div, sliceCount); int rem = sliceCount % blockSize; @@ -669,14 +897,12 @@ CCompositeGeometryManager::TPartList CCompositeGeometryManager::CProjectionPart: sub->pData = pData; - sub->pGeom = getSubProjectionGeometry(pGeom, newsubZ, size); + sub->pGeom = getSubProjectionGeometryV(pGeom, newsubZ, size); - ret.push_back(boost::shared_ptr<CPart>(sub)); + out.push_back(boost::shared_ptr<CPart>(sub)); } } - return ret; - } CCompositeGeometryManager::CProjectionPart* CCompositeGeometryManager::CProjectionPart::clone() const diff --git a/src/PluginAlgorithm.cpp b/src/PluginAlgorithm.cpp index 9fc511a..1bcfbdb 100644 --- a/src/PluginAlgorithm.cpp +++ b/src/PluginAlgorithm.cpp @@ -26,376 +26,11 @@ along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>. $Id$ */ -#ifdef ASTRA_PYTHON - #include "astra/PluginAlgorithm.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 { +CPluginAlgorithmFactory *CPluginAlgorithmFactory::m_factory = 0; - -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); } -void fixLapackLoading(){ - // When running in Matlab, we need to force numpy - // to use its internal lapack library instead of - // Matlab's MKL library to avoid errors. To do this, - // we set Python's dlopen flags to RTLD_NOW|RTLD_DEEPBIND - // and import 'numpy.linalg.lapack_lite' here. We reset - // Python's dlopen flags afterwards. - PyObject *sys = PyImport_ImportModule("sys"); - if(sys!=NULL){ - PyObject *curFlags = PyObject_CallMethod(sys,"getdlopenflags",NULL); - if(curFlags!=NULL){ - PyObject *retVal = PyObject_CallMethod(sys, "setdlopenflags", "i",10); - if(retVal!=NULL){ - PyObject *lapack = PyImport_ImportModule("numpy.linalg.lapack_lite"); - if(lapack!=NULL){ - Py_DECREF(lapack); - } - PyObject_CallMethod(sys, "setdlopenflags", "O",curFlags); - Py_DECREF(retVal); - } - Py_DECREF(curFlags); - } - Py_DECREF(sys); - } -} - -CPluginAlgorithmFactory::CPluginAlgorithmFactory(){ - if(!Py_IsInitialized()){ - Py_Initialize(); - PyEval_InitThreads(); - } -#ifndef _MSC_VER - if(astra::running_in_matlab) fixLapackLoading(); -#endif - pluginDict = PyDict_New(); - inspect = PyImport_ImportModule("inspect"); - six = PyImport_ImportModule("six"); -} - -CPluginAlgorithmFactory::~CPluginAlgorithmFactory(){ - 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 CPluginAlgorithmFactory::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 CPluginAlgorithmFactory::registerPlugin(std::string className){ - PyObject *pyclass = getClassFromString(className); - if(pyclass==NULL) return false; - bool ret = registerPluginClass(pyclass); - Py_DECREF(pyclass); - return ret; -} - -bool CPluginAlgorithmFactory::registerPluginClass(std::string name, PyObject * className){ - PyDict_SetItemString(pluginDict, name.c_str(), className); - return true; -} - -bool CPluginAlgorithmFactory::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; -} - -CPluginAlgorithm * CPluginAlgorithmFactory::getPlugin(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 * CPluginAlgorithmFactory::getRegistered(){ - Py_INCREF(pluginDict); - return pluginDict; -} - -std::map<std::string, std::string> CPluginAlgorithmFactory::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 CPluginAlgorithmFactory::getHelp(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(CPluginAlgorithmFactory); - -#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 |