summaryrefslogtreecommitdiffstats
path: root/python/astra
diff options
context:
space:
mode:
authorWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2017-11-22 16:41:34 +0100
committerWillem Jan Palenstijn <Willem.Jan.Palenstijn@cwi.nl>2017-11-22 16:41:34 +0100
commita527cc9e29cae256bd095b032f34c80957e84907 (patch)
treee68dd547d6a88c188eca4798423adf084ba58124 /python/astra
parent6a7b605102f1c22224b516906cb4a848cda50a3b (diff)
parentbd2798bed2fddfe00dac006013a9fb1363417f20 (diff)
downloadastra-a527cc9e29cae256bd095b032f34c80957e84907.tar.gz
astra-a527cc9e29cae256bd095b032f34c80957e84907.tar.bz2
astra-a527cc9e29cae256bd095b032f34c80957e84907.tar.xz
astra-a527cc9e29cae256bd095b032f34c80957e84907.zip
Merge branch 'master' into parallel_vec
Diffstat (limited to 'python/astra')
-rw-r--r--python/astra/PyIncludes.pxd5
-rw-r--r--python/astra/__init__.py6
-rw-r--r--python/astra/algorithm_c.pyx17
-rw-r--r--python/astra/astra.py10
-rw-r--r--python/astra/astra_c.pyx10
-rw-r--r--python/astra/creators.py29
-rw-r--r--python/astra/data3d_c.pyx26
-rw-r--r--python/astra/experimental.pyx4
-rw-r--r--python/astra/tests.py97
-rw-r--r--python/astra/utils.pyx2
10 files changed, 167 insertions, 39 deletions
diff --git a/python/astra/PyIncludes.pxd b/python/astra/PyIncludes.pxd
index bba47f3..84469aa 100644
--- a/python/astra/PyIncludes.pxd
+++ b/python/astra/PyIncludes.pxd
@@ -156,6 +156,10 @@ cdef extern from "astra/ReconstructionAlgorithm2D.h" namespace "astra":
cdef cppclass CReconstructionAlgorithm2D:
bool getResidualNorm(float32&)
+cdef extern from "astra/ReconstructionAlgorithm3D.h" namespace "astra":
+ cdef cppclass CReconstructionAlgorithm3D:
+ bool getResidualNorm(float32&)
+
cdef extern from "astra/Projector2D.h" namespace "astra":
cdef cppclass CProjector2D:
bool isInitialized()
@@ -211,7 +215,6 @@ cdef extern from "astra/Float32Data3DMemory.h" namespace "astra":
CFloat32Data3DMemory()
void updateStatistics()
float32 *getData()
- float32 ***getData3D()
THREEEDataType getType()
diff --git a/python/astra/__init__.py b/python/astra/__init__.py
index b73fff5..5e52a1c 100644
--- a/python/astra/__init__.py
+++ b/python/astra/__init__.py
@@ -27,6 +27,7 @@ from . import matlab as m
from .creators import astra_dict,create_vol_geom, create_proj_geom, create_backprojection, create_sino, create_reconstruction, create_projector,create_sino3d_gpu, create_backprojection3d_gpu
from .functions import data_op, add_noise_to_sino, clear, move_vol_geom
from .extrautils import clipCircle
+from .astra import set_gpu_index, get_gpu_info
from . import data2d
from . import astra
from . import data3d
@@ -38,11 +39,12 @@ from . import plugin
from . import plugins
from . import log
from .optomo import OpTomo
+from .tests import test_noCUDA, test_CUDA
-__version__ = '1.8'
+__version__ = '1.8.3'
import os
if 'ASTRA_GPU_INDEX' in os.environ:
L = [ int(x) for x in os.environ['ASTRA_GPU_INDEX'].split(',') ]
- astra.set_gpu_index(L)
+ set_gpu_index(L)
diff --git a/python/astra/algorithm_c.pyx b/python/astra/algorithm_c.pyx
index 9ed0634..161fe98 100644
--- a/python/astra/algorithm_c.pyx
+++ b/python/astra/algorithm_c.pyx
@@ -44,7 +44,8 @@ from .utils import wrap_from_bytes
cdef CAlgorithmManager * manAlg = <CAlgorithmManager * >PyAlgorithmManager.getSingletonPtr()
cdef extern from *:
- CReconstructionAlgorithm2D * dynamic_cast_recAlg "dynamic_cast<astra::CReconstructionAlgorithm2D*>" (CAlgorithm * ) except NULL
+ CReconstructionAlgorithm2D * dynamic_cast_recAlg2D "dynamic_cast<astra::CReconstructionAlgorithm2D*>" (CAlgorithm * )
+ CReconstructionAlgorithm3D * dynamic_cast_recAlg3D "dynamic_cast<astra::CReconstructionAlgorithm3D*>" (CAlgorithm * )
def create(config):
@@ -79,12 +80,18 @@ def run(i, iterations=0):
def get_res_norm(i):
cdef CReconstructionAlgorithm2D * pAlg2D
+ cdef CReconstructionAlgorithm3D * pAlg3D
cdef CAlgorithm * alg = getAlg(i)
cdef float32 res = 0.0
- pAlg2D = dynamic_cast_recAlg(alg)
- if pAlg2D == NULL:
- raise Exception("Operation not supported.")
- if not pAlg2D.getResidualNorm(res):
+ pAlg2D = dynamic_cast_recAlg2D(alg)
+ pAlg3D = dynamic_cast_recAlg3D(alg)
+ if pAlg2D != NULL:
+ if not pAlg2D.getResidualNorm(res):
+ raise Exception("Operation not supported.")
+ elif pAlg3D != NULL:
+ if not pAlg3D.getResidualNorm(res):
+ raise Exception("Operation not supported.")
+ else:
raise Exception("Operation not supported.")
return res
diff --git a/python/astra/astra.py b/python/astra/astra.py
index 3804d51..434ccb9 100644
--- a/python/astra/astra.py
+++ b/python/astra/astra.py
@@ -45,6 +45,16 @@ def set_gpu_index(idx, memory=0):
"""
a.set_gpu_index(idx, memory)
+def get_gpu_info(idx=-1):
+ """Get GPU info.
+
+ :param idx: GPU index, or -1 for current device
+ :type idx: :class:`int`
+ :returns: :class:`str` -- GPU info
+ """
+ return a.get_gpu_info(idx)
+
+
def delete(ids):
"""Delete an astra object.
diff --git a/python/astra/astra_c.pyx b/python/astra/astra_c.pyx
index 6de10da..f25fc2a 100644
--- a/python/astra/astra_c.pyx
+++ b/python/astra/astra_c.pyx
@@ -40,11 +40,15 @@ cdef extern from "astra/Globals.h" namespace "astra":
bool cudaEnabled()
IF HAVE_CUDA==True:
- cdef extern from "../cuda/2d/darthelper.h" namespace "astraCUDA":
+ cdef extern from "../cuda/2d/astra.h" namespace "astraCUDA":
bool setGPUIndex(int)
+ string getCudaDeviceString(int)
ELSE:
def setGPUIndex():
pass
+ def getCudaDeviceString(idx):
+ pass
+
cdef extern from "astra/CompositeGeometryManager.h" namespace "astra":
cdef cppclass SGPUParams:
vector[int] GPUIndices
@@ -85,9 +89,13 @@ IF HAVE_CUDA==True:
ret = setGPUIndex(params.GPUIndices[0])
if not ret:
six.print_("Failed to set GPU " + str(params.GPUIndices[0]))
+ def get_gpu_info(idx=-1):
+ return wrap_from_bytes(getCudaDeviceString(idx))
ELSE:
def set_gpu_index(idx, memory=0):
raise NotImplementedError("CUDA support is not enabled in ASTRA")
+ def get_gpu_info(idx=-1):
+ raise NotImplementedError("CUDA support is not enabled in ASTRA")
def delete(ids):
import collections
diff --git a/python/astra/creators.py b/python/astra/creators.py
index 4ddaf0c..85daf82 100644
--- a/python/astra/creators.py
+++ b/python/astra/creators.py
@@ -81,37 +81,19 @@ This method can be called in a number of ways:
if len(varargin) == 1 and isinstance(varargin[0], int) == 1:
vol_geom['GridRowCount'] = varargin[0]
vol_geom['GridColCount'] = varargin[0]
- vol_geom['option']['WindowMinX'] = -varargin[0] / 2.
- vol_geom['option']['WindowMaxX'] = varargin[0] / 2.
- vol_geom['option']['WindowMinY'] = -varargin[0] / 2.
- vol_geom['option']['WindowMaxY'] = varargin[0] / 2.
# astra_create_vol_geom([row_count col_count])
elif len(varargin) == 1 and len(varargin[0]) == 2:
vol_geom['GridRowCount'] = varargin[0][0]
vol_geom['GridColCount'] = varargin[0][1]
- vol_geom['option']['WindowMinX'] = -varargin[0][1] / 2.
- vol_geom['option']['WindowMaxX'] = varargin[0][1] / 2.
- vol_geom['option']['WindowMinY'] = -varargin[0][0] / 2.
- vol_geom['option']['WindowMaxY'] = varargin[0][0] / 2.
# astra_create_vol_geom([row_count col_count slice_count])
elif len(varargin) == 1 and len(varargin[0]) == 3:
vol_geom['GridRowCount'] = varargin[0][0]
vol_geom['GridColCount'] = varargin[0][1]
vol_geom['GridSliceCount'] = varargin[0][2]
- vol_geom['option']['WindowMinX'] = -varargin[0][1] / 2.
- vol_geom['option']['WindowMaxX'] = varargin[0][1] / 2.
- vol_geom['option']['WindowMinY'] = -varargin[0][0] / 2.
- vol_geom['option']['WindowMaxY'] = varargin[0][0] / 2.
- vol_geom['option']['WindowMinZ'] = -varargin[0][2] / 2.
- vol_geom['option']['WindowMaxZ'] = varargin[0][2] / 2.
# astra_create_vol_geom(row_count, col_count)
elif len(varargin) == 2:
vol_geom['GridRowCount'] = varargin[0]
vol_geom['GridColCount'] = varargin[1]
- vol_geom['option']['WindowMinX'] = -varargin[1] / 2.
- vol_geom['option']['WindowMaxX'] = varargin[1] / 2.
- vol_geom['option']['WindowMinY'] = -varargin[0] / 2.
- vol_geom['option']['WindowMaxY'] = varargin[0] / 2.
# astra_create_vol_geom(row_count, col_count, min_x, max_x, min_y, max_y)
elif len(varargin) == 6:
vol_geom['GridRowCount'] = varargin[0]
@@ -136,6 +118,17 @@ This method can be called in a number of ways:
vol_geom['option']['WindowMaxY'] = varargin[6]
vol_geom['option']['WindowMinZ'] = varargin[7]
vol_geom['option']['WindowMaxZ'] = varargin[8]
+
+ # set the window options, if not set already.
+ if not 'WindowMinX' in vol_geom['option']:
+ vol_geom['option']['WindowMinX'] = -vol_geom['GridColCount'] / 2.
+ vol_geom['option']['WindowMaxX'] = vol_geom['GridColCount'] / 2.
+ vol_geom['option']['WindowMinY'] = -vol_geom['GridRowCount'] / 2.
+ vol_geom['option']['WindowMaxY'] = vol_geom['GridRowCount'] / 2.
+ if 'GridSliceCount' in vol_geom:
+ vol_geom['option']['WindowMinZ'] = -vol_geom['GridSliceCount'] / 2.
+ vol_geom['option']['WindowMaxZ'] = vol_geom['GridSliceCount'] / 2.
+
return vol_geom
diff --git a/python/astra/data3d_c.pyx b/python/astra/data3d_c.pyx
index 78ed620..897634b 100644
--- a/python/astra/data3d_c.pyx
+++ b/python/astra/data3d_c.pyx
@@ -60,7 +60,13 @@ cdef extern from "Python.h":
cdef CData3DManager * man3d = <CData3DManager * >PyData3DManager.getSingletonPtr()
cdef extern from *:
- CFloat32Data3DMemory * dynamic_cast_mem "dynamic_cast<astra::CFloat32Data3DMemory*>" (CFloat32Data3D * ) except NULL
+ CFloat32Data3DMemory * dynamic_cast_mem "dynamic_cast<astra::CFloat32Data3DMemory*>" (CFloat32Data3D * )
+
+cdef CFloat32Data3DMemory * dynamic_cast_mem_safe(CFloat32Data3D *obj) except NULL:
+ cdef CFloat32Data3DMemory *ret = dynamic_cast_mem(obj)
+ if not ret:
+ raise RuntimeError("Not a memory 3D data object")
+ return ret
cdef extern from "CFloat32CustomPython.h":
cdef cppclass CFloat32CustomPython:
@@ -154,12 +160,12 @@ def create(datatype,geometry,data=None, link=False):
raise RuntimeError("Couldn't initialize data object.")
if not link:
- fillDataObject(dynamic_cast_mem(pDataObject3D), data)
+ fillDataObject(dynamic_cast_mem_safe(pDataObject3D), data)
return man3d.store(<CFloat32Data3D*>pDataObject3D)
def get_geometry(i):
- cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i))
+ cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem_safe(getObject(i))
cdef CFloat32ProjectionData3DMemory * pDataObject2
cdef CFloat32VolumeData3DMemory * pDataObject3
if pDataObject.getType() == THREEPROJECTION:
@@ -173,7 +179,7 @@ def get_geometry(i):
return geom
def change_geometry(i, geom):
- cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i))
+ cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem_safe(getObject(i))
cdef CFloat32ProjectionData3DMemory * pDataObject2
cdef CFloat32VolumeData3DMemory * pDataObject3
if pDataObject.getType() == THREEPROJECTION:
@@ -248,7 +254,7 @@ cdef fillDataObjectScalar(CFloat32Data3DMemory * obj, float s):
@cython.boundscheck(False)
@cython.wraparound(False)
cdef fillDataObjectArray(CFloat32Data3DMemory * obj, float [:,:,::1] data):
- cdef float [:,:,::1] cView = <float[:data.shape[0],:data.shape[1],:data.shape[2]]> obj.getData3D()[0][0]
+ cdef float [:,:,::1] cView = <float[:data.shape[0],:data.shape[1],:data.shape[2]]> obj.getData()
cView[:] = data
cdef CFloat32Data3D * getObject(i) except NULL:
@@ -262,28 +268,28 @@ cdef CFloat32Data3D * getObject(i) except NULL:
@cython.boundscheck(False)
@cython.wraparound(False)
def get(i):
- cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i))
+ cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem_safe(getObject(i))
outArr = np.empty((pDataObject.getDepth(),pDataObject.getHeight(), pDataObject.getWidth()),dtype=np.float32,order='C')
cdef float [:,:,::1] mView = outArr
- cdef float [:,:,::1] cView = <float[:outArr.shape[0],:outArr.shape[1],:outArr.shape[2]]> pDataObject.getData3D()[0][0]
+ cdef float [:,:,::1] cView = <float[:outArr.shape[0],:outArr.shape[1],:outArr.shape[2]]> pDataObject.getData()
mView[:] = cView
return outArr
def get_shared(i):
- cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem(getObject(i))
+ cdef CFloat32Data3DMemory * pDataObject = dynamic_cast_mem_safe(getObject(i))
outArr = np.empty((pDataObject.getDepth(),pDataObject.getHeight(), pDataObject.getWidth()),dtype=np.float32,order='C')
cdef np.npy_intp shape[3]
shape[0] = <np.npy_intp> pDataObject.getDepth()
shape[1] = <np.npy_intp> pDataObject.getHeight()
shape[2] = <np.npy_intp> pDataObject.getWidth()
- return np.PyArray_SimpleNewFromData(3,shape,np.NPY_FLOAT32,<void *>pDataObject.getData3D()[0][0])
+ return np.PyArray_SimpleNewFromData(3,shape,np.NPY_FLOAT32,<void *>pDataObject.getData())
def get_single(i):
raise NotImplementedError("Not yet implemented")
def store(i,data):
cdef CFloat32Data3D * pDataObject = getObject(i)
- fillDataObject(dynamic_cast_mem(pDataObject), data)
+ fillDataObject(dynamic_cast_mem_safe(pDataObject), data)
def dimensions(i):
cdef CFloat32Data3D * pDataObject = getObject(i)
diff --git a/python/astra/experimental.pyx b/python/astra/experimental.pyx
index 0af3118..136165b 100644
--- a/python/astra/experimental.pyx
+++ b/python/astra/experimental.pyx
@@ -40,8 +40,8 @@ IF HAVE_CUDA==True:
bool doBP(CProjector3D *, vector[CFloat32VolumeData3D *], vector[CFloat32ProjectionData3D *])
cdef extern from *:
- CFloat32VolumeData3D * dynamic_cast_vol_mem "dynamic_cast<astra::CFloat32VolumeData3D*>" (CFloat32Data3D * ) except NULL
- CFloat32ProjectionData3D * dynamic_cast_proj_mem "dynamic_cast<astra::CFloat32ProjectionData3D*>" (CFloat32Data3D * ) except NULL
+ CFloat32VolumeData3D * dynamic_cast_vol_mem "dynamic_cast<astra::CFloat32VolumeData3D*>" (CFloat32Data3D * )
+ CFloat32ProjectionData3D * dynamic_cast_proj_mem "dynamic_cast<astra::CFloat32ProjectionData3D*>" (CFloat32Data3D * )
cdef extern from "astra/Float32ProjectionData3D.h" namespace "astra":
cdef cppclass CFloat32ProjectionData3D:
diff --git a/python/astra/tests.py b/python/astra/tests.py
new file mode 100644
index 0000000..32afd36
--- /dev/null
+++ b/python/astra/tests.py
@@ -0,0 +1,97 @@
+# -----------------------------------------------------------------------
+# Copyright: 2010-2017, iMinds-Vision Lab, University of Antwerp
+# 2013-2017, CWI, Amsterdam
+#
+# Contact: astra@uantwerpen.be
+# Website: http://www.astra-toolbox.com/
+#
+# This file is part of the ASTRA Toolbox.
+#
+#
+# The ASTRA Toolbox is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# The ASTRA Toolbox is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with the ASTRA Toolbox. If not, see <http://www.gnu.org/licenses/>.
+#
+# -----------------------------------------------------------------------
+
+from __future__ import print_function, absolute_import
+
+def _basic_par2d_fp(type):
+ import astra
+ import numpy as np
+ vg = astra.create_vol_geom(2, 32)
+ pg = astra.create_proj_geom('parallel', 1, 32, [0])
+ proj_id = astra.create_projector(type, pg, vg)
+ vol = np.random.rand(2, 32)
+ (sino_id, sino) = astra.create_sino(vol, proj_id)
+ astra.data2d.delete(sino_id)
+ astra.projector.delete(proj_id)
+ err = np.max(np.abs(sino[0,:] - np.sum(vol,axis=0)))
+ return err < 1e-6
+
+def _basic_par3d_fp():
+ import astra
+ import numpy as np
+ vg = astra.create_vol_geom(2, 32, 32)
+ pg = astra.create_proj_geom('parallel3d', 1, 1, 32, 32, [0])
+ vol = np.random.rand(32, 2, 32)
+ (sino_id, sino) = astra.create_sino3d_gpu(vol, pg, vg)
+ astra.data3d.delete(sino_id)
+ err = np.max(np.abs(sino[:,0,:] - np.sum(vol,axis=1)))
+ return err < 1e-6
+
+
+def _basic_par2d():
+ print("Testing basic CPU 2D functionality... ", end="")
+ if _basic_par2d_fp('line'):
+ print("Ok")
+ return True
+ else:
+ print("Error")
+ return False
+
+def _basic_par2d_cuda():
+ print("Testing basic CUDA 2D functionality... ", end="")
+ if _basic_par2d_fp('cuda'):
+ print("Ok")
+ return True
+ else:
+ print("Error")
+ return False
+
+def _basic_par3d_cuda():
+ print("Testing basic CUDA 3D functionality... ", end="")
+ if _basic_par3d_fp():
+ print("Ok")
+ return True
+ else:
+ print("Error")
+ return False
+
+def test_noCUDA():
+ """Perform a very basic functionality test, without CUDA"""
+
+ ok = _basic_par2d()
+ if not ok:
+ raise RuntimeError("Test failed")
+
+def test_CUDA():
+ """Perform a very basic functionality test, including CUDA"""
+
+ import astra
+ print("Getting GPU info... ", end="")
+ print(astra.get_gpu_info())
+ ok1 = _basic_par2d()
+ ok2 = _basic_par2d_cuda()
+ ok3 = _basic_par3d_cuda()
+ if not (ok1 and ok2 and ok3):
+ raise RuntimeError("Test failed")
diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx
index a40916b..bcff6c3 100644
--- a/python/astra/utils.pyx
+++ b/python/astra/utils.pyx
@@ -171,6 +171,7 @@ def stringToPythonValue(inputIn):
input = castString(inputIn)
# matrix
if ';' in input:
+ input = input.rstrip(';')
row_strings = input.split(';')
col_strings = row_strings[0].split(',')
nRows = len(row_strings)
@@ -185,6 +186,7 @@ def stringToPythonValue(inputIn):
# vector
if ',' in input:
+ input = input.rstrip(',')
items = input.split(',')
out = np.empty(len(items))
for idx,item in enumerate(items):