#----------------------------------------------------------------------- #Copyright 2013 Centrum Wiskunde & Informatica, Amsterdam # #Author: Daniel M. Pelt #Contact: D.M.Pelt@cwi.nl #Website: http://dmpelt.github.io/pyastratoolbox/ # # #This file is part of the Python interface to the #All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA Toolbox"). # #The Python interface to 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 Python interface to 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 Python interface to the ASTRA Toolbox. If not, see . # #----------------------------------------------------------------------- # distutils: language = c++ # distutils: libraries = astra import six cimport cython from cython cimport view cimport PyData2DManager from .PyData2DManager cimport CData2DManager cimport PyXMLDocument from .PyXMLDocument cimport XMLDocument import numpy as np cimport numpy as np np.import_array() from .PyIncludes cimport * cimport utils from .utils import wrap_from_bytes from .pythonutils import geom_size import operator from six.moves import reduce cdef CData2DManager * man2d = PyData2DManager.getSingletonPtr() cdef extern from "CFloat32CustomPython.h": cdef cppclass CFloat32CustomPython: CFloat32CustomPython(arrIn) def clear(): man2d.clear() def delete(ids): try: for i in ids: man2d.remove(i) except TypeError: man2d.remove(ids) def create(datatype, geometry, data=None, link=False): cdef Config *cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject2D cdef CFloat32CustomMemory * pCustom if link: geomSize = geom_size(geometry) if len(data.shape)==1: if data.size!=reduce(operator.mul,geomSize): raise Exception("The dimensions of the data do not match those specified in the geometry.") else: if data.shape!=geomSize: raise Exception("The dimensions of the data do not match those specified in the geometry.") if datatype == '-vol': cfg = utils.dictToConfig(six.b('VolumeGeometry'), geometry) pGeometry = new CVolumeGeometry2D() if not pGeometry.initialize(cfg[0]): del cfg del pGeometry raise Exception('Geometry class not initialized.') if link: pCustom = new CFloat32CustomPython(data) pDataObject2D = new CFloat32VolumeData2D(pGeometry, pCustom) else: pDataObject2D = new CFloat32VolumeData2D(pGeometry) del cfg del pGeometry elif datatype == '-sino': cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geometry) tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = new CSparseMatrixProjectionGeometry2D() elif (tpe == 'fanflat'): ppGeometry = new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = new CFanFlatVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() if not ppGeometry.initialize(cfg[0]): del cfg del ppGeometry raise Exception('Geometry class not initialized.') if link: pCustom = new CFloat32CustomPython(data) pDataObject2D = new CFloat32ProjectionData2D(ppGeometry, pCustom) else: pDataObject2D = new CFloat32ProjectionData2D(ppGeometry) del ppGeometry del cfg else: raise Exception("Invalid datatype. Please specify '-vol' or '-sino'.") if not pDataObject2D.isInitialized(): del pDataObject2D raise Exception("Couldn't initialize data object.") if not link: fillDataObject(pDataObject2D, data) return man2d.store(pDataObject2D) cdef fillDataObject(CFloat32Data2D * obj, data): if data is None: fillDataObjectScalar(obj, 0) else: if isinstance(data, np.ndarray): fillDataObjectArray(obj, np.ascontiguousarray(data,dtype=np.float32)) else: fillDataObjectScalar(obj, np.float32(data)) cdef fillDataObjectScalar(CFloat32Data2D * obj, float s): cdef int i for i in range(obj.getSize()): obj.getData()[i] = s @cython.boundscheck(False) @cython.wraparound(False) cdef fillDataObjectArray(CFloat32Data2D * obj, float [:,::1] data): if (not data.shape[0] == obj.getHeight()) or (not data.shape[1] == obj.getWidth()): raise Exception( "The dimensions of the data do not match those specified in the geometry.") cdef float [:,::1] cView = obj.getData2D()[0] cView[:] = data cdef CFloat32Data2D * getObject(i) except NULL: cdef CFloat32Data2D * pDataObject = man2d.get(i) if pDataObject == NULL: raise Exception("Data object not found") if not pDataObject.isInitialized(): raise Exception("Data object not initialized properly.") return pDataObject def store(i, data): cdef CFloat32Data2D * pDataObject = getObject(i) fillDataObject(pDataObject, data) def get_geometry(i): cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 if pDataObject.getType() == TWOPROJECTION: pDataObject2 = pDataObject geom = utils.configToDict(pDataObject2.getGeometry().getConfiguration()) elif pDataObject.getType() == TWOVOLUME: pDataObject3 = pDataObject geom = utils.configToDict(pDataObject3.getGeometry().getConfiguration()) else: raise Exception("Not a known data object") return geom def change_geometry(i, geom): cdef Config *cfg cdef CVolumeGeometry2D * pGeometry cdef CProjectionGeometry2D * ppGeometry cdef CFloat32Data2D * pDataObject = getObject(i) cdef CFloat32ProjectionData2D * pDataObject2 cdef CFloat32VolumeData2D * pDataObject3 if pDataObject.getType() == TWOPROJECTION: pDataObject2 = pDataObject cfg = utils.dictToConfig(six.b('ProjectionGeometry'), geom) tpe = wrap_from_bytes(cfg.self.getAttribute(six.b('type'))) if (tpe == 'sparse_matrix'): ppGeometry = new CSparseMatrixProjectionGeometry2D() elif (tpe == 'fanflat'): ppGeometry = new CFanFlatProjectionGeometry2D() elif (tpe == 'fanflat_vec'): ppGeometry = new CFanFlatVecProjectionGeometry2D() else: ppGeometry = new CParallelProjectionGeometry2D() 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 cfg 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: pDataObject3 = pDataObject cfg = utils.dictToConfig(six.b('VolumeGeometry'), geom) pGeometry = new CVolumeGeometry2D() 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 cfg del pGeometry raise Exception( 'The dimensions of the data do not match those specified in the geometry.') pDataObject3.changeGeometry(pGeometry) del cfg del pGeometry else: raise Exception("Not a known data object") @cython.boundscheck(False) @cython.wraparound(False) def get(i): cdef CFloat32Data2D * pDataObject = getObject(i) outArr = np.empty((pDataObject.getHeight(), pDataObject.getWidth()),dtype=np.float32,order='C') cdef float [:,::1] mView = outArr cdef float [:,::1] cView = pDataObject.getData2D()[0] mView[:] = cView return outArr def get_shared(i): cdef CFloat32Data2D * pDataObject = getObject(i) cdef np.npy_intp shape[2] shape[0] = pDataObject.getHeight() shape[1] = pDataObject.getWidth() return np.PyArray_SimpleNewFromData(2,shape,np.NPY_FLOAT32,pDataObject.getData2D()[0]) def get_single(i): raise Exception("Not yet implemented") def info(): six.print_(wrap_from_bytes(man2d.info()))