diff options
| author | Daniel M. Pelt <D.M.Pelt@cwi.nl> | 2015-06-19 22:28:06 +0200 | 
|---|---|---|
| committer | Willem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl> | 2015-07-23 11:57:15 +0200 | 
| commit | 18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3 (patch) | |
| tree | 8919012d1c610eaf6b2e8c157082a85fb71137a4 /python/astra | |
| parent | 9e077994b382b2df63e4b79dd2afebc50366d419 (diff) | |
| download | astra-18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3.tar.gz astra-18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3.tar.bz2 astra-18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3.tar.xz astra-18b6d25f7e4f0943b3592f3bb4f6ca5ed9c285d3.zip | |
Add support for Python algorithm plugins
Diffstat (limited to 'python/astra')
| -rw-r--r-- | python/astra/__init__.py | 1 | ||||
| -rw-r--r-- | python/astra/plugin.py | 95 | ||||
| -rw-r--r-- | python/astra/plugin_c.pyx | 59 | ||||
| -rw-r--r-- | python/astra/utils.pyx | 72 | 
4 files changed, 160 insertions, 67 deletions
| diff --git a/python/astra/__init__.py b/python/astra/__init__.py index 6c15d30..10ed74d 100644 --- a/python/astra/__init__.py +++ b/python/astra/__init__.py @@ -34,6 +34,7 @@ from . import algorithm  from . import projector  from . import projector3d  from . import matrix +from . import plugin  from . import log  from .optomo import OpTomo diff --git a/python/astra/plugin.py b/python/astra/plugin.py new file mode 100644 index 0000000..ccdb2cb --- /dev/null +++ b/python/astra/plugin.py @@ -0,0 +1,95 @@ +#----------------------------------------------------------------------- +#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 + +class base(object): + +    def astra_init(self, cfg): +        try: +            try: +                req = self.required_options +            except AttributeError: +                log.warn("Plugin '" + self.__class__.__name__ + "' does not specify required options") +                req = {} + +            try: +                opt = self.optional_options +            except AttributeError: +                log.warn("Plugin '" + self.__class__.__name__ + "' does not specify optional options") +                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)))) + +            self.initialize(cfg) +        except Exception as e: +            log.error(str(e)) +            raise + +def register(name, className): +    """Register plugin with ASTRA. +     +    :param name: Plugin name to register +    :type name: :class:`str` +    :param className: Class name or class object to register +    :type className: :class:`str` or :class:`class` +     +    """ +    p.register(name,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..91b3cd5 --- /dev/null +++ b/python/astra/plugin_c.pyx @@ -0,0 +1,59 @@ +#----------------------------------------------------------------------- +#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/>. +# +#----------------------------------------------------------------------- +# distutils: language = c++ +# distutils: libraries = astra + +import six +import inspect + +from libcpp.string cimport string +from libcpp cimport bool + +cdef CPluginAlgorithmFactory *fact = getSingletonPtr() + +from . import utils + +cdef extern from "astra/PluginAlgorithm.h" namespace "astra": +    cdef cppclass CPluginAlgorithmFactory: +        bool registerPlugin(string name, string className) +        bool registerPluginClass(string name, object className) +        object getRegistered() +        string getHelp(string name) + +cdef extern from "astra/PluginAlgorithm.h" namespace "astra::CPluginAlgorithmFactory": +    cdef CPluginAlgorithmFactory* getSingletonPtr() + +def register(name, className): +    if inspect.isclass(className): +        fact.registerPluginClass(six.b(name), 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))) diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index ddb37aa..3746b8e 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.pyx @@ -30,7 +30,6 @@ cimport numpy as np  import numpy as np  import six  from libcpp.string cimport string -from libcpp.list cimport list  from libcpp.vector cimport vector  from cython.operator cimport dereference as deref, preincrement as inc  from cpython.version cimport PY_MAJOR_VERSION @@ -40,6 +39,9 @@ from .PyXMLDocument cimport XMLDocument  from .PyXMLDocument cimport XMLNode  from .PyIncludes cimport * +cdef extern from "astra/PluginAlgorithm.h" namespace "astra": +    object XMLNode2dict(XMLNode) +  cdef Config * dictToConfig(string rootname, dc):      cdef Config * cfg = new Config() @@ -91,6 +93,8 @@ cdef void readDict(XMLNode root, _dc):      dc = convert_item(_dc)      for item in dc:          val = dc[item] +        if isinstance(val, list): +            val = np.array(val,dtype=np.float64)          if isinstance(val, np.ndarray):              if val.size == 0:                  break @@ -142,69 +146,3 @@ cdef void readOptions(XMLNode node, dc):  cdef configToDict(Config *cfg):      return XMLNode2dict(cfg.self) -def castString3(input): -    return input.decode('utf-8') - -def castString2(input): -    return input - -if six.PY3: -    castString = castString3 -else: -    castString = castString2 - -def stringToPythonValue(inputIn): -    input = castString(inputIn) -    # matrix -    if ';' in input: -        row_strings = input.split(';') -        col_strings = row_strings[0].split(',') -        nRows = len(row_strings) -        nCols = len(col_strings) - -        out = np.empty((nRows,nCols)) -        for ridx, row in enumerate(row_strings): -            col_strings = row.split(',') -            for cidx, col in enumerate(col_strings): -                out[ridx,cidx] = float(col) -        return out - -    # vector -    if ',' in input: -        items = input.split(',') -        out = np.empty(len(items)) -        for idx,item in enumerate(items): -            out[idx] = float(item) -        return out - -    try: -        # integer -        return int(input) -    except ValueError: -        try: -            #float -            return float(input) -        except ValueError: -            # string -            return str(input) - - -cdef XMLNode2dict(XMLNode node): -    cdef XMLNode subnode -    cdef list[XMLNode] nodes -    cdef list[XMLNode].iterator it -    dct = {} -    opts = {} -    if node.hasAttribute(six.b('type')): -        dct['type'] = castString(node.getAttribute(six.b('type'))) -    nodes = node.getNodes() -    it = nodes.begin() -    while it != nodes.end(): -        subnode = deref(it) -        if castString(subnode.getName())=="Option": -            opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getAttribute('value')) -        else: -            dct[castString(subnode.getName())] = stringToPythonValue(subnode.getContent()) -        inc(it) -    if len(opts)>0: dct['options'] = opts -    return dct | 
