From e8765bcdab3be977cd5536531cacb24bf3378a59 Mon Sep 17 00:00:00 2001 From: Wim van Aarle Date: Thu, 12 Mar 2015 17:32:28 +0100 Subject: added parallel_vec to the python bindings --- python/astra/PyIncludes.pxd | 4 ++++ python/astra/creators.py | 13 +++++++++++++ python/astra/data2d_c.pyx | 4 ++++ python/astra/functions.py | 22 +++++++++++++++++++++- python/astra/utils.pyx | 2 ++ 5 files changed, 44 insertions(+), 1 deletion(-) (limited to 'python') diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd index fc5980f..5a81844 100644 --- a/python/astra/PyIncludes.pxd +++ b/python/astra/PyIncludes.pxd @@ -109,6 +109,10 @@ 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() 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 ec1b478..dbe1c2f 100644 --- a/python/astra/data2d_c.pyx +++ b/python/astra/data2d_c.pyx @@ -90,6 +90,8 @@ def create(datatype, geometry, data=None): ppGeometry = new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = new CFanFlatVecProjectionGeometry2D() + elif (tpe == 'parallel_vec'): + ppGeometry = new CParallelVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() if not ppGeometry.initialize(cfg): @@ -181,6 +183,8 @@ def change_geometry(i, geom): ppGeometry = new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = new CFanFlatVecProjectionGeometry2D() + elif (tpe == 'parallel_vec'): + ppGeometry = new CParallelVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() if not ppGeometry.initialize(cfg): diff --git a/python/astra/functions.py b/python/astra/functions.py index 4025468..b9deb66 100644 --- a/python/astra/functions.py +++ b/python/astra/functions.py @@ -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)): diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index 53e84a9..0b8d527 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.pyx @@ -227,6 +227,8 @@ cdef createProjectionGeometryStruct(CProjectionGeometry2D * geom): # 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(_pProjGeom) -- cgit v1.2.3 From 1ca3383b9454c3952c9715c0a8fc52a1031c67ce Mon Sep 17 00:00:00 2001 From: Wim van Aarle Date: Tue, 17 Mar 2015 16:25:23 +0100 Subject: updated python tools --- python/astra/functions.py | 36 +++++++++++++++++++++++++++++++++++- 1 file changed, 35 insertions(+), 1 deletion(-) (limited to 'python') diff --git a/python/astra/functions.py b/python/astra/functions.py index b9deb66..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[ @@ -288,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 + -- cgit v1.2.3 From fb01aaf4cd4e7f22308e07bd94dcfc97083e8ec8 Mon Sep 17 00:00:00 2001 From: Wim van Aarle Date: Wed, 18 Mar 2015 11:08:20 +0100 Subject: updated python bindings --- python/astra/PyIncludes.pxd | 41 +++++++---- python/astra/algorithm_c.pyx | 12 ++-- python/astra/data2d_c.pyx | 60 +++++++--------- python/astra/data3d.py | 38 +++++++---- python/astra/data3d_c.pyx | 41 ++++++----- python/astra/projector_c.pyx | 14 ++-- python/astra/utils.pxd | 6 +- python/astra/utils.pyx | 158 ++++++++++++++++++------------------------- 8 files changed, 181 insertions(+), 189 deletions(-) (limited to 'python') diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd index 5a81844..ea624fc 100644 --- a/python/astra/PyIncludes.pxd +++ b/python/astra/PyIncludes.pxd @@ -40,6 +40,7 @@ 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": @@ -58,6 +59,7 @@ cdef extern from "astra/VolumeGeometry2D.h" namespace "astra": float32 getWindowMinY() float32 getWindowMaxX() float32 getWindowMaxY() + Config* getConfiguration() cdef extern from "astra/Float32VolumeData2D.h" namespace "astra": @@ -67,6 +69,7 @@ cdef extern from "astra/Float32VolumeData2D.h" namespace "astra": int getWidth() int getHeight() void changeGeometry(CVolumeGeometry2D*) + Config* getConfiguration() @@ -79,10 +82,18 @@ 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 EDataType: - BASE,PROJECTION,VOLUME + 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 extern from "astra/Float32Data2D.h" namespace "astra": cdef cppclass CFloat32Data2D: @@ -92,7 +103,7 @@ cdef extern from "astra/Float32Data2D.h" namespace "astra": float32 **getData2D() int getWidth() int getHeight() - EDataType getType() + TWOEDataType getType() @@ -104,7 +115,7 @@ 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() @@ -153,8 +164,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() @@ -165,22 +176,26 @@ 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": @@ -195,7 +210,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() @@ -203,9 +218,10 @@ cdef extern from "astra/ConeVecProjectionGeometry3D.h" namespace "astra": cdef extern from "astra/Float32ProjectionData3DMemory.h" namespace "astra": cdef cppclass CFloat32ProjectionData3DMemory: CFloat32ProjectionData3DMemory(CProjectionGeometry3D*) - CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*) + CFloat32ProjectionData3DMemory(CConeProjectionGeometry3D*) + CProjectionGeometry3D* getGeometry() -cdef extern from "astra/Float32Data3D.h" namespace "astra": +cdef extern from "astra/Float32Data3D.h" namespace "astra": cdef cppclass CFloat32Data3D: CFloat32Data3D() bool isInitialized() @@ -214,6 +230,3 @@ 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 0c2999c..966d3d7 100644 --- a/python/astra/algorithm_c.pyx +++ b/python/astra/algorithm_c.pyx @@ -49,19 +49,17 @@ cdef extern from *: def create(config): - cdef XMLDocument * xml = utils.dict2XML(six.b('Algorithm'), config) - cdef Config cfg + cdef Config * cfg = utils.dictToConfig(six.b('Algorithm'), config) cdef CAlgorithm * alg - cfg.self = xml.getRootNode() alg = PyAlgorithmFactory.getSingletonPtr().create(cfg.self.getAttribute(six.b('type'))) if alg == NULL: - del xml + del cfg raise Exception("Unknown algorithm.") - if not alg.initialize(cfg): - del xml + if not alg.initialize(cfg[0]): + del cfg del alg raise Exception("Algorithm not initialized.") - del xml + del cfg return manAlg.store(alg) cdef CAlgorithm * getAlg(i) except NULL: diff --git a/python/astra/data2d_c.pyx b/python/astra/data2d_c.pyx index dbe1c2f..882051c 100644 --- a/python/astra/data2d_c.pyx +++ b/python/astra/data2d_c.pyx @@ -47,10 +47,8 @@ from .PyIncludes cimport * cimport utils from .utils import wrap_from_bytes - cdef CData2DManager * man2d = PyData2DManager.getSingletonPtr() - def clear(): man2d.clear() @@ -64,25 +62,22 @@ def delete(ids): def create(datatype, geometry, data=None): - cdef XMLDocument * xml - cdef Config cfg + cdef Config *cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject2D if datatype == '-vol': - xml = utils.dict2XML(six.b('VolumeGeometry'), geometry) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry) pGeometry = new CVolumeGeometry2D() - if not pGeometry.initialize(cfg): - del xml + if not pGeometry.initialize(cfg[0]): + del cfg del pGeometry raise Exception('Geometry class not initialized.') pDataObject2D = new CFloat32VolumeData2D(pGeometry) - del xml + del cfg del pGeometry elif datatype == '-sino': - xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = new CSparseMatrixProjectionGeometry2D() @@ -94,13 +89,13 @@ def create(datatype, geometry, data=None): ppGeometry = new CParallelVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() - if not ppGeometry.initialize(cfg): - del xml + if not ppGeometry.initialize(cfg[0]): + del cfg del ppGeometry raise Exception('Geometry class not initialized.') pDataObject2D = new CFloat32ProjectionData2D(ppGeometry) del ppGeometry - del xml + del cfg else: raise Exception("Invalid datatype. Please specify '-vol' or '-sino'.") @@ -153,29 +148,27 @@ def get_geometry(i): cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 - if pDataObject.getType() == PROJECTION: + if pDataObject.getType() == TWOPROJECTION: pDataObject2 = pDataObject - geom = utils.createProjectionGeometryStruct(pDataObject2.getGeometry()) - elif pDataObject.getType() == VOLUME: + geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration()) + elif pDataObject.getType() == TWOVOLUME: pDataObject3 = pDataObject - geom = utils.createVolumeGeometryStruct(pDataObject3.getGeometry()) + geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration()) else: raise Exception("Not a known data object") return geom def change_geometry(i, geom): - cdef XMLDocument * xml - cdef Config cfg + cdef Config *cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 - if pDataObject.getType() == PROJECTION: + if pDataObject.getType() == TWOPROJECTION: pDataObject2 = pDataObject - xml = utils.dict2XML(six.b('ProjectionGeometry'), geom) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geom) tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = new CSparseMatrixProjectionGeometry2D() @@ -187,34 +180,33 @@ def change_geometry(i, geom): ppGeometry = new CParallelVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() - if not ppGeometry.initialize(cfg): - del xml + if not ppGeometry.initialize(cfg[0]): + del cfg del ppGeometry raise Exception('Geometry class not initialized.') if (ppGeometry.getDetectorCount() != pDataObject2.getDetectorCount() or ppGeometry.getProjectionAngleCount() != pDataObject2.getAngleCount()): del ppGeometry - del xml + del cfg raise Exception( "The dimensions of the data do not match those specified in the geometry.") pDataObject2.changeGeometry(ppGeometry) del ppGeometry - del xml - elif pDataObject.getType() == VOLUME: + del cfg + elif pDataObject.getType() == TWOVOLUME: pDataObject3 = pDataObject - xml = utils.dict2XML(six.b('VolumeGeometry'), geom) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('VolumeGeometry'), geom) pGeometry = new CVolumeGeometry2D() - if not pGeometry.initialize(cfg): - del xml + if not pGeometry.initialize(cfg[0]): + del cfg del pGeometry raise Exception('Geometry class not initialized.') if (pGeometry.getGridColCount() != pDataObject3.getWidth() or pGeometry.getGridRowCount() != pDataObject3.getHeight()): - del xml + del cfg del pGeometry raise Exception( 'The dimensions of the data do not match those specified in the geometry.') pDataObject3.changeGeometry(pGeometry) - del xml + del cfg del pGeometry else: raise Exception("Not a known data object") diff --git a/python/astra/data3d.py b/python/astra/data3d.py index 33bde51..a2e9201 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,67 +35,77 @@ 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 f821aaf..4b069f7 100644 --- a/python/astra/data3d_c.pyx +++ b/python/astra/data3d_c.pyx @@ -51,26 +51,23 @@ cdef extern from *: CFloat32Data3DMemory * dynamic_cast_mem "dynamic_cast" (CFloat32Data3D * ) except NULL def create(datatype,geometry,data=None): - cdef XMLDocument * xml - cdef Config cfg + cdef Config *cfg cdef CVolumeGeometry3D * pGeometry cdef CProjectionGeometry3D * ppGeometry cdef CFloat32Data3DMemory * pDataObject3D cdef CConeProjectionGeometry3D* pppGeometry if datatype == '-vol': - xml = utils.dict2XML(six.b('VolumeGeometry'), geometry) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry) pGeometry = new CVolumeGeometry3D() - if not pGeometry.initialize(cfg): - del xml + if not pGeometry.initialize(cfg[0]): + del cfg del pGeometry raise Exception('Geometry class not initialized.') pDataObject3D = new CFloat32VolumeData3DMemory(pGeometry) - del xml + del cfg del pGeometry elif datatype == '-sino' or datatype == '-proj3d': - xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == "parallel3d"): ppGeometry = new CParallelProjectionGeometry3D(); @@ -83,19 +80,18 @@ def create(datatype,geometry,data=None): else: raise Exception("Invalid geometry type.") - if not ppGeometry.initialize(cfg): - del xml + if not ppGeometry.initialize(cfg[0]): + del cfg del ppGeometry raise Exception('Geometry class not initialized.') pDataObject3D = new CFloat32ProjectionData3DMemory(ppGeometry) del ppGeometry - del xml + del cfg elif datatype == "-sinocone": - xml = utils.dict2XML(six.b('ProjectionGeometry'), geometry) - cfg.self = xml.getRootNode() + cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) pppGeometry = new CConeProjectionGeometry3D() - if not pppGeometry.initialize(cfg): - del xml + if not pppGeometry.initialize(cfg[0]): + del cfg del pppGeometry raise Exception('Geometry class not initialized.') pDataObject3D = new CFloat32ProjectionData3DMemory(pppGeometry) @@ -112,6 +108,19 @@ def create(datatype,geometry,data=None): return man3d.store(pDataObject3D) +def get_geometry(i): + cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i)) + cdef CFloat32ProjectionData3DMemory * pDataObject2 + cdef CFloat32VolumeData3DMemory * pDataObject3 + if pDataObject.getType() == THREEPROJECTION: + pDataObject2 = pDataObject + geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration()) + elif pDataObject.getType() == THREEVOLUME: + pDataObject3 = 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/projector_c.pyx b/python/astra/projector_c.pyx index 978ca09..f91a8dd 100644 --- a/python/astra/projector_c.pyx +++ b/python/astra/projector_c.pyx @@ -49,15 +49,13 @@ cdef CMatrixManager * manM = PyMatrixManager.getSingletonPtr( def create(config): - cdef XMLDocument * xml = utils.dict2XML(six.b('Projector2D'), config) - cdef Config cfg + cdef Config * cfg = utils.dictToConfig(six.b('Projector2D'), config) cdef CProjector2D * proj - cfg.self = xml.getRootNode() - proj = PyProjector2DFactory.getSingletonPtr().create(cfg) + proj = PyProjector2DFactory.getSingletonPtr().create(cfg[0]) if proj == NULL: - del xml + del cfg raise Exception("Error creating projector.") - del xml + del cfg return manProj.store(proj) @@ -87,12 +85,12 @@ cdef CProjector2D * getObject(i) except NULL: def projection_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.createProjectionGeometryStruct(proj.getProjectionGeometry()) + return utils.configToDict(proj.getProjectionGeometry().getConfiguration()) def volume_geometry(i): cdef CProjector2D * proj = getObject(i) - return utils.createVolumeGeometryStruct(proj.getVolumeGeometry()) + return utils.configToDict(proj.getVolumeGeometry().getConfiguration()) def weights_single_ray(i, projection_index, detector_index): diff --git a/python/astra/utils.pxd b/python/astra/utils.pxd index 55db9d3..ca84836 100644 --- a/python/astra/utils.pxd +++ b/python/astra/utils.pxd @@ -31,7 +31,5 @@ from .PyXMLDocument cimport XMLNode from .PyIncludes cimport * -cdef XMLDocument *dict2XML(string rootname, dc) -cdef XML2dict(XMLDocument *) -cdef createVolumeGeometryStruct(CVolumeGeometry2D* geom) -cdef createProjectionGeometryStruct(CProjectionGeometry2D* geom) +cdef configToDict(Config *) +cdef Config * dictToConfig(string rootname, dc) diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index 0b8d527..0439f1b 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 +from cython.operator cimport dereference as deref, preincrement as inc from cpython.version cimport PY_MAJOR_VERSION cimport PyXMLDocument @@ -40,18 +40,16 @@ from .PyXMLDocument cimport XMLNode from .PyIncludes cimport * -cdef XMLDocument * dict2XML(string rootname, dc): - cdef XMLDocument * doc = PyXMLDocument.createDocument(rootname) - cdef XMLNode * node = doc.getRootNode() +cdef Config * dictToConfig(string rootname, dc): + cdef Config * cfg = new Config() + cfg.initialize(rootname) try: - readDict(node, dc) - except: - six.print_('Error reading XML') - del doc - doc = NULL - finally: - del node - return doc + readDict(cfg.self, dc) + except Exception as e: + del cfg + six.print_(e.strerror) + return NULL + return cfg def convert_item(item): if isinstance(item, six.string_types): @@ -166,97 +164,73 @@ cdef void readOptions(XMLNode * node, dc): else: node.addOption(item, wrap_to_bytes(val)) -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 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'] = node.getAttribute(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 subnode.hasAttribute(six.b('listsize')): - dct[subnode.getName( - )] = vectorToNumpy(subnode.getContentNumericalArray()) + if castString(subnode.getName())=="Option": + opts[castString(subnode.getAttribute('key'))] = stringToPythonValue(subnode.getAttribute('value')) else: - dct[subnode.getName()] = subnode.getContent() + dct[castString(subnode.getName())] = stringToPythonValue(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 = 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(_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(_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 -- cgit v1.2.3 From a3dc1d2ee6e683dadfd4ec418c72aa13eea6a2db Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Tue, 19 Sep 2017 16:45:33 +0200 Subject: Fix spaces/tabs --- python/astra/PyIncludes.pxd | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'python') diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd index 1c7973a..cf3f902 100644 --- a/python/astra/PyIncludes.pxd +++ b/python/astra/PyIncludes.pxd @@ -129,8 +129,8 @@ cdef extern from "astra/FanFlatVecProjectionGeometry2D.h" namespace "astra": CFanFlatVecProjectionGeometry2D() cdef extern from "astra/ParallelVecProjectionGeometry2D.h" namespace "astra": - cdef cppclass CParallelVecProjectionGeometry2D: - CParallelVecProjectionGeometry2D() + cdef cppclass CParallelVecProjectionGeometry2D: + CParallelVecProjectionGeometry2D() cdef extern from "astra/ParallelProjectionGeometry2D.h" namespace "astra": cdef cppclass CParallelProjectionGeometry2D: -- cgit v1.2.3 From bf92d2d8dfacd7125ed48403145dbd4dc6181e4a Mon Sep 17 00:00:00 2001 From: Willem Jan Palenstijn Date: Mon, 9 Oct 2017 15:12:14 +0200 Subject: Support parallel_vec in python geom_size --- python/astra/pythonutils.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'python') diff --git a/python/astra/pythonutils.py b/python/astra/pythonutils.py index 27fa8fd..1028a0a 100644 --- a/python/astra/pythonutils.py +++ b/python/astra/pythonutils.py @@ -51,7 +51,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'] == 'fanflat_vec' or geom['type'] == 'parallel_vec': s = (geom['Vectors'].shape[0], geom['DetectorCount']) elif geom['type'] == 'parallel3d_vec' or geom['type'] == 'cone_vec': s = (geom['DetectorRowCount'], geom[ -- cgit v1.2.3