summaryrefslogtreecommitdiffstats
path: root/python
diff options
context:
space:
mode:
Diffstat (limited to 'python')
-rw-r--r--python/astra/PyIncludes.pxd45
-rw-r--r--python/astra/algorithm_c.pyx12
-rw-r--r--python/astra/creators.py13
-rw-r--r--python/astra/data2d_c.pyx64
-rw-r--r--python/astra/data3d.py38
-rw-r--r--python/astra/data3d_c.pyx41
-rw-r--r--python/astra/functions.py58
-rw-r--r--python/astra/projector_c.pyx14
-rw-r--r--python/astra/utils.pxd6
-rw-r--r--python/astra/utils.pyx158
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