diff options
Diffstat (limited to 'python')
-rw-r--r-- | python/astra/PyIncludes.pxd | 45 | ||||
-rw-r--r-- | python/astra/algorithm_c.pyx | 12 | ||||
-rw-r--r-- | python/astra/creators.py | 13 | ||||
-rw-r--r-- | python/astra/data2d_c.pyx | 64 | ||||
-rw-r--r-- | python/astra/data3d.py | 38 | ||||
-rw-r--r-- | python/astra/data3d_c.pyx | 41 | ||||
-rw-r--r-- | python/astra/functions.py | 58 | ||||
-rw-r--r-- | python/astra/projector_c.pyx | 14 | ||||
-rw-r--r-- | python/astra/utils.pxd | 6 | ||||
-rw-r--r-- | python/astra/utils.pyx | 158 |
10 files changed, 266 insertions, 183 deletions
diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd index 434546a..5a81844 100644 --- a/python/astra/PyIncludes.pxd +++ b/python/astra/PyIncludes.pxd @@ -40,7 +40,6 @@ cdef extern from "astra/Globals.h" namespace "astra": cdef extern from "astra/Config.h" namespace "astra": cdef cppclass Config: Config() - void initialize(string rootname) XMLNode *self cdef extern from "astra/VolumeGeometry2D.h" namespace "astra": @@ -59,7 +58,6 @@ cdef extern from "astra/VolumeGeometry2D.h" namespace "astra": float32 getWindowMinY() float32 getWindowMaxX() float32 getWindowMaxY() - Config* getConfiguration() cdef extern from "astra/Float32VolumeData2D.h" namespace "astra": @@ -69,7 +67,6 @@ cdef extern from "astra/Float32VolumeData2D.h" namespace "astra": int getWidth() int getHeight() void changeGeometry(CVolumeGeometry2D*) - Config* getConfiguration() @@ -82,18 +79,10 @@ cdef extern from "astra/ProjectionGeometry2D.h" namespace "astra": bool isOfType(string) float32 getProjectionAngle(int) float32 getDetectorWidth() - Config* getConfiguration() cdef extern from "astra/Float32Data2D.h" namespace "astra::CFloat32Data2D": - cdef enum TWOEDataType "astra::CFloat32Data2D::EDataType": - TWOPROJECTION "astra::CFloat32Data2D::PROJECTION" - TWOVOLUME "astra::CFloat32Data2D::VOLUME" - -cdef extern from "astra/Float32Data3D.h" namespace "astra::CFloat32Data3D": - cdef enum THREEEDataType "astra::CFloat32Data3D::EDataType": - THREEPROJECTION "astra::CFloat32Data3D::PROJECTION" - THREEVOLUME "astra::CFloat32Data3D::VOLUME" - + cdef enum EDataType: + BASE,PROJECTION,VOLUME cdef extern from "astra/Float32Data2D.h" namespace "astra": cdef cppclass CFloat32Data2D: @@ -103,7 +92,7 @@ cdef extern from "astra/Float32Data2D.h" namespace "astra": float32 **getData2D() int getWidth() int getHeight() - TWOEDataType getType() + EDataType getType() @@ -115,11 +104,15 @@ cdef extern from "astra/SparseMatrixProjectionGeometry2D.h" namespace "astra": cdef extern from "astra/FanFlatProjectionGeometry2D.h" namespace "astra": cdef cppclass CFanFlatProjectionGeometry2D: CFanFlatProjectionGeometry2D() - + cdef extern from "astra/FanFlatVecProjectionGeometry2D.h" namespace "astra": cdef cppclass CFanFlatVecProjectionGeometry2D: CFanFlatVecProjectionGeometry2D() +cdef extern from "astra/ParallelVecProjectionGeometry2D.h" namespace "astra": + cdef cppclass CParallelVecProjectionGeometry2D: + CParallelVecProjectionGeometry2D() + cdef extern from "astra/ParallelProjectionGeometry2D.h" namespace "astra": cdef cppclass CParallelProjectionGeometry2D: CParallelProjectionGeometry2D() @@ -160,8 +153,8 @@ cdef extern from "astra/SparseMatrix.h" namespace "astra": float32* m_pfValues unsigned int* m_piColIndices unsigned long* m_plRowStarts - -cdef extern from "astra/Float32Data3DMemory.h" namespace "astra": + +cdef extern from "astra/Float32Data3DMemory.h" namespace "astra": cdef cppclass CFloat32Data3DMemory: CFloat32Data3DMemory() bool isInitialized() @@ -172,26 +165,22 @@ cdef extern from "astra/Float32Data3DMemory.h" namespace "astra": void updateStatistics() float32 *getData() float32 ***getData3D() - THREEEDataType getType() cdef extern from "astra/VolumeGeometry3D.h" namespace "astra": cdef cppclass CVolumeGeometry3D: CVolumeGeometry3D() bool initialize(Config) - Config * getConfiguration() cdef extern from "astra/ProjectionGeometry3D.h" namespace "astra": cdef cppclass CProjectionGeometry3D: CProjectionGeometry3D() bool initialize(Config) - Config * getConfiguration() - - + + cdef extern from "astra/Float32VolumeData3DMemory.h" namespace "astra": cdef cppclass CFloat32VolumeData3DMemory: CFloat32VolumeData3DMemory(CVolumeGeometry3D*) - CVolumeGeometry3D* getGeometry() cdef extern from "astra/ParallelProjectionGeometry3D.h" namespace "astra": @@ -206,7 +195,7 @@ cdef extern from "astra/ConeProjectionGeometry3D.h" namespace "astra": cdef cppclass CConeProjectionGeometry3D: CConeProjectionGeometry3D() bool initialize(Config) - + cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra": cdef cppclass CConeVecProjectionGeometry3D: CConeVecProjectionGeometry3D() @@ -214,10 +203,9 @@ cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra": cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra": cdef cppclass CFloat32ProjectionData3DMemory: CFloat32ProjectionData3DMemory(CProjectionGeometry3D*) - CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*) - CProjectionGeometry3D* getGeometry() + CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*) -cdef extern from "astra/Float32Data3D.h" namespace "astra": +cdef extern from "astra/Float32Data3D.h" namespace "astra": cdef cppclass CFloat32Data3D: CFloat32Data3D() bool isInitialized() @@ -226,3 +214,6 @@ cdef extern from "astra/Float32Data3D.h" namespace "astra": int getHeight() int getDepth() void updateStatistics() + + + diff --git a/python/astra/algorithm_c.pyx b/python/astra/algorithm_c.pyx index 966d3d7..0c2999c 100644 --- a/python/astra/algorithm_c.pyx +++ b/python/astra/algorithm_c.pyx @@ -49,17 +49,19 @@ cdef extern from *: def create(config): - cdef Config * cfg = utils.dictToConfig(six.b('Algorithm'), config) + cdef XMLDocument * xml = utils.dict2XML(six.b('Algorithm'), config) + cdef Config cfg cdef CAlgorithm * alg + cfg.self = xml.getRootNode() alg = PyAlgorithmFactory.getSingletonPtr().create(cfg.self.getAttribute(six.b('type'))) if alg == NULL: - del cfg + del xml raise Exception("Unknown algorithm.") - if not alg.initialize(cfg[0]): - del cfg + if not alg.initialize(cfg): + del xml del alg raise Exception("Algorithm not initialized.") - del cfg + del xml return manAlg.store(alg) cdef CAlgorithm * getAlg(i) except NULL: diff --git a/python/astra/creators.py b/python/astra/creators.py index 9aba464..b5ecd5a 100644 --- a/python/astra/creators.py +++ b/python/astra/creators.py @@ -139,6 +139,13 @@ This method can be called in a number of ways: :type angles: :class:`numpy.ndarray` :returns: A parallel projection geometry. +``create_proj_geom('parallel_vec', det_count, V)``: + +:param det_count: Number of detector pixels. +:type det_count: :class:`int` +:param V: Vector array. +:type V: :class:`numpy.ndarray` +:returns: A parallel-beam projection geometry. ``create_proj_geom('fanflat', det_width, det_count, angles, source_origin, source_det)``: @@ -226,6 +233,12 @@ This method can be called in a number of ways: raise Exception( 'not enough variables: astra_create_proj_geom(parallel, detector_spacing, det_count, angles)') return {'type': 'parallel', 'DetectorWidth': args[0], 'DetectorCount': args[1], 'ProjectionAngles': args[2]} + elif intype == 'parallel_vec': + if len(args) < 2: + raise Exception('not enough variables: astra_create_proj_geom(parallel_vec, det_count, V)') + if not args[1].shape[1] == 6: + raise Exception('V should be a Nx6 matrix, with N the number of projections') + return {'type':'parallel_vec', 'DetectorCount':args[0], 'Vectors':args[1]} elif intype == 'fanflat': if len(args) < 5: raise Exception('not enough variables: astra_create_proj_geom(fanflat, det_width, det_count, angles, source_origin, source_det)') diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx index b9c105e..dbe1c2f 100644 --- a/python/astra/data2d_c.pyx +++ b/python/astra/data2d_c.pyx @@ -47,8 +47,10 @@ from .PyIncludes cimport * cimport utils from .utils import wrap_from_bytes + cdef CData2DManager * man2d = <CData2DManager * >PyData2DManager.getSingletonPtr() + def clear(): man2d.clear() @@ -62,22 +64,25 @@ def delete(ids): def create(datatype, geometry, data=None): - cdef Config *cfg + cdef XMLDocument * xml + cdef Config cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject2D if datatype == '-vol': - cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry) + xml = utils.dict2XML(six.b('VolumeGeometry'), geometry) + cfg.self = xml.getRootNode() pGeometry = new CVolumeGeometry2D() - if not pGeometry.initialize(cfg[0]): - del cfg + if not pGeometry.initialize(cfg): + del xml del pGeometry raise Exception('Geometry class not initialized.') pDataObject2D = <CFloat32Data2D * > new CFloat32VolumeData2D(pGeometry) - del cfg + del xml del pGeometry elif datatype == '-sino': - cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) + xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) + cfg.self = xml.getRootNode() tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = <CProjectionGeometry2D * >new CSparseMatrixProjectionGeometry2D() @@ -85,15 +90,17 @@ def create(datatype, geometry, data=None): ppGeometry = <CProjectionGeometry2D * >new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = <CProjectionGeometry2D * >new CFanFlatVecProjectionGeometry2D() + elif (tpe == 'parallel_vec'): + ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D() else: ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D() - if not ppGeometry.initialize(cfg[0]): - del cfg + if not ppGeometry.initialize(cfg): + del xml del ppGeometry raise Exception('Geometry class not initialized.') pDataObject2D = <CFloat32Data2D * > new CFloat32ProjectionData2D(ppGeometry) del ppGeometry - del cfg + del xml else: raise Exception("Invalid datatype. Please specify '-vol' or '-sino'.") @@ -146,27 +153,29 @@ def get_geometry(i): cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 - if pDataObject.getType() == TWOPROJECTION: + if pDataObject.getType() == PROJECTION: pDataObject2 = <CFloat32ProjectionData2D * >pDataObject - geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration()) - elif pDataObject.getType() == TWOVOLUME: + geom = utils.createProjectionGeometryStruct(pDataObject2.getGeometry()) + elif pDataObject.getType() == VOLUME: pDataObject3 = <CFloat32VolumeData2D * >pDataObject - geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration()) + geom = utils.createVolumeGeometryStruct(pDataObject3.getGeometry()) else: raise Exception("Not a known data object") return geom def change_geometry(i, geom): - cdef Config *cfg + cdef XMLDocument * xml + cdef Config cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 - if pDataObject.getType() == TWOPROJECTION: + if pDataObject.getType() == PROJECTION: pDataObject2 = <CFloat32ProjectionData2D * >pDataObject - cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geom) + xml = utils.dict2XML(six.b('ProjectionGeometry'), geom) + cfg.self = xml.getRootNode() tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = <CProjectionGeometry2D * >new CSparseMatrixProjectionGeometry2D() @@ -174,35 +183,38 @@ def change_geometry(i, geom): ppGeometry = <CProjectionGeometry2D * >new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = <CProjectionGeometry2D * >new CFanFlatVecProjectionGeometry2D() + elif (tpe == 'parallel_vec'): + ppGeometry = <CProjectionGeometry2D * >new CParallelVecProjectionGeometry2D() else: ppGeometry = <CProjectionGeometry2D * >new CParallelProjectionGeometry2D() - if not ppGeometry.initialize(cfg[0]): - del cfg + if not ppGeometry.initialize(cfg): + del xml del ppGeometry raise Exception('Geometry class not initialized.') if (ppGeometry.getDetectorCount() != pDataObject2.getDetectorCount() or ppGeometry.getProjectionAngleCount() != pDataObject2.getAngleCount()): del ppGeometry - del cfg + del xml raise Exception( "The dimensions of the data do not match those specified in the geometry.") pDataObject2.changeGeometry(ppGeometry) del ppGeometry - del cfg - elif pDataObject.getType() == TWOVOLUME: + del xml + elif pDataObject.getType() == VOLUME: pDataObject3 = <CFloat32VolumeData2D * >pDataObject - cfg = utils.dictToConfig(six.b('VolumeGeometry'), geom) + xml = utils.dict2XML(six.b('VolumeGeometry'), geom) + cfg.self = xml.getRootNode() pGeometry = new CVolumeGeometry2D() - if not pGeometry.initialize(cfg[0]): - del cfg + if not pGeometry.initialize(cfg): + del xml del pGeometry raise Exception('Geometry class not initialized.') if (pGeometry.getGridColCount() != pDataObject3.getWidth() or pGeometry.getGridRowCount() != pDataObject3.getHeight()): - del cfg + del xml del pGeometry raise Exception( 'The dimensions of the data do not match those specified in the geometry.') pDataObject3.changeGeometry(pGeometry) - del cfg + del xml del pGeometry else: raise Exception("Not a known data object") diff --git a/python/astra/data3d.py b/python/astra/data3d.py index a2e9201..33bde51 100644 --- a/python/astra/data3d.py +++ b/python/astra/data3d.py @@ -27,7 +27,7 @@ from . import data3d_c as d def create(datatype,geometry,data=None): """Create a 3D object. - + :param datatype: Data object type, '-vol' or '-sino'. :type datatype: :class:`string` :param geometry: Volume or projection geometry. @@ -35,77 +35,67 @@ def create(datatype,geometry,data=None): :param data: Data to fill the constructed object with, either a scalar or array. :type data: :class:`float` or :class:`numpy.ndarray` :returns: :class:`int` -- the ID of the constructed object. - + """ return d.create(datatype,geometry,data) def get(i): """Get a 3D object. - + :param i: ID of object to get. :type i: :class:`int` :returns: :class:`numpy.ndarray` -- The object data. - + """ return d.get(i) def get_shared(i): """Get a 3D object with memory shared between the ASTRA toolbox and numpy array. - + :param i: ID of object to get. :type i: :class:`int` :returns: :class:`numpy.ndarray` -- The object data. - + """ return d.get_shared(i) def get_single(i): """Get a 3D object in single precision. - + :param i: ID of object to get. :type i: :class:`int` :returns: :class:`numpy.ndarray` -- The object data. - + """ return g.get_single(i) def store(i,data): """Fill existing 3D object with data. - + :param i: ID of object to fill. :type i: :class:`int` :param data: Data to fill the object with, either a scalar or array. :type data: :class:`float` or :class:`numpy.ndarray` - + """ return d.store(i,data) -def get_geometry(i): - """Get the geometry of a 3D object. - - :param i: ID of object. - :type i: :class:`int` - :returns: :class:`dict` -- The geometry of object with ID ``i``. - - """ - return d.get_geometry(i) - def dimensions(i): """Get dimensions of a 3D object. - + :param i: ID of object. :type i: :class:`int` :returns: :class:`tuple` -- dimensions of object with ID ``i``. - + """ return d.dimensions(i) def delete(ids): """Delete a 2D object. - + :param ids: ID or list of ID's to delete. :type ids: :class:`int` or :class:`list` - + """ return d.delete(ids) diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx index 4b069f7..f821aaf 100644 --- a/python/astra/data3d_c.pyx +++ b/python/astra/data3d_c.pyx @@ -51,23 +51,26 @@ cdef extern from *: CFloat32Data3DMemory * dynamic_cast_mem "dynamic_cast<astra::CFloat32Data3DMemory*>" (CFloat32Data3D * ) except NULL def create(datatype,geometry,data=None): - cdef Config *cfg + cdef XMLDocument * xml + cdef Config cfg cdef CVolumeGeometry3D * pGeometry cdef CProjectionGeometry3D * ppGeometry cdef CFloat32Data3DMemory * pDataObject3D cdef CConeProjectionGeometry3D* pppGeometry if datatype == '-vol': - cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry) + xml = utils.dict2XML(six.b('VolumeGeometry'), geometry) + cfg.self = xml.getRootNode() pGeometry = new CVolumeGeometry3D() - if not pGeometry.initialize(cfg[0]): - del cfg + if not pGeometry.initialize(cfg): + del xml del pGeometry raise Exception('Geometry class not initialized.') pDataObject3D = <CFloat32Data3DMemory * > new CFloat32VolumeData3DMemory(pGeometry) - del cfg + del xml del pGeometry elif datatype == '-sino' or datatype == '-proj3d': - cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) + xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) + cfg.self = xml.getRootNode() tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == "parallel3d"): ppGeometry = <CProjectionGeometry3D*> new CParallelProjectionGeometry3D(); @@ -80,18 +83,19 @@ def create(datatype,geometry,data=None): else: raise Exception("Invalid geometry type.") - if not ppGeometry.initialize(cfg[0]): - del cfg + if not ppGeometry.initialize(cfg): + del xml del ppGeometry raise Exception('Geometry class not initialized.') pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(ppGeometry) del ppGeometry - del cfg + del xml elif datatype == "-sinocone": - cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) + xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) + cfg.self = xml.getRootNode() pppGeometry = new CConeProjectionGeometry3D() - if not pppGeometry.initialize(cfg[0]): - del cfg + if not pppGeometry.initialize(cfg): + del xml del pppGeometry raise Exception('Geometry class not initialized.') pDataObject3D = <CFloat32Data3DMemory * > new CFloat32ProjectionData3DMemory(pppGeometry) @@ -108,19 +112,6 @@ def create(datatype,geometry,data=None): return man3d.store(<CFloat32Data3D*>pDataObject3D) -def get_geometry(i): - cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i)) - cdef CFloat32ProjectionData3DMemory * pDataObject2 - cdef CFloat32VolumeData3DMemory * pDataObject3 - if pDataObject.getType() == THREEPROJECTION: - pDataObject2 = <CFloat32ProjectionData3DMemory * >pDataObject - geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration()) - elif pDataObject.getType() == THREEVOLUME: - pDataObject3 = <CFloat32VolumeData3DMemory * >pDataObject - geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration()) - else: - raise Exception("Not a known data object") - return geom cdef fillDataObject(CFloat32Data3DMemory * obj, data): if data is None: diff --git a/python/astra/functions.py b/python/astra/functions.py index 4025468..bbbb355 100644 --- a/python/astra/functions.py +++ b/python/astra/functions.py @@ -171,7 +171,7 @@ def geom_size(geom, dim=None): elif geom['type'] == 'parallel3d' or geom['type'] == 'cone': s = (geom['DetectorRowCount'], len( geom['ProjectionAngles']), geom['DetectorColCount']) - elif geom['type'] == 'fanflat_vec': + elif geom['type'] == 'parallel_vec' or geom['type'] == 'fanflat_vec': s = (geom['Vectors'].shape[0], geom['DetectorCount']) elif geom['type'] == 'parallel3d_vec' or geom['type'] == 'cone_vec': s = (geom['DetectorRowCount'], geom[ @@ -189,7 +189,27 @@ def geom_2vec(proj_geom): :param proj_geom: Projection geometry to convert :type proj_geom: :class:`dict` """ - if proj_geom['type'] == 'fanflat': + + if proj_geom['type'] == 'parallel': + angles = proj_geom['ProjectionAngles'] + vectors = np.zeros((len(angles), 6)) + for i in range(len(angles)): + + # source + vectors[i, 0] = np.sin(angles[i]) + vectors[i, 1] = -np.cos(angles[i]) + + # center of detector + vectors[i, 2] = 0 + vectors[i, 3] = 0 + + # vector from detector pixel 0 to 1 + vectors[i, 4] = np.cos(angles[i]) * proj_geom['DetectorWidth'] + vectors[i, 5] = np.sin(angles[i]) * proj_geom['DetectorWidth'] + proj_geom_out = ac.create_proj_geom( + 'parallel_vec', proj_geom['DetectorCount'], vectors) + + elif proj_geom['type'] == 'fanflat': angles = proj_geom['ProjectionAngles'] vectors = np.zeros((len(angles), 6)) for i in range(len(angles)): @@ -268,3 +288,37 @@ def geom_2vec(proj_geom): raise ValueError( 'No suitable vector geometry found for type: ' + proj_geom['type']) return proj_geom_out + + +def geom_postalignment(proj_geom, factor): + """Returns the size of a volume or sinogram, based on the projection or volume geometry. + + :param proj_geom: input projection geometry (vector-based only, use astra.geom_2vec to convert conventional projection geometries) + :type proj_geom: :class:`dict` + :param factor: Optional axis index to return + :type factor: :class:`float` + """ + + if proj_geom['type'] == 'parallel_vec' or proj_geom['type'] == 'fanflat_vec': + for i in range(proj_geom['Vectors'].shape[0]): + proj_geom['Vectors'][i,2] = proj_geom['Vectors'][i,2] + factor * proj_geom['Vectors'][i,4]; + proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor * proj_geom['Vectors'][i,5]; + + elif proj_geom['type'] == 'parallel3d_vec' or proj_geom['type'] == 'cone_vec': + + if len(factor) == 1: + for i in range(proj_geom['Vectors'].shape[0]): + proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor * proj_geom['Vectors'][i,6]; + proj_geom['Vectors'][i,4] = proj_geom['Vectors'][i,4] + factor * proj_geom['Vectors'][i,7]; + proj_geom['Vectors'][i,5] = proj_geom['Vectors'][i,5] + factor * proj_geom['Vectors'][i,8]; + + elif len(factor) > 1: + for i in range(proj_geom['Vectors'].shape[0]): + proj_geom['Vectors'][i,3] = proj_geom['Vectors'][i,3] + factor[0] * proj_geom['Vectors'][i,6] + factor[1] * proj_geom['Vectors'][i, 9]; + proj_geom['Vectors'][i,4] = proj_geom['Vectors'][i,4] + factor[0] * proj_geom['Vectors'][i,7] + factor[1] * proj_geom['Vectors'][i,10]; + proj_geom['Vectors'][i,5] = proj_geom['Vectors'][i,5] + factor[0] * proj_geom['Vectors'][i,8] + factor[1] * proj_geom['Vectors'][i,11]; + else: + raise ValueError('No suitable geometry for postalignment: ' + proj_geom['type']) + + return proj_geom + diff --git a/python/astra/projector_c.pyx b/python/astra/projector_c.pyx index f91a8dd..978ca09 100644 --- a/python/astra/projector_c.pyx +++ b/python/astra/projector_c.pyx @@ -49,13 +49,15 @@ cdef CMatrixManager * manM = <CMatrixManager * >PyMatrixManager.getSingletonPtr( def create(config): - cdef Config * cfg = utils.dictToConfig(six.b('Projector2D'), config) + cdef XMLDocument * xml = utils.dict2XML(six.b('Projector2D'), config) + cdef Config cfg cdef CProjector2D * proj - proj = PyProjector2DFactory.getSingletonPtr().create(cfg[0]) + cfg.self = xml.getRootNode() + proj = PyProjector2DFactory.getSingletonPtr().create(cfg) if proj == NULL: - del cfg + del xml raise Exception("Error creating projector.") - del cfg + del xml return manProj.store(proj) @@ -85,12 +87,12 @@ cdef CProjector2D * getObject(i) except NULL: def projection_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.configToDict(proj.getProjectionGeometry().getConfiguration()) + return utils.createProjectionGeometryStruct(proj.getProjectionGeometry()) def volume_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.configToDict(proj.getVolumeGeometry().getConfiguration()) + return utils.createVolumeGeometryStruct(proj.getVolumeGeometry()) def weights_single_ray(i, projection_index, detector_index): diff --git a/python/astra/utils.pxd b/python/astra/utils.pxd index ca84836..55db9d3 100644 --- a/python/astra/utils.pxd +++ b/python/astra/utils.pxd @@ -31,5 +31,7 @@ from .PyXMLDocument cimport XMLNode from .PyIncludes cimport * -cdef configToDict(Config *) -cdef Config * dictToConfig(string rootname, dc) +cdef XMLDocument *dict2XML(string rootname, dc) +cdef XML2dict(XMLDocument *) +cdef createVolumeGeometryStruct(CVolumeGeometry2D* geom) +cdef createProjectionGeometryStruct(CProjectionGeometry2D* geom) diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index 0439f1b..0b8d527 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.pyx @@ -31,7 +31,7 @@ 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 cython.operator cimport dereference as deref from cpython.version cimport PY_MAJOR_VERSION cimport PyXMLDocument @@ -40,16 +40,18 @@ from .PyXMLDocument cimport XMLNode from .PyIncludes cimport * -cdef Config * dictToConfig(string rootname, dc): - cdef Config * cfg = new Config() - cfg.initialize(rootname) +cdef XMLDocument * dict2XML(string rootname, dc): + cdef XMLDocument * doc = PyXMLDocument.createDocument(rootname) + cdef XMLNode * node = doc.getRootNode() try: - readDict(cfg.self, dc) - except Exception as e: - del cfg - six.print_(e.strerror) - return NULL - return cfg + readDict(node, dc) + except: + six.print_('Error reading XML') + del doc + doc = NULL + finally: + del node + return doc def convert_item(item): if isinstance(item, six.string_types): @@ -164,73 +166,97 @@ cdef void readOptions(XMLNode * node, dc): else: node.addOption(item, wrap_to_bytes(val)) -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 vectorToNumpy(vector[float32] inp): + cdef int i + cdef int sz = inp.size() + ret = np.empty(sz) + for i in range(sz): + ret[i] = inp[i] + return ret 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'))) + dct['type'] = 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')) + if subnode.hasAttribute(six.b('listsize')): + dct[subnode.getName( + )] = vectorToNumpy(subnode.getContentNumericalArray()) else: - dct[castString(subnode.getName())] = stringToPythonValue(subnode.getContent()) + dct[subnode.getName()] = subnode.getContent() del subnode - inc(it) - if len(opts)>0: dct['options'] = opts return dct + +cdef XML2dict(XMLDocument * xml): + cdef XMLNode * node = xml.getRootNode() + dct = XMLNode2dict(node) + del node; + return dct; + +cdef createProjectionGeometryStruct(CProjectionGeometry2D * geom): + cdef int i + cdef CFanFlatVecProjectionGeometry2D * fanvecGeom + # cdef SFanProjection* p + dct = {} + dct['DetectorCount'] = geom.getDetectorCount() + if not geom.isOfType(< string > six.b('fanflat_vec')): + dct['DetectorWidth'] = geom.getDetectorWidth() + angles = np.empty(geom.getProjectionAngleCount()) + for i in range(geom.getProjectionAngleCount()): + angles[i] = geom.getProjectionAngle(i) + dct['ProjectionAngles'] = angles + else: + raise Exception("Not yet implemented") + # fanvecGeom = <CFanFlatVecProjectionGeometry2D*> geom + # vecs = np.empty(fanvecGeom.getProjectionAngleCount()*6) + # iDetCount = pVecGeom.getDetectorCount() + # for i in range(fanvecGeom.getProjectionAngleCount()): + # p = &fanvecGeom.getProjectionVectors()[i]; + # out[6*i + 0] = p.fSrcX + # out[6*i + 1] = p.fSrcY + # out[6*i + 2] = p.fDetSX + 0.5f*iDetCount*p.fDetUX + # out[6*i + 3] = p.fDetSY + 0.5f*iDetCount*p.fDetUY + # out[6*i + 4] = p.fDetUX + # out[6*i + 5] = p.fDetUY + # dct['Vectors'] = vecs + if (geom.isOfType(< string > six.b('parallel'))): + dct["type"] = "parallel" + if (geom.isOfType(< string > six.b('parallel_vec'))): + dct["type"] = "parallel_vec" + elif (geom.isOfType(< string > six.b('fanflat'))): + raise Exception("Not yet implemented") + # astra::CFanFlatProjectionGeometry2D* pFanFlatGeom = dynamic_cast<astra::CFanFlatProjectionGeometry2D*>(_pProjGeom) + # mGeometryInfo["DistanceOriginSource"] = mxCreateDoubleScalar(pFanFlatGeom->getOriginSourceDistance()) + # mGeometryInfo["DistanceOriginDetector"] = + # mxCreateDoubleScalar(pFanFlatGeom->getOriginDetectorDistance()) + dct["type"] = "fanflat" + elif (geom.isOfType(< string > six.b('sparse_matrix'))): + raise Exception("Not yet implemented") + # astra::CSparseMatrixProjectionGeometry2D* pSparseMatrixGeom = + # dynamic_cast<astra::CSparseMatrixProjectionGeometry2D*>(_pProjGeom); + dct["type"] = "sparse_matrix" + # dct["MatrixID"] = + # mxCreateDoubleScalar(CMatrixManager::getSingleton().getIndex(pSparseMatrixGeom->getMatrix())) + elif(geom.isOfType(< string > six.b('fanflat_vec'))): + dct["type"] = "fanflat_vec" + return dct + +cdef createVolumeGeometryStruct(CVolumeGeometry2D * geom): + mGeometryInfo = {} + mGeometryInfo["GridColCount"] = geom.getGridColCount() + mGeometryInfo["GridRowCount"] = geom.getGridRowCount() + + mGeometryOptions = {} + mGeometryOptions["WindowMinX"] = geom.getWindowMinX() + mGeometryOptions["WindowMaxX"] = geom.getWindowMaxX() + mGeometryOptions["WindowMinY"] = geom.getWindowMinY() + mGeometryOptions["WindowMaxY"] = geom.getWindowMaxY() + + mGeometryInfo["option"] = mGeometryOptions + return mGeometryInfo |