summaryrefslogtreecommitdiffstats
path: root/python/astra/optomo.py
diff options
context:
space:
mode:
Diffstat (limited to 'python/astra/optomo.py')
-rw-r--r--python/astra/optomo.py120
1 files changed, 87 insertions, 33 deletions
diff --git a/python/astra/optomo.py b/python/astra/optomo.py
index 2937d9c..dde719e 100644
--- a/python/astra/optomo.py
+++ b/python/astra/optomo.py
@@ -86,7 +86,15 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
self.proj_id = proj_id
- self.T = OpTomoTranspose(self)
+ self.transposeOpTomo = OpTomoTranspose(self)
+ try:
+ self.T = self.transposeOpTomo
+ except AttributeError:
+ # Scipy >= 0.16 defines self.T using self._transpose()
+ pass
+
+ def _transpose(self):
+ return self.transposeOpTomo
def __checkArray(self, arr, shp):
if len(arr.shape)==1:
@@ -103,21 +111,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
:param v: Volume to forward project.
:type v: :class:`numpy.ndarray`
"""
- v = self.__checkArray(v, self.vshape)
- vid = self.data_mod.link('-vol',self.vg,v)
- s = np.zeros(self.sshape,dtype=np.float32)
- sid = self.data_mod.link('-sino',self.pg,s)
-
- cfg = creators.astra_dict('FP'+self.appendString)
- cfg['ProjectionDataId'] = sid
- cfg['VolumeDataId'] = vid
- cfg['ProjectorId'] = self.proj_id
- fp_id = algorithm.create(cfg)
- algorithm.run(fp_id)
-
- algorithm.delete(fp_id)
- self.data_mod.delete([vid,sid])
- return s.flatten()
+ return self.FP(v, out=None).ravel()
def rmatvec(self,s):
"""Implements the transpose operator.
@@ -125,21 +119,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
:param s: The projection data.
:type s: :class:`numpy.ndarray`
"""
- s = self.__checkArray(s, self.sshape)
- sid = self.data_mod.link('-sino',self.pg,s)
- v = np.zeros(self.vshape,dtype=np.float32)
- vid = self.data_mod.link('-vol',self.vg,v)
-
- cfg = creators.astra_dict('BP'+self.appendString)
- cfg['ProjectionDataId'] = sid
- cfg['ReconstructionDataId'] = vid
- cfg['ProjectorId'] = self.proj_id
- bp_id = algorithm.create(cfg)
- algorithm.run(bp_id)
-
- algorithm.delete(bp_id)
- self.data_mod.delete([vid,sid])
- return v.flatten()
+ return self.BP(s, out=None).ravel()
def __mul__(self,v):
"""Provides easy forward operator by *.
@@ -152,7 +132,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
return self._matvec(v)
return scipy.sparse.linalg.LinearOperator.__mul__(self, v)
- def reconstruct(self, method, s, iterations=1, extraOptions = {}):
+ def reconstruct(self, method, s, iterations=1, extraOptions = None):
"""Reconstruct an object.
:param method: Method to use for reconstruction.
@@ -164,7 +144,9 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
:param extraOptions: Extra options to use during reconstruction (i.e. for cfg['option']).
:type extraOptions: :class:`dict`
"""
- self.__checkArray(s, self.sshape)
+ if extraOptions is None:
+ extraOptions={}
+ s = self.__checkArray(s, self.sshape)
sid = self.data_mod.link('-sino',self.pg,s)
v = np.zeros(self.vshape,dtype=np.float32)
vid = self.data_mod.link('-vol',self.vg,v)
@@ -179,6 +161,70 @@ class OpTomo(scipy.sparse.linalg.LinearOperator):
self.data_mod.delete([vid,sid])
return v
+ def FP(self,v,out=None):
+ """Perform forward projection.
+
+ Output must have the right 2D/3D shape. Input may also be flattened.
+
+ Output must also be contiguous and float32. This isn't required for the
+ input, but it is more efficient if it is.
+
+ :param v: Volume to forward project.
+ :type v: :class:`numpy.ndarray`
+ :param out: Array to store result in.
+ :type out: :class:`numpy.ndarray`
+ """
+
+ v = self.__checkArray(v, self.vshape)
+ vid = self.data_mod.link('-vol',self.vg,v)
+ if out is None:
+ out = np.zeros(self.sshape,dtype=np.float32)
+ sid = self.data_mod.link('-sino',self.pg,out)
+
+ cfg = creators.astra_dict('FP'+self.appendString)
+ cfg['ProjectionDataId'] = sid
+ cfg['VolumeDataId'] = vid
+ cfg['ProjectorId'] = self.proj_id
+ fp_id = algorithm.create(cfg)
+ algorithm.run(fp_id)
+
+ algorithm.delete(fp_id)
+ self.data_mod.delete([vid,sid])
+ return out
+
+ def BP(self,s,out=None):
+ """Perform backprojection.
+
+ Output must have the right 2D/3D shape. Input may also be flattened.
+
+ Output must also be contiguous and float32. This isn't required for the
+ input, but it is more efficient if it is.
+
+ :param : The projection data.
+ :type s: :class:`numpy.ndarray`
+ :param out: Array to store result in.
+ :type out: :class:`numpy.ndarray`
+ """
+ s = self.__checkArray(s, self.sshape)
+ sid = self.data_mod.link('-sino',self.pg,s)
+ if out is None:
+ out = np.zeros(self.vshape,dtype=np.float32)
+ vid = self.data_mod.link('-vol',self.vg,out)
+
+ cfg = creators.astra_dict('BP'+self.appendString)
+ cfg['ProjectionDataId'] = sid
+ cfg['ReconstructionDataId'] = vid
+ cfg['ProjectorId'] = self.proj_id
+ bp_id = algorithm.create(cfg)
+ algorithm.run(bp_id)
+
+ algorithm.delete(bp_id)
+ self.data_mod.delete([vid,sid])
+ return out
+
+
+
+
class OpTomoTranspose(scipy.sparse.linalg.LinearOperator):
"""This object provides the transpose operation (``.T``) of the OpTomo object.
@@ -189,6 +235,11 @@ class OpTomoTranspose(scipy.sparse.linalg.LinearOperator):
self.parent = parent
self.dtype = np.float32
self.shape = (parent.shape[1], parent.shape[0])
+ try:
+ self.T = self.parent
+ except AttributeError:
+ # Scipy >= 0.16 defines self.T using self._transpose()
+ pass
def _matvec(self, s):
return self.parent.rmatvec(s)
@@ -196,6 +247,9 @@ class OpTomoTranspose(scipy.sparse.linalg.LinearOperator):
def rmatvec(self, v):
return self.parent.matvec(v)
+ def _transpose(self):
+ return self.parent
+
def __mul__(self,s):
# Catch the case of a backprojection of 2D/3D data
if isinstance(s, np.ndarray) and s.shape==self.parent.sshape: