diff options
Diffstat (limited to 'src')
81 files changed, 16728 insertions, 0 deletions
diff --git a/src/Algorithm.cpp b/src/Algorithm.cpp new file mode 100644 index 0000000..38ae65d --- /dev/null +++ b/src/Algorithm.cpp @@ -0,0 +1,64 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Algorithm.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CAlgorithm::CAlgorithm() : m_bShouldAbort(false), configCheckData(0) { + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CAlgorithm::~CAlgorithm() { + +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["Initialized"] = getInformation("Initialized"); + return result; +}; + +//---------------------------------------------------------------------------------------- +// Information - Specific +boost::any CAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "Initialized") { return m_bIsInitialized ? "yes" : "no"; } + return std::string("not found"); +} + +} // namespace astra diff --git a/src/ArtAlgorithm.cpp b/src/ArtAlgorithm.cpp new file mode 100644 index 0000000..77ab5ab --- /dev/null +++ b/src/ArtAlgorithm.cpp @@ -0,0 +1,331 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ArtAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CArtAlgorithm::type = "ART"; + +//---------------------------------------------------------------------------------------- +// Constructor +CArtAlgorithm::CArtAlgorithm() + : CReconstructionAlgorithm2D() +{ + m_fLambda = 1.0f; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_piProjectionOrder = NULL; + m_piDetectorOrder = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CArtAlgorithm::~CArtAlgorithm() +{ + if (m_piProjectionOrder != NULL) + delete[] m_piProjectionOrder; + if (m_piDetectorOrder != NULL) + delete[] m_piDetectorOrder; +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CArtAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_piDetectorOrder = NULL; + m_piProjectionOrder = NULL; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CArtAlgorithm::clear() +{ + CReconstructionAlgorithm2D::clear(); + if (m_piDetectorOrder) { + delete[] m_piDetectorOrder; + m_piDetectorOrder = NULL; + } + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + m_fLambda = 1.0f; + m_iRayCount = 0; + m_iCurrentRay = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CArtAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "ART", "Error in ReconstructionAlgorithm2D initialization"); + + // check ray order list + for (int i = 0; i < m_iRayCount; i++) { + if (m_piProjectionOrder[i] < 0 || m_piProjectionOrder[i] > m_pSinogram->getAngleCount()-1) { + ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list."); + } + if (m_piDetectorOrder[i] < 0 || m_piDetectorOrder[i] > m_pSinogram->getDetectorCount()-1) { + ASTRA_CONFIG_CHECK(false, "ART", "Invalid value in ray order list."); + } + } + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CArtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ArtAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // ray order + string projOrder = _cfg.self->getOption("RayOrder", "sequential"); + CC.markOptionParsed("RayOrder"); + m_iCurrentRay = 0; + m_iRayCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount() * + m_pProjector->getProjectionGeometry()->getDetectorCount(); + if (projOrder == "sequential") { + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = (int)floor((float)i / m_pProjector->getProjectionGeometry()->getDetectorCount()); + m_piDetectorOrder[i] = i % m_pProjector->getProjectionGeometry()->getDetectorCount(); + } + } else if (projOrder == "custom") { + vector<float32> rayOrderList = _cfg.self->getOptionNumericalArray("RayOrderList"); + m_iRayCount = rayOrderList.size() / 2; + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = static_cast<int>(rayOrderList[2*i]); + m_piDetectorOrder[i] = static_cast<int>(rayOrderList[2*i+1]); + } + CC.markOptionParsed("RayOrderList"); + } else { + return false; + } + + m_fLambda = _cfg.self->getOptionNumerical("Lambda", 1.0f); + CC.markOptionParsed("Lambda"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CArtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentRay = 0; + m_iRayCount = _pProjector->getProjectionGeometry()->getDetectorCount() * + _pProjector->getProjectionGeometry()->getProjectionAngleCount(); + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = (int)floor((float)i / _pProjector->getProjectionGeometry()->getDetectorCount()); + m_piDetectorOrder[i] = i % _pProjector->getProjectionGeometry()->getDetectorCount(); + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Set the relaxation factor. +void CArtAlgorithm::setLambda(float32 _fLambda) +{ + m_fLambda = _fLambda; +} + +//---------------------------------------------------------------------------------------- +// Set the order in which the rays will be selected +void CArtAlgorithm::setRayOrder(int* _piProjectionOrder, int* _piDetectorOrder, int _iRayCount) +{ + if (m_piDetectorOrder) { + delete[] m_piDetectorOrder; + m_piDetectorOrder = NULL; + } + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + + m_iCurrentRay = 0; + m_iRayCount = _iRayCount; + m_piProjectionOrder = new int[m_iRayCount]; + m_piDetectorOrder = new int[m_iRayCount]; + for (int i = 0; i < m_iRayCount; i++) { + m_piProjectionOrder[i] = _piProjectionOrder[i]; + m_piDetectorOrder[i] = _piDetectorOrder[i]; + } +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CArtAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["RayOrder"] = getInformation("RayOrder"); + res["Lambda"] = getInformation("Lambda"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CArtAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "Lambda") { return m_fLambda; } + if (_sIdentifier == "RayOrder") { + vector<float32> res; + for (int i = 0; i < m_iRayCount; i++) { + res.push_back(m_piProjectionOrder[i]); + } + for (int i = 0; i < m_iRayCount; i++) { + res.push_back(m_piDetectorOrder[i]); + } + return res; + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CArtAlgorithm::run(int _iNrIterations) +{ + // check initialized + assert(m_bIsInitialized); + + // variables + int iIteration, iPixel; + int iUsedPixels, iProjection, iDetector; + float32 fRayForwardProj, fSumSquaredWeights; + float32 fProjectionDifference, fBackProjectionFactor; + + // create a pixel buffer + int iPixelBufferSize = m_pProjector->getProjectionWeightsCount(0); + SPixelWeight* pPixels = new SPixelWeight[iPixelBufferSize]; + + // start iterations + for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + + // step0: compute single weight rays + iProjection = m_piProjectionOrder[m_iCurrentRay]; + iDetector = m_piDetectorOrder[m_iCurrentRay]; + m_iCurrentRay = (m_iCurrentRay + 1) % m_iRayCount; + + if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + m_pProjector->computeSingleRayWeights(iProjection, iDetector, pPixels, iPixelBufferSize, iUsedPixels); + + // step1: forward projections + fRayForwardProj = 0.0f; + fSumSquaredWeights = 0.0f; + for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) { + if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue; + + fRayForwardProj += pPixels[iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[iPixel].m_iIndex]; + fSumSquaredWeights += pPixels[iPixel].m_fWeight * pPixels[iPixel].m_fWeight; + } + if (fSumSquaredWeights == 0) continue; + + // step2: difference + fProjectionDifference = m_pSinogram->getData2D()[iProjection][iDetector] - fRayForwardProj; + + // step3: back projection + fBackProjectionFactor = m_fLambda * fProjectionDifference / fSumSquaredWeights; + for (iPixel = iUsedPixels-1; iPixel >= 0; --iPixel) { + + // pixel must be loose + if (m_bUseReconstructionMask && m_pReconstructionMask->getDataConst()[pPixels[iPixel].m_iIndex] == 0) continue; + + // update + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] += fBackProjectionFactor * pPixels[iPixel].m_fWeight; + + // constraints + if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] < m_fMinValue) { + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMinValue; + } + if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] > m_fMaxValue) { + m_pReconstruction->getData()[pPixels[iPixel].m_iIndex] = m_fMaxValue; + } + } + + } + delete[] pPixels; + + // update statistics + m_pReconstruction->updateStatistics(); +} + + +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/AstraObjectFactory.cpp b/src/AstraObjectFactory.cpp new file mode 100644 index 0000000..195c431 --- /dev/null +++ b/src/AstraObjectFactory.cpp @@ -0,0 +1,39 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AstraObjectFactory.h" + +using namespace std; + +namespace astra { + +DEFINE_SINGLETON2(CAstraObjectFactory<CAlgorithm, AlgorithmTypeList>); +DEFINE_SINGLETON2(CAstraObjectFactory<CProjector2D, Projector2DTypeList>); +DEFINE_SINGLETON2(CAstraObjectFactory<CProjector3D, Projector3DTypeList>); + +} // end namespace diff --git a/src/AstraObjectManager.cpp b/src/AstraObjectManager.cpp new file mode 100644 index 0000000..597119d --- /dev/null +++ b/src/AstraObjectManager.cpp @@ -0,0 +1,43 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AstraObjectManager.h" + + +namespace astra { + +int CAstraIndexManager::m_iPreviousIndex = 0; + +DEFINE_SINGLETON(CAstraObjectManager<CProjector2D>); +DEFINE_SINGLETON(CAstraObjectManager<CProjector3D>); +DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data2D>); +DEFINE_SINGLETON(CAstraObjectManager<CFloat32Data3D>); +DEFINE_SINGLETON(CAstraObjectManager<CAlgorithm>); +DEFINE_SINGLETON(CAstraObjectManager<CSparseMatrix>); + +} // end namespace diff --git a/src/AsyncAlgorithm.cpp b/src/AsyncAlgorithm.cpp new file mode 100644 index 0000000..431dbbc --- /dev/null +++ b/src/AsyncAlgorithm.cpp @@ -0,0 +1,195 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/AsyncAlgorithm.h" +#include "astra/AstraObjectFactory.h" + +#ifndef USE_PTHREAD +#include <boost/bind.hpp> +#endif + +namespace astra { + +CAsyncAlgorithm::CAsyncAlgorithm() +{ + m_bInitialized = false; +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; +} + +CAsyncAlgorithm::CAsyncAlgorithm(CAlgorithm* _pAlg) +{ + m_pAlg = _pAlg; + m_bInitialized = (m_pAlg != 0); +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_bDone = false; + m_bAutoFree = false; +} + +bool CAsyncAlgorithm::initialize(const Config& _cfg) +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_pAlg = 0; + m_bDone = false; + + m_pAlg = CAlgorithmFactory::getSingleton().create(_cfg); + if (m_pAlg && !m_pAlg->isInitialized()) { + if (m_bAutoFree) + delete m_pAlg; + m_pAlg = 0; + } + m_bInitialized = (m_pAlg != 0); + m_bAutoFree = true; + return m_bInitialized; +} + +bool CAsyncAlgorithm::initialize(CAlgorithm* _pAlg) +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + m_bDone = false; + + m_pAlg = _pAlg; + m_bInitialized = (m_pAlg != 0); + m_bAutoFree = false; + return m_bInitialized; +} + +CAsyncAlgorithm::~CAsyncAlgorithm() +{ + if (m_bInitialized && m_bThreadStarted) { +#ifndef USE_PTHREADS + m_pThread->join(); + delete m_pThread; +#else + pthread_join(m_thread, 0); +#endif + } +#ifndef USE_PTHREADS + m_pThread = 0; +#endif + m_bThreadStarted = false; + + if (m_bInitialized && m_bAutoFree) { + delete m_pAlg; + m_pAlg = 0; + } +} + +#ifdef USE_PTHREADS +void* runAsync_pthreads(void* data) +{ + CAsyncAlgorithm::AsyncThreadInfo *info = (CAsyncAlgorithm::AsyncThreadInfo*)data; + info->m_pAlg->run(info->m_iIterations); + *info->m_pDone = true; + return 0; +} +#endif + +void CAsyncAlgorithm::run(int _iNrIterations) +{ + if (!m_bInitialized) + return; + +#ifndef USE_PTHREADS + m_pThread = new boost::thread( + boost::bind(&CAsyncAlgorithm::runWrapped, + this, _iNrIterations)); +#else + m_ThreadInfo.m_iIterations = _iNrIterations; + m_ThreadInfo.m_pAlg = m_pAlg; + m_ThreadInfo.m_pDone = &this->m_bDone; + pthread_create(&m_thread, 0, runAsync_pthreads, &this->m_ThreadInfo); +#endif +} + +void CAsyncAlgorithm::runWrapped(int _iNrIterations) +{ + m_pAlg->run(_iNrIterations); + m_bDone = true; +} + +void CAsyncAlgorithm::timedJoin(int _milliseconds) +{ +#ifndef USE_PTHREADS + if (m_pThread) { + boost::posix_time::milliseconds rel(_milliseconds); + bool res = m_pThread->timed_join(rel); + if (res) { + delete m_pThread; + m_pThread = 0; + m_bThreadStarted = false; + } + } +#else + if (m_bThreadStarted) { + struct timespec abstime; + clock_gettime(CLOCK_REALTIME, &abstime); + abstime.tv_sec += _milliseconds / 1000; + abstime.tv_nsec += (_milliseconds % 1000) * 1000000L; + int err = pthread_timedjoin_np(m_thread, 0, &abstime); + if (err == 0) { + m_bThreadStarted = false; + } + } +#endif +} + +void CAsyncAlgorithm::signalAbort() +{ + if (m_pAlg) + m_pAlg->signalAbort(); +} + +} diff --git a/src/BackProjectionAlgorithm.cpp b/src/BackProjectionAlgorithm.cpp new file mode 100644 index 0000000..cf8c9ca --- /dev/null +++ b/src/BackProjectionAlgorithm.cpp @@ -0,0 +1,192 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/BackProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CBackProjectionAlgorithm::type = "BP"; + +//---------------------------------------------------------------------------------------- +// Constructor +CBackProjectionAlgorithm::CBackProjectionAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CBackProjectionAlgorithm::CBackProjectionAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CBackProjectionAlgorithm::~CBackProjectionAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CBackProjectionAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CBackProjectionAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CBackProjectionAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "BP", "Error in ReconstructionAlgorithm2D initialization"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("BackProjectionAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CBackProjectionAlgorithm::_init() +{ + +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CBackProjectionAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CBackProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CBackProjectionAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + CDataProjectorInterface* pBackProjector; + + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(m_pReconstruction, m_pSinogram), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + m_pReconstruction->setData(0.0f); + pBackProjector->project(); + + ASTRA_DELETE(pBackProjector); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CglsAlgorithm.cpp b/src/CglsAlgorithm.cpp new file mode 100644 index 0000000..f3e1be1 --- /dev/null +++ b/src/CglsAlgorithm.cpp @@ -0,0 +1,297 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CglsAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCglsAlgorithm::type = "CGLS"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCglsAlgorithm::CCglsAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CCglsAlgorithm::CCglsAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCglsAlgorithm::~CCglsAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CCglsAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + r = NULL; + w = NULL; + z = NULL; + p = NULL; + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + m_iIteration = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CCglsAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + ASTRA_DELETE(r); + ASTRA_DELETE(w); + ASTRA_DELETE(z); + ASTRA_DELETE(p); + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + m_iIteration = 0; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCglsAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "CGLS", "Error in ReconstructionAlgorithm2D initialization"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCglsAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CglsAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // member variables + r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + + alpha = 0.0f; + beta = 0.0f; + gamma = 0.0f; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCglsAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // member variables + r = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + w = new CFloat32ProjectionData2D(m_pSinogram->getGeometry()); + z = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + p = new CFloat32VolumeData2D(m_pReconstruction->getGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCglsAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCglsAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCglsAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + + // forward projection data projector + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultFPPolicy(p, w), // forward projection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(z, r), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + int i; + + if (m_iIteration == 0) { + // r = b; + r->copyData(m_pSinogram->getData()); + + // z = A'*b; + z->setData(0.0f); + pBackProjector->project(); + if (m_bUseMinConstraint) + z->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + z->clampMax(m_fMaxValue); + + // p = z; + p->copyData(z->getData()); + + // gamma = dot(z,z); + gamma = 0.0f; + for (i = 0; i < z->getSize(); ++i) { + gamma += z->getData()[i] * z->getData()[i]; + } + m_iIteration++; + } + + + // start iterations + for (int iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + + // w = A*p; + pForwardProjector->project(); + + // alpha = gamma/dot(w,w); + float32 tmp = 0; + for (i = 0; i < w->getSize(); ++i) { + tmp += w->getData()[i] * w->getData()[i]; + } + alpha = gamma / tmp; + + // x = x + alpha*p; + for (i = 0; i < m_pReconstruction->getSize(); ++i) { + m_pReconstruction->getData()[i] += alpha * p->getData()[i]; + } + + // r = r - alpha*w; + for (i = 0; i < r->getSize(); ++i) { + r->getData()[i] -= alpha * w->getData()[i]; + } + + // z = A'*r; + z->setData(0.0f); + pBackProjector->project(); + + // CHECKME: should these be here? + if (m_bUseMinConstraint) + z->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + z->clampMax(m_fMaxValue); + + // beta = 1/gamma; + beta = 1.0f / gamma; + + // gamma = dot(z,z); + gamma = 0; + for (i = 0; i < z->getSize(); ++i) { + gamma += z->getData()[i] * z->getData()[i]; + } + + // beta = gamma*beta; + beta *= gamma; + + // p = z + beta*p; + for (i = 0; i < z->getSize(); ++i) { + p->getData()[i] = z->getData()[i] + beta * p->getData()[i]; + } + + m_iIteration++; + } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ConeProjectionGeometry3D.cpp b/src/ConeProjectionGeometry3D.cpp new file mode 100644 index 0000000..129e675 --- /dev/null +++ b/src/ConeProjectionGeometry3D.cpp @@ -0,0 +1,228 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConeProjectionGeometry3D.h" + +#include <boost/lexical_cast.hpp> +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CConeProjectionGeometry3D::CConeProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_fOriginSourceDistance = 0.0f; + m_fOriginDetectorDistance = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CConeProjectionGeometry3D::CConeProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _fOriginSourceDistance, + _fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CConeProjectionGeometry3D::~CConeProjectionGeometry3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConeProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ConeProjectionGeometry3D", this, _cfg); + + // initialization of parent class + CProjectionGeometry3D::initialize(_cfg); + + // Required: DistanceOriginDetector + XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector"); + ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginDetector tag specified."); + m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginDetector"); + + // Required: DetectorOriginSource + node = _cfg.self->getSingleNode("DistanceOriginSource"); + ASTRA_CONFIG_CHECK(node, "ConeProjectionGeometry3D", "No DistanceOriginSource tag specified."); + m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginSource"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CConeProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + _initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles); + + m_fOriginSourceDistance = _fOriginSourceDistance; + m_fOriginDetectorDistance = _fOriginDetectorDistance; + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CConeProjectionGeometry3D::clone() const +{ + CConeProjectionGeometry3D* res = new CConeProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + res->m_fOriginSourceDistance = m_fOriginSourceDistance; + res->m_fOriginDetectorDistance = m_fOriginDetectorDistance; + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CConeProjectionGeometry3D::isEqual(const CProjectionGeometry3D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CConeProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false; + if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CConeProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "cone"); +} + +//---------------------------------------------------------------------------------------- +void CConeProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type", "cone"); + _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX); + _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); + _sNode->addChildNode("DistanceOriginDetector", m_fOriginDetectorDistance); + _sNode->addChildNode("DistanceOriginSource", m_fOriginSourceDistance); +} +//---------------------------------------------------------------------------------------- + +CVector3D CConeProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + float32 fSrcX = -m_fOriginSourceDistance; + float32 fSrcY = 0.0f; + float32 fSrcZ = 0.0f; + + float32 fDetX = m_fOriginDetectorDistance; + float32 fDetY = 0.0f; + float32 fDetZ = 0.0f; + + fDetY += indexToDetectorOffsetX(_iDetectorIndex); + fDetZ += indexToDetectorOffsetY(_iDetectorIndex); + + float32 angle = m_pfProjectionAngles[_iProjectionIndex]; + + #define ROTATE(name,alpha) do { float32 tX = f##name##X * cos(alpha) - f##name##Y * sin(alpha); f##name##Y = f##name##X * sin(alpha) + f##name##Y * cos(alpha); f##name##X = tX; } while(0) + + ROTATE(Src, angle); + ROTATE(Det, angle); + + #undef ROTATE + + CVector3D ret(fDetX - fSrcX, fDetY - fSrcY, fDetZ - fDetZ); + return ret; +} + +} // end namespace astra diff --git a/src/ConeVecProjectionGeometry3D.cpp b/src/ConeVecProjectionGeometry3D.cpp new file mode 100644 index 0000000..875a2c7 --- /dev/null +++ b/src/ConeVecProjectionGeometry3D.cpp @@ -0,0 +1,232 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConeVecProjectionGeometry3D.h" + +#include <cstring> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CConeVecProjectionGeometry3D::CConeVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles + ) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CConeVecProjectionGeometry3D::~CConeVecProjectionGeometry3D() +{ + delete[] m_pProjectionAngles; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConeVecProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ConeVecProjectionGeometry3D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry3D::initialize(_cfg); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorColCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "ConeVecProjectionGeometry3D", "No Vectors tag specified."); + vector<double> data = node->getContentNumericalArrayDouble(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ConeVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples."); + m_iProjectionAngleCount = data.size() / 12; + m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SConeProjection& p = m_pProjectionAngles[i]; + p.fSrcX = data[12*i + 0]; + p.fSrcY = data[12*i + 1]; + p.fSrcZ = data[12*i + 2]; + p.fDetUX = data[12*i + 6]; + p.fDetUY = data[12*i + 7]; + p.fDetUZ = data[12*i + 8]; + p.fDetVX = data[12*i + 9]; + p.fDetVY = data[12*i + 10]; + p.fDetVZ = data[12*i + 11]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX; + p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY; + p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ; + } + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CConeVecProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SConeProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CConeVecProjectionGeometry3D::clone() const +{ + CConeVecProjectionGeometry3D* res = new CConeVecProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pProjectionAngles = new SConeProjection[m_iProjectionAngleCount]; + memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CConeVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CConeProjectionGeometry3D + const CConeVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CConeVecProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CConeVecProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "cone3d_vec"); +} + +//---------------------------------------------------------------------------------------- +void CConeVecProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","cone3d_vec"); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + // TODO: + //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); +} + +CVector3D CConeVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + const SConeProjection& p = m_pProjectionAngles[_iProjectionIndex]; + int u = _iDetectorIndex % m_iDetectorColCount; + int v = _iDetectorIndex / m_iDetectorColCount; + + return CVector3D(p.fDetSX + (u+0.5)*p.fDetUX + (v+0.5)*p.fDetVX - p.fSrcX, p.fDetSY + (u+0.5)*p.fDetUY + (v+0.5)*p.fDetVY - p.fSrcY, p.fDetSZ + (u+0.5)*p.fDetUZ + (v+0.5)*p.fDetVZ - p.fSrcZ); +} + + +//---------------------------------------------------------------------------------------- + +bool CConeVecProjectionGeometry3D::_check() +{ + // TODO + return true; +} + +} // end namespace astra diff --git a/src/Config.cpp b/src/Config.cpp new file mode 100644 index 0000000..8c5cbf5 --- /dev/null +++ b/src/Config.cpp @@ -0,0 +1,166 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Config.h" + +// For explicit ConfigStackCheck instantiations +#include "astra/Algorithm.h" +#include "astra/VolumeGeometry2D.h" +#include "astra/VolumeGeometry3D.h" +#include "astra/ProjectionGeometry2D.h" +#include "astra/ProjectionGeometry3D.h" +#include "astra/Projector2D.h" +#include "astra/Projector3D.h" + +using namespace astra; +using namespace std; + +//----------------------------------------------------------------------------- +// default constructor +Config::Config() +{ + self = 0; +} + +//----------------------------------------------------------------------------- +// not so default constructor +Config::Config(XMLNode* _self) +{ + self = _self; +} + +Config::~Config() +{ + delete self; + self = 0; +} + +template <class T> +ConfigStackCheck<T>::ConfigStackCheck(const char *_name, T* _obj, const Config& _cfg) + : object(_obj), cfg(&_cfg), name(_name) +{ + assert(object); + assert(cfg); + if (!object->configCheckData) { + object->configCheckData = new ConfigCheckData; + object->configCheckData->parseDepth = 0; + } + + object->configCheckData->parseDepth++; +} + +template <class T> +ConfigStackCheck<T>::~ConfigStackCheck() +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + + + if (object->configCheckData->parseDepth == 1) { + // Entirely done with parsing this Config object + + if (object->isInitialized()) + stopParsing(); + + delete object->configCheckData; + object->configCheckData = 0; + } else { + object->configCheckData->parseDepth--; + } +} + + +// returns true if no unused nodes/options +template <class T> +bool ConfigStackCheck<T>::stopParsing() +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + + if (object->configCheckData->parseDepth > 1) + return true; + + // If this was the top-level parse function, check + + std::string errors; + + std::list<XMLNode*> nodes = cfg->self->getNodes(); + for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + { + std::string nodeName = (*i)->getName(); + + if (nodeName == "Option") { + nodeName = (*i)->getAttribute("key", ""); + if (object->configCheckData->parsedOptions.find(nodeName) == object->configCheckData->parsedOptions.end()) { + if (!errors.empty()) errors += ", "; + errors += nodeName; + } + } else { + if (object->configCheckData->parsedNodes.find(nodeName) == object->configCheckData->parsedNodes.end()) { + if (!errors.empty()) errors += ", "; + errors += nodeName; + } + } + } + for (std::list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + delete (*i); + nodes.clear(); + + if (!errors.empty()) { + cout << "Warning: " << name << ": unused configuration options: " << errors << std::endl; + return false; + } + + return true; +} + +template <class T> +void ConfigStackCheck<T>::markNodeParsed(const std::string& nodeName) +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + object->configCheckData->parsedNodes.insert(nodeName); +} + +template <class T> +void ConfigStackCheck<T>::markOptionParsed(const std::string& nodeName) +{ + assert(object->configCheckData); + assert(object->configCheckData->parseDepth > 0); + object->configCheckData->parsedOptions.insert(nodeName); +} + + +template class ConfigStackCheck<CAlgorithm>; +template class ConfigStackCheck<CProjectionGeometry2D>; +template class ConfigStackCheck<CProjectionGeometry3D>; +template class ConfigStackCheck<CVolumeGeometry2D>; +template class ConfigStackCheck<CVolumeGeometry3D>; +template class ConfigStackCheck<CProjector2D>; +template class ConfigStackCheck<CProjector3D>; + diff --git a/src/ConvexHullAlgorithm.cpp b/src/ConvexHullAlgorithm.cpp new file mode 100644 index 0000000..e769420 --- /dev/null +++ b/src/ConvexHullAlgorithm.cpp @@ -0,0 +1,239 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ConvexHullAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CConvexHullAlgorithm::type = "ConvexHull"; + +//---------------------------------------------------------------------------------------- +// Constructor +CConvexHullAlgorithm::CConvexHullAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CConvexHullAlgorithm::CConvexHullAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstructionMask) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstructionMask); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CConvexHullAlgorithm::~CConvexHullAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CConvexHullAlgorithm::_clear() +{ + m_bIsInitialized = false; + + m_pProjectionPixelWeight = NULL; + m_pReconstructionMask = NULL; + m_pSinogram = NULL; + + m_pProjector = NULL; + m_pDataProjector = NULL; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CConvexHullAlgorithm::clear() +{ + m_bIsInitialized = false; + + ASTRA_DELETE(m_pProjectionPixelWeight); + m_pReconstructionMask = NULL; + m_pSinogram = NULL; + + m_pProjector = NULL; + ASTRA_DELETE(m_pDataProjector); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CConvexHullAlgorithm::_check() +{ + ASTRA_CONFIG_CHECK(m_pReconstructionMask, "ConvexHull", "Invalid ReconstructionMask Object"); + ASTRA_CONFIG_CHECK(m_pReconstructionMask->isInitialized(), "ConvexHull", "Invalid ReconstructionMask Object"); + ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight, "ConvexHull", "Invalid ProjectionPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pProjectionPixelWeight->isInitialized(), "ConvexHull", "Invalid ProjectionPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pSinogram, "ConvexHull", "Invalid Sinogram Object"); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ConvexHull", "Invalid Sinogram Object"); + + ASTRA_CONFIG_CHECK(m_pDataProjector, "ConvexHull", "Invalid Data Projector Policy"); + ASTRA_CONFIG_CHECK(m_pProjector, "ConvexHull", "Invalid Projector Object"); + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ConvexHull", "Invalid Projector Object"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CConvexHullAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // reconstruction mask + node = _cfg.self->getSingleNode("ConvexHullDataId"); + ASTRA_CONFIG_CHECK(node, "ConvexHull", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CConvexHullAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstructionMask) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstructionMask = _pReconstructionMask; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CConvexHullAlgorithm::_init() +{ + // create data objects + m_pProjectionPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pProjectionPixelWeight->setData(0); + + // forward projection data projector + m_pDataProjector = dispatchDataProjector( + m_pProjector, + //SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + TotalPixelWeightBySinogramPolicy(m_pSinogram, m_pProjectionPixelWeight) // pixel weight * sinogram + ); +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CConvexHullAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CConvexHullAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CConvexHullAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_pReconstructionMask->setData(1.0f); + + // loop angles + for (int iProjection = 0; iProjection < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); ++iProjection) { + + m_pProjectionPixelWeight->setData(0.0f); + + // project + m_pDataProjector->projectSingleProjection(iProjection); + + // loop values and set to zero + for (int iPixel = 0; iPixel < m_pReconstructionMask->getSize(); ++iPixel) { + if (m_pProjectionPixelWeight->getData()[iPixel] == 0) { + m_pReconstructionMask->getData()[iPixel] = 0; + } + } + + } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CudaBackProjectionAlgorithm.cpp b/src/CudaBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..7d597b8 --- /dev/null +++ b/src/CudaBackProjectionAlgorithm.cpp @@ -0,0 +1,96 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaBackProjectionAlgorithm.h" + +#include "../cuda/2d/astra.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaBackProjectionAlgorithm::type = "BP_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaBackProjectionAlgorithm::CCudaBackProjectionAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaBackProjectionAlgorithm::~CCudaBackProjectionAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new BPalgo(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, 1, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new BPalgo(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaBackProjectionAlgorithm3D.cpp b/src/CudaBackProjectionAlgorithm3D.cpp new file mode 100644 index 0000000..b60adf1 --- /dev/null +++ b/src/CudaBackProjectionAlgorithm3D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaBackProjectionAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaBackProjectionAlgorithm3D::type = "BP3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaBackProjectionAlgorithm3D::CCudaBackProjectionAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaBackProjectionAlgorithm3D::~CCudaBackProjectionAlgorithm3D() +{ + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaBackProjectionAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "BP3D_CUDA", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaBackProjectionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaBackProjectionAlgorithm3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaBackProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaBackProjectionAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaBackProjectionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaBackProjectionAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + + const CProjectionGeometry3D* projgeom = pSinoMem->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *pReconMem->getGeometry(); + + if (conegeom) { + astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (par3dgeom) { + astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (parvec3dgeom) { + astraCudaPar3DBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else if (conevecgeom) { + astraCudaConeBP(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conevecgeom->getProjectionCount(), + conevecgeom->getDetectorColCount(), + conevecgeom->getDetectorRowCount(), + conevecgeom->getProjectionVectors(), + m_iGPUIndex, m_iVoxelSuperSampling); + } else { + ASTRA_ASSERT(false); + } + +} + + +} // namespace astra diff --git a/src/CudaCglsAlgorithm.cpp b/src/CudaCglsAlgorithm.cpp new file mode 100644 index 0000000..c408638 --- /dev/null +++ b/src/CudaCglsAlgorithm.cpp @@ -0,0 +1,98 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaCglsAlgorithm.h" + +#include "../cuda/2d/cgls.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaCglsAlgorithm::type = "CGLS_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaCglsAlgorithm::CCudaCglsAlgorithm() +{ + m_bIsInitialized = false; + CReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaCglsAlgorithm::~CCudaCglsAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaCglsAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::CGLS(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaCglsAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::CGLS(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaCglsAlgorithm3D.cpp b/src/CudaCglsAlgorithm3D.cpp new file mode 100644 index 0000000..07569a2 --- /dev/null +++ b/src/CudaCglsAlgorithm3D.cpp @@ -0,0 +1,314 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaCglsAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaCglsAlgorithm3D::type = "CGLS3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D() +{ + m_bIsInitialized = false; + m_pCgls = 0; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; + m_iDetectorSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaCglsAlgorithm3D::CCudaCglsAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaCglsAlgorithm3D::~CCudaCglsAlgorithm3D() +{ + delete m_pCgls; + m_pCgls = 0; + + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaCglsAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CGLS3D", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaCglsAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaCglsAlgorithm3D", this, _cfg); + + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_pCgls = new AstraCGLS3d(); + + m_bAstraCGLSInit = false; + + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaCglsAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_pCgls = new AstraCGLS3d; + + m_bAstraCGLSInit = false; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaCglsAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaCglsAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaCglsAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + bool ok = true; + + if (!m_bAstraCGLSInit) { + + ok &= m_pCgls->setGPUIndex(m_iGPUIndex); + + ok &= m_pCgls->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount()); +/* + unsigned int iProjAngles, + unsigned int iProjU, + unsigned int iProjV, + float fOriginSourceDistance, + float fOriginDetectorDistance, + float fDetUSize, + float fDetVSize, + const float *pfAngles) +*/ + fprintf(stderr, "01: %d\n", ok); + + if (conegeom) { + ok &= m_pCgls->setConeGeometry(conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles()); + } else if (parvec3dgeom) { + ok &= m_pCgls->setPar3DGeometry(parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors()); + } else if (conevec3dgeom) { + ok &= m_pCgls->setConeGeometry(conevec3dgeom->getProjectionCount(), + conevec3dgeom->getDetectorColCount(), + conevec3dgeom->getDetectorRowCount(), + conevec3dgeom->getProjectionVectors()); + } else { + ASTRA_ASSERT(false); + } + fprintf(stderr, "02: %d\n", ok); + + ok &= m_pCgls->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling); + + if (m_bUseReconstructionMask) + ok &= m_pCgls->enableVolumeMask(); +#if 0 + if (m_bUseSinogramMask) + ok &= m_pCgls->enableSinogramMask(); +#endif + + ASTRA_ASSERT(ok); + fprintf(stderr, "03: %d\n", ok); + + ok &= m_pCgls->init(); + fprintf(stderr, "04: %d\n", ok); + + ASTRA_ASSERT(ok); + + m_bAstraCGLSInit = true; + + } + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + + ok = m_pCgls->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount()); + + fprintf(stderr, "1: %d\n", ok); + ASTRA_ASSERT(ok); + + if (m_bUseReconstructionMask) { + CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask); + ASTRA_ASSERT(pRMaskMem); + ok &= m_pCgls->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount()); + } +#if 0 + if (m_bUseSinogramMask) { + CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask); + ASTRA_ASSERT(pSMaskMem); + ok &= m_pCgls->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount()); + } +#endif + fprintf(stderr, "2: %d\n", ok); + + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + ok &= m_pCgls->setStartReconstruction(pReconMem->getDataConst(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); + fprintf(stderr, "3: %d\n", ok); + +#if 0 + if (m_bUseMinConstraint) + ok &= m_pCgls->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pCgls->setMaxConstraint(m_fMaxValue); +#endif + fprintf(stderr, "4: %d\n", ok); + + ok &= m_pCgls->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + fprintf(stderr, "5: %d\n", ok); + + ok &= m_pCgls->getReconstruction(pReconMem->getData(), + volgeom.getGridColCount()); + fprintf(stderr, "6: %d\n", ok); + ASTRA_ASSERT(ok); + + +} +//---------------------------------------------------------------------------------------- +void CCudaCglsAlgorithm3D::signalAbort() +{ + if (m_bIsInitialized && m_pCgls) { + m_pCgls->signalAbort(); + } +} + +bool CCudaCglsAlgorithm3D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pCgls) + return false; + + _fNorm = m_pCgls->computeDiffNorm(); + + return true; +} + + + +} // namespace astra diff --git a/src/CudaDartMaskAlgorithm.cpp b/src/CudaDartMaskAlgorithm.cpp new file mode 100644 index 0000000..9c9b83f --- /dev/null +++ b/src/CudaDartMaskAlgorithm.cpp @@ -0,0 +1,166 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartMaskAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartMaskAlgorithm::type = "DARTMASK_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartMaskAlgorithm::CCudaDartMaskAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartMaskAlgorithm::~CCudaDartMaskAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartMaskAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSegmentation = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("SegmentationDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("MaskDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("MaskDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Connectivity + m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8); + CC.markOptionParsed("Connectivity"); + + // Option: Threshold + m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1); + CC.markOptionParsed("Threshold"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartMaskAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pSegmentation->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + astraCUDA::setGPUIndex(m_iGPUIndex); + astraCUDA::dartMask(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartMaskAlgorithm::_check() +{ + + // connectivity: 4 of 8 + + // gpuindex >= 0 + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartMaskAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartMaskAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartMaskAlgorithm3D.cpp b/src/CudaDartMaskAlgorithm3D.cpp new file mode 100644 index 0000000..7965587 --- /dev/null +++ b/src/CudaDartMaskAlgorithm3D.cpp @@ -0,0 +1,168 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartMaskAlgorithm3D.h" + +#include "../cuda/3d/darthelper3d.h" +#include "../cuda/3d/dims3d.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartMaskAlgorithm3D::type = "DARTMASK3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartMaskAlgorithm3D::CCudaDartMaskAlgorithm3D() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartMaskAlgorithm3D::~CCudaDartMaskAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartMaskAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("SegmentationDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No SegmentationDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSegmentation = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("SegmentationDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("MaskDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No MaskDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pMask = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("MaskDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Connectivity + m_iConn = (unsigned int)_cfg.self->getOptionNumerical("Connectivity", 8); + CC.markOptionParsed("Connectivity"); + + // Option: Threshold + m_iThreshold = (unsigned int)_cfg.self->getOptionNumerical("Threshold", 1); + CC.markOptionParsed("Threshold"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartMaskAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry3D& volgeom = *m_pSegmentation->getGeometry(); + astraCUDA3d::SDimensions3D dims; + dims.iVolX = volgeom.getGridColCount(); + dims.iVolY = volgeom.getGridRowCount(); + dims.iVolZ = volgeom.getGridSliceCount(); + + astraCUDA3d::setGPUIndex(m_iGPUIndex); + astraCUDA3d::dartMasking(m_pMask->getData(), m_pSegmentation->getDataConst(), m_iConn, m_iRadius, m_iThreshold, dims); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartMaskAlgorithm3D::_check() +{ + + // connectivity: 4 of 8 + + // gpuindex >= 0 + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartMaskAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartMaskAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartSmoothingAlgorithm.cpp b/src/CudaDartSmoothingAlgorithm.cpp new file mode 100644 index 0000000..91cde6d --- /dev/null +++ b/src/CudaDartSmoothingAlgorithm.cpp @@ -0,0 +1,158 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartSmoothingAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartSmoothingAlgorithm::type = "DARTSMOOTHING_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartSmoothingAlgorithm::CCudaDartSmoothingAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartSmoothingAlgorithm::~CCudaDartSmoothingAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartSmoothingAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("InDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pIn = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("InDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("OutDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pOut = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("OutDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Radius + m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f); + CC.markOptionParsed("Intensity"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartSmoothingAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pIn->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + astraCUDA::setGPUIndex(m_iGPUIndex); + + astraCUDA::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartSmoothingAlgorithm::_check() +{ + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartSmoothingAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartSmoothingAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDartSmoothingAlgorithm3D.cpp b/src/CudaDartSmoothingAlgorithm3D.cpp new file mode 100644 index 0000000..50ef847 --- /dev/null +++ b/src/CudaDartSmoothingAlgorithm3D.cpp @@ -0,0 +1,160 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDartSmoothingAlgorithm3D.h" + +#include "../cuda/3d/darthelper3d.h" +#include "../cuda/3d/dims3d.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDartSmoothingAlgorithm3D::type = "DARTSMOOTHING3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDartSmoothingAlgorithm3D::CCudaDartSmoothingAlgorithm3D() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDartSmoothingAlgorithm3D::~CCudaDartSmoothingAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDartSmoothingAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartSmoothingAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("InDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No InDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pIn = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("InDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("OutDataId"); + ASTRA_CONFIG_CHECK(node, "CudaDartMask", "No OutDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pOut = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("OutDataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Intensity + m_fB = (float)_cfg.self->getOptionNumerical("Intensity", 0.3f); + CC.markOptionParsed("Intensity"); + + // Option: Radius + m_iRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 1); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartSmoothingAlgorithm3D::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDartSmoothingAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry3D& volgeom = *m_pIn->getGeometry(); + astraCUDA3d::SDimensions3D dims; + dims.iVolX = volgeom.getGridColCount(); + dims.iVolY = volgeom.getGridRowCount(); + dims.iVolZ = volgeom.getGridSliceCount(); + + astraCUDA3d::setGPUIndex(m_iGPUIndex); + astraCUDA3d::dartSmoothing(m_pOut->getData(), m_pIn->getDataConst(), m_fB, m_iRadius, dims); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDartSmoothingAlgorithm3D::_check() +{ + // geometry of inData must match that of outData + + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDartSmoothingAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDartSmoothingAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaDataOperationAlgorithm.cpp b/src/CudaDataOperationAlgorithm.cpp new file mode 100644 index 0000000..ed2ac94 --- /dev/null +++ b/src/CudaDataOperationAlgorithm.cpp @@ -0,0 +1,208 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaDataOperationAlgorithm.h" + +#include "../cuda/2d/dataop.h" +#include "../cuda/2d/algo.h" +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/arith.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaDataOperationAlgorithm::type = "DataOperation_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaDataOperationAlgorithm::CCudaDataOperationAlgorithm() +{ + m_pMask = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaDataOperationAlgorithm::~CCudaDataOperationAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CCudaDataOperationAlgorithm", this, _cfg); + + // operation + XMLNode* node = _cfg.self->getSingleNode("Operation"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Operation tag specified."); + m_sOperation = node->getContent(); + m_sOperation.erase(std::remove(m_sOperation.begin(), m_sOperation.end(), ' '), m_sOperation.end()); + ASTRA_DELETE(node); + CC.markNodeParsed("Operation"); + + // data + node = _cfg.self->getSingleNode("DataId"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No DataId tag specified."); + vector<string> data = node->getContentArray(); + for (vector<string>::iterator it = data.begin(); it != data.end(); it++){ + int id = boost::lexical_cast<int>(*it); + m_pData.push_back(dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id))); + } + ASTRA_DELETE(node); + CC.markNodeParsed("DataId"); + + // scalar + node = _cfg.self->getSingleNode("Scalar"); + ASTRA_CONFIG_CHECK(node, "CCudaDataOperationAlgorithm", "No Scalar tag specified."); + m_fScalar = node->getContentNumericalArray(); + ASTRA_DELETE(node); + CC.markNodeParsed("Scalar"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + if (_cfg.self->hasOption("MaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MaskId")); + m_pMask = dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MaskId"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaDataOperationAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + astraCUDA::setGPUIndex(m_iGPUIndex); + + if (m_sOperation == "$1*s1" || m_sOperation == "$1.*s1") // data * scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + if (m_pMask == NULL) + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height); + else + astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), m_fScalar[0], width, height); + } + else if (m_sOperation == "$1/s1" || m_sOperation == "$1./s1") // data / scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + if (m_pMask == NULL) + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), 1.0f/m_fScalar[0], width, height); + else + astraCUDA::processVolCopy<astraCUDA::opMulMask,astraCUDA::VOL>(m_pData[0]->getData(), m_pMask->getDataConst(), 1.0f/m_fScalar[0], width, height); + } + else if (m_sOperation == "$1+s1") // data + scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_fScalar[0], width, height); + } + else if (m_sOperation == "$1-s1") // data - scalar + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), -m_fScalar[0], width, height); + } + else if (m_sOperation == "$1.*$2") // data .* data + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opMul,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height); + } + else if (m_sOperation == "$1+$2") // data + data + { + unsigned int width = m_pData[0]->getWidth(); + unsigned int height = m_pData[0]->getHeight(); + astraCUDA::processVolCopy<astraCUDA::opAdd,astraCUDA::VOL>(m_pData[0]->getData(), m_pData[1]->getDataConst(), width, height); + } + +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaDataOperationAlgorithm::_check() +{ + // s*: 1 data + 1 scalar + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaDataOperationAlgorithm::getInformation() +{ + map<string,boost::any> res; + // TODO: add PDART-specific options + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaDataOperationAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaEMAlgorithm.cpp b/src/CudaEMAlgorithm.cpp new file mode 100644 index 0000000..44dd0fd --- /dev/null +++ b/src/CudaEMAlgorithm.cpp @@ -0,0 +1,97 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaEMAlgorithm.h" + +#include "../cuda/2d/em.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaEMAlgorithm::type = "EM_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaEMAlgorithm::CCudaEMAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaEMAlgorithm::~CCudaEMAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaEMAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaEMAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::EM(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaEMAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::EM(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaFDKAlgorithm3D.cpp b/src/CudaFDKAlgorithm3D.cpp new file mode 100644 index 0000000..8f9e7b8 --- /dev/null +++ b/src/CudaFDKAlgorithm3D.cpp @@ -0,0 +1,192 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaFDKAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaFDKAlgorithm3D::type = "FDK_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaFDKAlgorithm3D::CCudaFDKAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaFDKAlgorithm3D::~CCudaFDKAlgorithm3D() +{ + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaFDKAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "CUDA_FDK", "Error in ReconstructionAlgorithm3D initialization"); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + ASTRA_CONFIG_CHECK(dynamic_cast<const CConeProjectionGeometry3D*>(projgeom), "CUDA_FDK", "Error setting FDK geometry"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaFDKAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaFDKAlgorithm3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_bShortScan = _cfg.self->getOptionBool("ShortScan", false); + CC.markOptionParsed("ShortScan"); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaFDKAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaFDKAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaFDKAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaFDKAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + ASTRA_ASSERT(conegeom); + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + + + bool ok = true; + + ok = astraCudaFDK(pReconMem->getData(), pSinoMem->getDataConst(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_bShortScan, m_iGPUIndex, m_iVoxelSuperSampling); + + ASTRA_ASSERT(ok); + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/CudaFilteredBackProjectionAlgorithm.cpp b/src/CudaFilteredBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..75a1534 --- /dev/null +++ b/src/CudaFilteredBackProjectionAlgorithm.cpp @@ -0,0 +1,442 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <astra/CudaFilteredBackProjectionAlgorithm.h> +#include <boost/lexical_cast.hpp> +#include <cstring> + +#include "astra/AstraObjectManager.h" + +#include <astra/Logger.h> + +using namespace std; +using namespace astra; + +string CCudaFilteredBackProjectionAlgorithm::type = "FBP_CUDA"; + +CCudaFilteredBackProjectionAlgorithm::CCudaFilteredBackProjectionAlgorithm() +{ + m_bIsInitialized = false; + CReconstructionAlgorithm2D::_clear(); + m_pFBP = 0; + m_pfFilter = NULL; + m_fFilterParameter = -1.0f; + m_fFilterD = 1.0f; +} + +CCudaFilteredBackProjectionAlgorithm::~CCudaFilteredBackProjectionAlgorithm() +{ + if(m_pfFilter != NULL) + { + delete [] m_pfFilter; + m_pfFilter = NULL; + } + + if(m_pFBP != NULL) + { + delete m_pFBP; + m_pFBP = NULL; + } +} + +bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaFilteredBackProjectionAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) + { + clear(); + } + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaFBP", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // filter type + node = _cfg.self->getSingleNode("FilterType"); + if(node != NULL) + { + m_eFilter = _convertStringToFilter(node->getContent().c_str()); + } + else + { + m_eFilter = FILTER_RAMLAK; + } + CC.markNodeParsed("FilterType"); + ASTRA_DELETE(node); + + // filter + node = _cfg.self->getSingleNode("FilterSinogramId"); + if(node != NULL) + { + int id = boost::lexical_cast<int>(node->getContent()); + const CFloat32ProjectionData2D * pFilterData = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + m_iFilterWidth = pFilterData->getGeometry()->getDetectorCount(); + int iFilterProjectionCount = pFilterData->getGeometry()->getProjectionAngleCount(); + + m_pfFilter = new float[m_iFilterWidth * iFilterProjectionCount]; + memcpy(m_pfFilter, pFilterData->getDataConst(), sizeof(float) * m_iFilterWidth * iFilterProjectionCount); + } + else + { + m_iFilterWidth = 0; + m_pfFilter = NULL; + } + CC.markNodeParsed("FilterSinogramId"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // filter parameter + node = _cfg.self->getSingleNode("FilterParameter"); + if(node != NULL) + { + float fParameter = boost::lexical_cast<float>(node->getContent()); + m_fFilterParameter = fParameter; + } + else + { + m_fFilterParameter = -1.0f; + } + CC.markNodeParsed("FilterParameter"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // D value + node = _cfg.self->getSingleNode("FilterD"); + if(node != NULL) + { + float fD = boost::lexical_cast<float>(node->getContent()); + m_fFilterD = fD; + } + else + { + m_fFilterD = 1.0f; + } + CC.markNodeParsed("FilterD"); // TODO: Only for some types! + ASTRA_DELETE(node); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + + // Pixel supersampling factor + m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1); + CC.markOptionParsed("PixelSuperSampling"); + + + m_pFBP = new AstraFBP; + m_bAstraFBPInit = false; + + // success + m_bIsInitialized = true; + return m_bIsInitialized; +} + +bool CCudaFilteredBackProjectionAlgorithm::initialize(CFloat32ProjectionData2D * _pSinogram, CFloat32VolumeData2D * _pReconstruction, E_FBPFILTER _eFilter, const float * _pfFilter /* = NULL */, int _iFilterWidth /* = 0 */, int _iGPUIndex /* = 0 */, float _fFilterParameter /* = -1.0f */) +{ + // if already initialized, clear first + if (m_bIsInitialized) + { + clear(); + } + + // required classes + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + m_iGPUIndex = _iGPUIndex; + + m_eFilter = _eFilter; + m_iFilterWidth = _iFilterWidth; + + // success + m_bIsInitialized = true; + + m_pFBP = new AstraFBP; + + m_bAstraFBPInit = false; + + if(_pfFilter != NULL) + { + int iFilterElementCount = 0; + + if((_eFilter != FILTER_SINOGRAM) && (_eFilter != FILTER_RSINOGRAM)) + { + iFilterElementCount = _iFilterWidth; + } + else + { + iFilterElementCount = m_pSinogram->getAngleCount(); + } + + m_pfFilter = new float[iFilterElementCount]; + memcpy(m_pfFilter, _pfFilter, iFilterElementCount * sizeof(float)); + } + else + { + m_pfFilter = NULL; + } + + m_fFilterParameter = _fFilterParameter; + + return m_bIsInitialized; +} + +void CCudaFilteredBackProjectionAlgorithm::run(int _iNrIterations /* = 0 */) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + if (!m_bAstraFBPInit) { + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + const CParallelProjectionGeometry2D& projgeom = *dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + bool ok = true; + + // TODO: off-center geometry, non-square pixels + ok &= m_pFBP->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getPixelLengthX()); + // TODO: off-center geometry + ok &= m_pFBP->setProjectionGeometry(projgeom.getProjectionAngleCount(), + projgeom.getDetectorCount(), + projgeom.getProjectionAngles(), + projgeom.getDetectorWidth()); + + ok &= m_pFBP->setPixelSuperSampling(m_iPixelSuperSampling); + + ASTRA_ASSERT(ok); + + const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset(); + if (pfTOffsets) + ok &= m_pFBP->setTOffsets(pfTOffsets); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->init(m_iGPUIndex); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->setSinogram(m_pSinogram->getDataConst(), projgeom.getDetectorCount()); + ASTRA_ASSERT(ok); + + ok &= m_pFBP->setFilter(m_eFilter, m_pfFilter, m_iFilterWidth, m_fFilterD, m_fFilterParameter); + ASTRA_ASSERT(ok); + + m_bAstraFBPInit = true; + } + + bool ok = m_pFBP->run(); + ASTRA_ASSERT(ok); + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + ok &= m_pFBP->getReconstruction(m_pReconstruction->getData(), volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); +} + +bool CCudaFilteredBackProjectionAlgorithm::check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pSinogram, "FBP_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "FBP_CUDA", "Invalid Reconstruction Data Object."); + + if((m_eFilter == FILTER_PROJECTION) || (m_eFilter == FILTER_SINOGRAM) || (m_eFilter == FILTER_RPROJECTION) || (m_eFilter == FILTER_RSINOGRAM)) + { + ASTRA_CONFIG_CHECK(m_pfFilter, "FBP_CUDA", "Invalid filter pointer."); + } + + // check initializations + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FBP_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "FBP_CUDA", "Reconstruction Data Object Not Initialized."); + + // check gpu index + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FBP_CUDA", "GPUIndex must be a non-negative integer."); + // check pixel supersampling + ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 0, "FBP_CUDA", "PixelSuperSampling must be a non-negative integer."); + + + // success + m_bIsInitialized = true; + return true; +} + +static int calcNextPowerOfTwo(int _iValue) +{ + int iOutput = 1; + + while(iOutput < _iValue) + { + iOutput *= 2; + } + + return iOutput; +} + +int CCudaFilteredBackProjectionAlgorithm::calcIdealRealFilterWidth(int _iDetectorCount) +{ + return calcNextPowerOfTwo(_iDetectorCount); +} + +int CCudaFilteredBackProjectionAlgorithm::calcIdealFourierFilterWidth(int _iDetectorCount) +{ + return (calcNextPowerOfTwo(_iDetectorCount) / 2 + 1); +} + +static bool stringCompareLowerCase(const char * _stringA, const char * _stringB) +{ + int iCmpReturn = 0; + +#ifdef _MSC_VER + iCmpReturn = _stricmp(_stringA, _stringB); +#else + iCmpReturn = strcasecmp(_stringA, _stringB); +#endif + + return (iCmpReturn == 0); +} + +E_FBPFILTER CCudaFilteredBackProjectionAlgorithm::_convertStringToFilter(const char * _filterType) +{ + E_FBPFILTER output = FILTER_NONE; + + if(stringCompareLowerCase(_filterType, "ram-lak")) + { + output = FILTER_RAMLAK; + } + else if(stringCompareLowerCase(_filterType, "shepp-logan")) + { + output = FILTER_SHEPPLOGAN; + } + else if(stringCompareLowerCase(_filterType, "cosine")) + { + output = FILTER_COSINE; + } + else if(stringCompareLowerCase(_filterType, "hamming")) + { + output = FILTER_HAMMING; + } + else if(stringCompareLowerCase(_filterType, "hann")) + { + output = FILTER_HANN; + } + else if(stringCompareLowerCase(_filterType, "none")) + { + output = FILTER_NONE; + } + else if(stringCompareLowerCase(_filterType, "tukey")) + { + output = FILTER_TUKEY; + } + else if(stringCompareLowerCase(_filterType, "lanczos")) + { + output = FILTER_LANCZOS; + } + else if(stringCompareLowerCase(_filterType, "triangular")) + { + output = FILTER_TRIANGULAR; + } + else if(stringCompareLowerCase(_filterType, "gaussian")) + { + output = FILTER_GAUSSIAN; + } + else if(stringCompareLowerCase(_filterType, "barlett-hann")) + { + output = FILTER_BARTLETTHANN; + } + else if(stringCompareLowerCase(_filterType, "blackman")) + { + output = FILTER_BLACKMAN; + } + else if(stringCompareLowerCase(_filterType, "nuttall")) + { + output = FILTER_NUTTALL; + } + else if(stringCompareLowerCase(_filterType, "blackman-harris")) + { + output = FILTER_BLACKMANHARRIS; + } + else if(stringCompareLowerCase(_filterType, "blackman-nuttall")) + { + output = FILTER_BLACKMANNUTTALL; + } + else if(stringCompareLowerCase(_filterType, "flat-top")) + { + output = FILTER_FLATTOP; + } + else if(stringCompareLowerCase(_filterType, "kaiser")) + { + output = FILTER_KAISER; + } + else if(stringCompareLowerCase(_filterType, "parzen")) + { + output = FILTER_PARZEN; + } + else if(stringCompareLowerCase(_filterType, "projection")) + { + output = FILTER_PROJECTION; + } + else if(stringCompareLowerCase(_filterType, "sinogram")) + { + output = FILTER_SINOGRAM; + } + else if(stringCompareLowerCase(_filterType, "rprojection")) + { + output = FILTER_RPROJECTION; + } + else if(stringCompareLowerCase(_filterType, "rsinogram")) + { + output = FILTER_RSINOGRAM; + } + else + { + cerr << "Failed to convert \"" << _filterType << "\" into a filter." << endl; + } + + return output; +} + +void CCudaFilteredBackProjectionAlgorithm::testGenFilter(E_FBPFILTER _eFilter, float _fD, int _iProjectionCount, cufftComplex * _pFilter, int _iFFTRealDetectorCount, int _iFFTFourierDetectorCount) +{ + genFilter(_eFilter, _fD, _iProjectionCount, _pFilter, _iFFTRealDetectorCount, _iFFTFourierDetectorCount); +} + +int CCudaFilteredBackProjectionAlgorithm::getGPUCount() +{ + return 0; +} diff --git a/src/CudaForwardProjectionAlgorithm.cpp b/src/CudaForwardProjectionAlgorithm.cpp new file mode 100644 index 0000000..965c4af --- /dev/null +++ b/src/CudaForwardProjectionAlgorithm.cpp @@ -0,0 +1,276 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaForwardProjectionAlgorithm.h" + +#ifdef ASTRA_CUDA + +#include "../cuda/2d/astra.h" + +#include <driver_types.h> +#include <cuda_runtime_api.h> + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/CudaProjector2D.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaForwardProjectionAlgorithm::type = "FP_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaForwardProjectionAlgorithm::CCudaForwardProjectionAlgorithm() +{ + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaForwardProjectionAlgorithm::~CCudaForwardProjectionAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaForwardProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm", this, _cfg); + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // volume data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "FP_CUDA", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeDataId"); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Detector supersampling factor + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + + // This isn't used yet, but passing it is not something to warn about + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + CProjector2D *projector = CProjector2DManager::getSingleton().get(id); + if (!dynamic_cast<CCudaProjector2D*>(projector)) { + cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl; + } + delete node; + } + CC.markNodeParsed("ProjectorId"); + + + + // return success + return check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaForwardProjectionAlgorithm::initialize(CProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram, + int _iGPUindex, int _iDetectorSuperSampling) +{ + // store classes + //m_pProjectionGeometry = _pProjectionGeometry; + //m_pReconstructionGeometry = _pReconstructionGeometry; + m_pVolume = _pVolume; + m_pSinogram = _pSinogram; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iGPUIndex = _iGPUindex; + + // return success + return check(); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaForwardProjectionAlgorithm::check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pSinogram, "FP_CUDA", "No valid projection data object found."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "FP_CUDA", "Projection data not initialized."); + ASTRA_CONFIG_CHECK(m_pVolume, "FP_CUDA", "No valid volume data object found."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP_CUDA", "Volume data not initialized."); + + // check restrictions + //int iImageSideBlocks = m_pReconstructionGeometry->getGridColCount() / G_BLOCKIMAGESIZE; + //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getWidth(), "FP_CUDA", "Volume Width must be a multiple of G_BLOCKIMAGESIZE"); + //ASTRA_CONFIG_CHECK((iImageSideBlocks * G_BLOCKIMAGESIZE) == m_pVolume->getHeight(), "FP_CUDA", "Volume Height must be a multiple of G_BLOCKIMAGESIZE"); + //ASTRA_CONFIG_CHECK(m_pProjectionGeometry->getDetectorCount() == (m_pVolume->getWidth() * 3 / 2), "SIRT_CUDA", "Number of detectors must be 1.5 times the width of the image"); + + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP_CUDA", "GPUIndex must be a non-negative integer."); + + // success + m_bIsInitialized = true; + return true; +} + +void CCudaForwardProjectionAlgorithm::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaForwardProjectionAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["VolumeDataId"] = getInformation("VolumeDataId"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaForwardProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Run +void CCudaForwardProjectionAlgorithm::run(int) +{ + // check initialized + assert(m_bIsInitialized); + + CVolumeGeometry2D* pVolGeom = m_pVolume->getGeometry(); + const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + bool ok = false; + if (parProjGeom) { + ok = astraCudaFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + parProjGeom->getProjectionAngleCount(), + parProjGeom->getDetectorCount(), + parProjGeom->getProjectionAngles(), + parProjGeom->getExtraDetectorOffset(), parProjGeom->getDetectorWidth() / pVolGeom->getPixelLengthX(), + m_iDetectorSuperSampling, m_iGPUIndex); + + } else if (fanProjGeom) { + + ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + fanProjGeom->getProjectionAngleCount(), + fanProjGeom->getDetectorCount(), + fanProjGeom->getProjectionAngles(), + fanProjGeom->getOriginSourceDistance(), + fanProjGeom->getOriginDetectorDistance(), + pVolGeom->getPixelLengthX(), + fanProjGeom->getDetectorWidth(), + m_iDetectorSuperSampling, m_iGPUIndex); + + } else if (fanVecProjGeom) { + + // Rescale projs to fPixelSize == 1 + float fPixelSize = pVolGeom->getPixelLengthX(); + const astraCUDA::SFanProjection* projs; + projs = fanVecProjGeom->getProjectionVectors(); + + astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[fanVecProjGeom->getProjectionAngleCount()]; +#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0) + for (unsigned int i = 0; i < fanVecProjGeom->getProjectionAngleCount(); ++i) { + SCALE(Src,i,1.0f/fPixelSize); + SCALE(DetS,i,1.0f/fPixelSize); + SCALE(DetU,i,1.0f/fPixelSize); + } + + + ok = astraCudaFanFP(m_pVolume->getDataConst(), m_pSinogram->getData(), + pVolGeom->getGridColCount(), pVolGeom->getGridRowCount(), + fanVecProjGeom->getProjectionAngleCount(), + fanVecProjGeom->getDetectorCount(), + scaledProjs, + /* 1.0f / pVolGeom->getPixelLengthX(), */ + m_iDetectorSuperSampling, m_iGPUIndex); + + delete[] scaledProjs; + + } else { + + ASTRA_ASSERT(false); + + } + + ASTRA_ASSERT(ok); + +} + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaForwardProjectionAlgorithm3D.cpp b/src/CudaForwardProjectionAlgorithm3D.cpp new file mode 100644 index 0000000..e9289f1 --- /dev/null +++ b/src/CudaForwardProjectionAlgorithm3D.cpp @@ -0,0 +1,311 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaForwardProjectionAlgorithm3D.h" + +#ifdef ASTRA_CUDA + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/CudaProjector3D.h" +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaForwardProjectionAlgorithm3D::type = "FP3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaForwardProjectionAlgorithm3D::CCudaForwardProjectionAlgorithm3D() +{ + m_bIsInitialized = false; + m_iGPUIndex = 0; + m_iDetectorSuperSampling = 1; + m_pProjector = 0; + m_pProjections = 0; + m_pVolume = 0; + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaForwardProjectionAlgorithm3D::~CCudaForwardProjectionAlgorithm3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaForwardProjectionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaForwardProjectionAlgorithm3D", this, _cfg); + + XMLNode* node; + int id; + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pProjections = dynamic_cast<CFloat32ProjectionData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "CudaForwardProjection3D", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData3DMemory*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeDataId"); + + // optional: projector + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector3DManager::getSingleton().get(id); + ASTRA_DELETE(node); + } else { + m_pProjector = 0; // TODO: or manually construct default projector? + } + CC.markNodeParsed("ProjectorId"); + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + // success + m_bIsInitialized = check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + + +bool CCudaForwardProjectionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjections, + CFloat32VolumeData3DMemory* _pVolume, + int _iGPUindex, int _iDetectorSuperSampling) +{ + m_pProjector = _pProjector; + + // required classes + m_pProjections = _pProjections; + m_pVolume = _pVolume; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iGPUIndex = _iGPUindex; + + // success + m_bIsInitialized = check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaForwardProjectionAlgorithm3D::check() +{ + // check pointers + //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pProjections, "FP3D_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pVolume, "FP3D_CUDA", "Invalid Volume Data Object."); + + // check initializations + //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pProjections->isInitialized(), "FP3D_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "FP3D_CUDA", "Volume Data Object Not Initialized."); + + ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "FP3D_CUDA", "DetectorSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "FP3D_CUDA", "GPUIndex must be a non-negative integer."); + + // check compatibility between projector and data classes +// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector."); +// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector."); + + // todo: turn some of these back on + +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized."); + + // check dimensions + //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + + // check restrictions + // TODO: check restrictions built into cuda code + + // success + m_bIsInitialized = true; + return true; +} + + +void CCudaForwardProjectionAlgorithm3D::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaForwardProjectionAlgorithm3D::getInformation() +{ + map<string,boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["VolumeGeometry"] = getInformation("VolumeGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["VolumeDataId"] = getInformation("VolumeDataId"); + res["GPUindex"] = getInformation("GPUindex"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaForwardProjectionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + // TODO: store these so we can return them? + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "VolumeGeometry") { return string("not implemented"); } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pProjections); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "VolumeDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +} + +//---------------------------------------------------------------------------------------- +// Run +void CCudaForwardProjectionAlgorithm3D::run(int) +{ + // check initialized + assert(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pProjections->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevecgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pVolume->getGeometry(); + + Cuda3DProjectionKernel projKernel = ker3d_default; + if (m_pProjector) { + CCudaProjector3D* projector = dynamic_cast<CCudaProjector3D*>(m_pProjector); + projKernel = projector->getProjectionKernel(); + } + + if (conegeom) { + astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles(), + m_iGPUIndex, m_iDetectorSuperSampling); + } else if (par3dgeom) { + astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles(), + m_iGPUIndex, m_iDetectorSuperSampling, + projKernel); + } else if (parvec3dgeom) { + astraCudaPar3DFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors(), + m_iGPUIndex, m_iDetectorSuperSampling, + projKernel); + } else if (conevecgeom) { + astraCudaConeFP(m_pVolume->getDataConst(), m_pProjections->getData(), + volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount(), + conevecgeom->getProjectionCount(), + conevecgeom->getDetectorColCount(), + conevecgeom->getDetectorRowCount(), + conevecgeom->getProjectionVectors(), + m_iGPUIndex, m_iDetectorSuperSampling); + } else { + ASTRA_ASSERT(false); + } + +} + + +} + +#endif diff --git a/src/CudaProjector2D.cpp b/src/CudaProjector2D.cpp new file mode 100644 index 0000000..731a3e1 --- /dev/null +++ b/src/CudaProjector2D.cpp @@ -0,0 +1,122 @@ +/* +----------------------------------------------------------------------- +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("ASTRA-Toolbox") + +Copyright: IBBT-Vision Lab, University of Antwerp +Contact: mailto:wim.vanaarle@ua.ac.be +Website: http://astra.ua.ac.be +----------------------------------------------------------------------- +$Id$ +*/ +#include "astra/CudaProjector2D.h" + + +namespace astra +{ + +// type of the projector, needed to register with CProjectorFactory +std::string CCudaProjector2D::type = "cuda"; + + +//---------------------------------------------------------------------------------------- +// Default constructor +CCudaProjector2D::CCudaProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaProjector2D::~CCudaProjector2D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CCudaProjector2D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; + + m_projectionKernel = ker2d_default; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CCudaProjector2D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaProjector2D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector2D", "ProjectionGeometry2D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector2D", "ProjectionGeometry2D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector2D", "VolumeGeometry2D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector2D", "VolumeGeometry2D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CCudaProjector2D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CProjector2D> CC("CudaProjector2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // TODO: Check the projection geometry is a supported type + + XMLNode* node = _cfg.self->getSingleNode("ProjectionKernel"); + m_projectionKernel = ker2d_default; + if (node) { + std::string sProjKernel = node->getContent(); + + if (sProjKernel == "default") { + + } else { + return false; + } + } + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionKernel"); + + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +/* +bool CProjector2D::initialize(astra::CProjectionGeometry2D *, astra::CVolumeGeometry2D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +std::string CCudaProjector2D::description() const +{ + return ""; +} + +} // end namespace diff --git a/src/CudaProjector3D.cpp b/src/CudaProjector3D.cpp new file mode 100644 index 0000000..4687825 --- /dev/null +++ b/src/CudaProjector3D.cpp @@ -0,0 +1,153 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaProjector3D.h" + + +namespace astra +{ + +// type of the projector, needed to register with CProjectorFactory +std::string CCudaProjector3D::type = "cuda3d"; + + +//---------------------------------------------------------------------------------------- +// Default constructor +CCudaProjector3D::CCudaProjector3D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaProjector3D::~CCudaProjector3D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CCudaProjector3D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; + + m_projectionKernel = ker3d_default; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CCudaProjector3D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaProjector3D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "CudaProjector3D", "ProjectionGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "CudaProjector3D", "ProjectionGeometry3D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "CudaProjector3D", "VolumeGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "CudaProjector3D", "VolumeGeometry3D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CCudaProjector3D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CProjector3D> CC("CudaProjector3D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector3D::initialize(_cfg)) { + return false; + } + + // TODO: These should go to the parent. + + // ProjectionGeometry + XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry"); + // TODO: Implement + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionGeometry"); + + // ReconstructionGeometry + node = _cfg.self->getSingleNode("VolumeGeometry"); + // TODO: Implement + ASTRA_DELETE(node); + CC.markNodeParsed("VolumeGeometry"); + + node = _cfg.self->getSingleNode("ProjectionKernel"); + m_projectionKernel = ker3d_default; + if (node) { + std::string sProjKernel = node->getContent(); + + if (sProjKernel == "default") { + + } else if (sProjKernel == "sum_square_weights") { + m_projectionKernel = ker3d_sum_square_weights; + } else { + return false; + } + } + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionKernel"); + + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +/* +bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +std::string CCudaProjector3D::description() const +{ + return ""; +} + +} // end namespace diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp new file mode 100644 index 0000000..d567158 --- /dev/null +++ b/src/CudaReconstructionAlgorithm2D.cpp @@ -0,0 +1,518 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaReconstructionAlgorithm2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/CudaProjector2D.h" + +#include "../cuda/2d/algo.h" + +#include <ctime> + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaReconstructionAlgorithm2D::CCudaReconstructionAlgorithm2D() +{ + _clear(); +} + + + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaReconstructionAlgorithm2D::~CCudaReconstructionAlgorithm2D() +{ + delete m_pAlgo; + m_pAlgo = 0; + m_bAlgoInit = false; +} + +void CCudaReconstructionAlgorithm2D::clear() +{ + delete m_pAlgo; + _clear(); +} + +void CCudaReconstructionAlgorithm2D::_clear() +{ + m_bIsInitialized = false; + m_pAlgo = 0; + m_bAlgoInit = false; + CReconstructionAlgorithm2D::_clear(); + + m_iGPUIndex = 0; + m_iDetectorSuperSampling = 1; + m_iPixelSuperSampling = 1; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaReconstructionAlgorithm2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaReconstructionAlgorithm2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // sinogram data + XMLNode* node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ProjectionDataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "CudaSirt2", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Detector supersampling factor + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + + // Pixel supersampling factor + m_iPixelSuperSampling = (int)_cfg.self->getOptionNumerical("PixelSuperSampling", 1); + CC.markOptionParsed("PixelSuperSampling"); + + + // This isn't used yet, but passing it is not something to warn about + node = _cfg.self->getSingleNode("ProjectorId"); + if (node) { + id = boost::lexical_cast<int>(node->getContent()); + CProjector2D *projector = CProjector2DManager::getSingleton().get(id); + if (!dynamic_cast<CCudaProjector2D*>(projector)) { + cout << "Warning: non-CUDA Projector2D passed to FP_CUDA" << std::endl; + } + delete node; + } + CC.markNodeParsed("ProjectorId"); + + + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + return initialize(_pProjector, _pSinogram, _pReconstruction, 0, 1); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, + int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + m_pProjector = 0; + + // required classes + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_iDetectorSuperSampling = _iDetectorSuperSampling; + m_iPixelSuperSampling = _iPixelSuperSampling; + m_iGPUIndex = _iGPUindex; + + return _check(); +} + + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaReconstructionAlgorithm2D::_check() +{ + // TODO: CLEAN UP + + + // check pointers + //ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "SIRT_CUDA", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "SIRT_CUDA", "Invalid Reconstruction Data Object."); + + // check initializations + //ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "SIRT_CUDA", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "SIRT_CUDA", "Reconstruction Data Object Not Initialized."); + + ASTRA_CONFIG_CHECK(m_iDetectorSuperSampling >= 1, "SIRT_CUDA", "DetectorSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 1, "SIRT_CUDA", "PixelSuperSampling must be a positive integer."); + ASTRA_CONFIG_CHECK(m_iGPUIndex >= 0, "SIRT_CUDA", "GPUIndex must be a non-negative integer."); + + // check compatibility between projector and data classes +// ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "SIRT_CUDA", "Projection Data not compatible with the specified Projector."); +// ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "SIRT_CUDA", "Reconstruction Data not compatible with the specified Projector."); + + // todo: turn some of these back on + +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "SIRT_CUDA", "ProjectionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SIRT_CUDA", "ProjectionGeometry not initialized."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry, "SIRT_CUDA", "ReconstructionGeometry not specified."); +// ASTRA_CONFIG_CHECK(m_pReconstructionGeometry->isInitialized(), "SIRT_CUDA", "ReconstructionGeometry not initialized."); + + // check dimensions + //ASTRA_CONFIG_CHECK(m_pSinogram->getAngleCount() == m_pProjectionGeometry->getProjectionAngleCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pSinogram->getDetectorCount() == m_pProjectionGeometry->getDetectorCount(), "SIRT_CUDA", "Sinogram data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getWidth() == m_pReconstructionGeometry->getGridColCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + //ASTRA_CONFIG_CHECK(m_pReconstruction->getHeight() == m_pReconstructionGeometry->getGridRowCount(), "SIRT_CUDA", "Reconstruction data object size mismatch."); + + // check restrictions + // TODO: check restrictions built into cuda code + + + // success + m_bIsInitialized = true; + return true; +} + +void CCudaReconstructionAlgorithm2D::setGPUIndex(int _iGPUIndex) +{ + m_iGPUIndex = _iGPUIndex; +} + + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaReconstructionAlgorithm2D::getInformation() +{ + // TODO: Verify and clean up + + map<string,boost::any> res; + res["ProjectionGeometry"] = getInformation("ProjectionGeometry"); + res["ReconstructionGeometry"] = getInformation("ReconstructionGeometry"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + res["GPUindex"] = getInformation("GPUindex"); + res["DetectorSuperSampling"] = getInformation("DetectorSuperSampling"); + res["PixelSuperSampling"] = getInformation("PixelSuperSampling"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaReconstructionAlgorithm2D::getInformation(std::string _sIdentifier) +{ + // TODO: Verify and clean up + + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + + // TODO: store these so we can return them? + if (_sIdentifier == "ProjectionGeometry") { return string("not implemented"); } + if (_sIdentifier == "ReconstructionGeometry") { return string("not implemented"); } + if (_sIdentifier == "GPUindex") { return m_iGPUIndex; } + if (_sIdentifier == "DetectorSuperSampling") { return m_iDetectorSuperSampling; } + if (_sIdentifier == "PixelSuperSampling") { return m_iPixelSuperSampling; } + + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CReconstructionAlgorithm2D::getInformation(_sIdentifier); +} + +bool CCudaReconstructionAlgorithm2D::setupGeometry() +{ + ASTRA_ASSERT(m_bIsInitialized); + ASTRA_ASSERT(!m_bAlgoInit); + + bool ok; + + // TODO: Probably not the best place for this... + ok = m_pAlgo->setGPUIndex(m_iGPUIndex); + if (!ok) return false; + + astraCUDA::SDimensions dims; + + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + + // TODO: off-center geometry, non-square pixels + dims.iVolWidth = volgeom.getGridColCount(); + dims.iVolHeight = volgeom.getGridRowCount(); + float fPixelSize = volgeom.getPixelLengthX(); + + dims.iRaysPerDet = m_iDetectorSuperSampling; + dims.iRaysPerPixelDim = m_iPixelSuperSampling; + + + const CParallelProjectionGeometry2D* parProjGeom = dynamic_cast<CParallelProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatProjectionGeometry2D* fanProjGeom = dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pSinogram->getGeometry()); + const CFanFlatVecProjectionGeometry2D* fanVecProjGeom = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pSinogram->getGeometry()); + + if (parProjGeom) { + + dims.iProjAngles = parProjGeom->getProjectionAngleCount(); + dims.iProjDets = parProjGeom->getDetectorCount(); + dims.fDetScale = parProjGeom->getDetectorWidth() / fPixelSize; + + ok = m_pAlgo->setGeometry(dims, parProjGeom->getProjectionAngles()); + + } else if (fanProjGeom) { + + dims.iProjAngles = fanProjGeom->getProjectionAngleCount(); + dims.iProjDets = fanProjGeom->getDetectorCount(); + dims.fDetScale = fanProjGeom->getDetectorWidth() / fPixelSize; + float fOriginSourceDistance = fanProjGeom->getOriginSourceDistance(); + float fOriginDetectorDistance = fanProjGeom->getOriginDetectorDistance(); + + const float* angles = fanProjGeom->getProjectionAngles(); + + astraCUDA::SFanProjection* projs; + projs = new astraCUDA::SFanProjection[dims.iProjAngles]; + + float fSrcX0 = 0.0f; + float fSrcY0 = -fOriginSourceDistance / fPixelSize; + float fDetUX0 = dims.fDetScale; + float fDetUY0 = 0.0f; + float fDetSX0 = dims.iProjDets * fDetUX0 / -2.0f; + float fDetSY0 = fOriginDetectorDistance / fPixelSize; + +#define ROTATE0(name,i,alpha) do { projs[i].f##name##X = f##name##X0 * cos(alpha) - f##name##Y0 * sin(alpha); projs[i].f##name##Y = f##name##X0 * sin(alpha) + f##name##Y0 * cos(alpha); } while(0) + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + ROTATE0(Src, i, angles[i]); + ROTATE0(DetS, i, angles[i]); + ROTATE0(DetU, i, angles[i]); + } + +#undef ROTATE0 + + ok = m_pAlgo->setFanGeometry(dims, projs); + delete[] projs; + + } else if (fanVecProjGeom) { + + dims.iProjAngles = fanVecProjGeom->getProjectionAngleCount(); + dims.iProjDets = fanVecProjGeom->getDetectorCount(); + dims.fDetScale = fanVecProjGeom->getDetectorWidth() / fPixelSize; + + const astraCUDA::SFanProjection* projs; + projs = fanVecProjGeom->getProjectionVectors(); + + // Rescale projs to fPixelSize == 1 + + astraCUDA::SFanProjection* scaledProjs = new astraCUDA::SFanProjection[dims.iProjAngles]; +#define SCALE(name,i,alpha) do { scaledProjs[i].f##name##X = projs[i].f##name##X * alpha; scaledProjs[i].f##name##Y = projs[i].f##name##Y * alpha; } while (0) + for (unsigned int i = 0; i < dims.iProjAngles; ++i) { + SCALE(Src,i,1.0f/fPixelSize); + SCALE(DetS,i,1.0f/fPixelSize); + SCALE(DetU,i,1.0f/fPixelSize); + } + + ok = m_pAlgo->setFanGeometry(dims, scaledProjs); + + delete[] scaledProjs; + + } else { + + ASTRA_ASSERT(false); + + } + if (!ok) return false; + + + if (m_bUseReconstructionMask) + ok &= m_pAlgo->enableVolumeMask(); + if (!ok) return false; + if (m_bUseSinogramMask) + ok &= m_pAlgo->enableSinogramMask(); + if (!ok) return false; + + const float *pfTOffsets = m_pSinogram->getGeometry()->getExtraDetectorOffset(); + if (pfTOffsets) + ok &= m_pAlgo->setTOffsets(pfTOffsets); + if (!ok) return false; + + ok &= m_pAlgo->init(); + if (!ok) return false; + + + return true; +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaReconstructionAlgorithm2D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + bool ok = true; + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + + if (!m_bAlgoInit) { + + ok = setupGeometry(); + ASTRA_ASSERT(ok); + + ok = m_pAlgo->allocateBuffers(); + ASTRA_ASSERT(ok); + + m_bAlgoInit = true; + } + + float fPixelSize = volgeom.getPixelLengthX(); + float fSinogramScale = 1.0f/(fPixelSize*fPixelSize); + + ok = m_pAlgo->copyDataToGPU(m_pSinogram->getDataConst(), m_pSinogram->getGeometry()->getDetectorCount(), fSinogramScale, + m_pReconstruction->getDataConst(), volgeom.getGridColCount(), + m_bUseReconstructionMask ? m_pReconstructionMask->getDataConst() : 0, volgeom.getGridColCount(), + m_bUseSinogramMask ? m_pSinogramMask->getDataConst() : 0, m_pSinogram->getGeometry()->getDetectorCount()); + + ASTRA_ASSERT(ok); + + if (m_bUseMinConstraint) + ok &= m_pAlgo->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pAlgo->setMaxConstraint(m_fMaxValue); + + ok &= m_pAlgo->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + + ok &= m_pAlgo->getReconstruction(m_pReconstruction->getData(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); +} + +void CCudaReconstructionAlgorithm2D::signalAbort() +{ + if (m_bIsInitialized && m_pAlgo) { + m_pAlgo->signalAbort(); + } +} + +bool CCudaReconstructionAlgorithm2D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pAlgo) + return false; + + _fNorm = m_pAlgo->computeDiffNorm(); + + return true; +} + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaRoiSelectAlgorithm.cpp b/src/CudaRoiSelectAlgorithm.cpp new file mode 100644 index 0000000..f835c59 --- /dev/null +++ b/src/CudaRoiSelectAlgorithm.cpp @@ -0,0 +1,149 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaRoiSelectAlgorithm.h" + +#include "../cuda/2d/darthelper.h" +#include "../cuda/2d/algo.h" + +#include "astra/AstraObjectManager.h" +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaRoiSelectAlgorithm::type = "RoiSelect_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaRoiSelectAlgorithm::CCudaRoiSelectAlgorithm() +{ + m_fRadius = 0.0f; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaRoiSelectAlgorithm::~CCudaRoiSelectAlgorithm() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaRoiSelectAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaDartMaskAlgorithm", this, _cfg); + + // reconstruction data + XMLNode* node = _cfg.self->getSingleNode("DataId"); + ASTRA_CONFIG_CHECK(node, "CudaRoiSelect", "No DataId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pData = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("DataId"); + + // Option: GPU number + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("GPUindex"); + if (!_cfg.self->hasOption("GPUindex")) + CC.markOptionParsed("GPUIndex"); + + // Option: Radius + m_fRadius = (unsigned int)_cfg.self->getOptionNumerical("Radius", 0.0f); + CC.markOptionParsed("Radius"); + + _check(); + + if (!m_bIsInitialized) + return false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +//bool CCudaDartMaskAlgorithm::initialize(CFloat32VolumeData2D* _pSegmentation, int _iConn) +//{ +// return false; +//} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaRoiSelectAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CVolumeGeometry2D& volgeom = *m_pData->getGeometry(); + unsigned int width = volgeom.getGridColCount(); + unsigned int height = volgeom.getGridRowCount(); + + if (m_fRadius == 0){ + m_fRadius = (width < height) ? width : height; + } + + astraCUDA::setGPUIndex(m_iGPUIndex); + astraCUDA::roiSelect(m_pData->getData(), m_fRadius, width, height); +} + +//---------------------------------------------------------------------------------------- +// Check +bool CCudaRoiSelectAlgorithm::_check() +{ + + // success + m_bIsInitialized = true; + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaRoiSelectAlgorithm::getInformation() +{ + map<string,boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +} + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaRoiSelectAlgorithm::getInformation(std::string _sIdentifier) +{ + return NULL; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSartAlgorithm.cpp b/src/CudaSartAlgorithm.cpp new file mode 100644 index 0000000..610793f --- /dev/null +++ b/src/CudaSartAlgorithm.cpp @@ -0,0 +1,136 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaSartAlgorithm.h" + +#include "../cuda/2d/sart.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSartAlgorithm::type = "SART_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSartAlgorithm::CCudaSartAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSartAlgorithm::~CCudaSartAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSartAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSartAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + astraCUDA::SART *sart = new astraCUDA::SART(); + + m_pAlgo = sart; + m_bAlgoInit = false; + + // projection order + int projectionCount = m_pSinogram->getGeometry()->getProjectionAngleCount(); + int* projectionOrder = NULL; + string projOrder = _cfg.self->getOption("ProjectionOrder", "random"); + CC.markOptionParsed("ProjectionOrder"); + if (projOrder == "sequential") { + projectionOrder = new int[projectionCount]; + for (int i = 0; i < projectionCount; i++) { + projectionOrder[i] = i; + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + } else if (projOrder == "random") { + projectionOrder = new int[projectionCount]; + for (int i = 0; i < projectionCount; i++) { + projectionOrder[i] = i; + } + for (int i = 0; i < projectionCount-1; i++) { + int k = (rand() % (projectionCount - i)); + int t = projectionOrder[i]; + projectionOrder[i] = projectionOrder[i + k]; + projectionOrder[i + k] = t; + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + } else if (projOrder == "custom") { + vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList"); + projectionOrder = new int[projOrderList.size()]; + for (int i = 0; i < projOrderList.size(); i++) { + projectionOrder[i] = static_cast<int>(projOrderList[i]); + } + sart->setProjectionOrder(projectionOrder, projectionCount); + delete[] projectionOrder; + CC.markOptionParsed("ProjectionOrderList"); + } + + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, 1); + + if (!m_bIsInitialized) + return false; + + m_pAlgo = new astraCUDA::SART(); + m_bAlgoInit = false; + + return true; +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSirtAlgorithm.cpp b/src/CudaSirtAlgorithm.cpp new file mode 100644 index 0000000..a2a30eb --- /dev/null +++ b/src/CudaSirtAlgorithm.cpp @@ -0,0 +1,154 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifdef ASTRA_CUDA + +#include "astra/CudaSirtAlgorithm.h" + +#include <boost/lexical_cast.hpp> +#include "astra/AstraObjectManager.h" + +#include "../cuda/2d/sirt.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSirtAlgorithm::type = "SIRT_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSirtAlgorithm::CCudaSirtAlgorithm() +{ + m_bIsInitialized = false; + CCudaReconstructionAlgorithm2D::_clear(); + + m_pMinMask = 0; + m_pMaxMask = 0; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSirtAlgorithm::~CCudaSirtAlgorithm() +{ + // The actual work is done by ~CCudaReconstructionAlgorithm2D + + m_pMinMask = 0; + m_pMaxMask = 0; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSirtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm", this, _cfg); + + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); + + if (!m_bIsInitialized) + return false; + + // min/max masks + if (_cfg.self->hasOption("MinMaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MinMaskId")); + m_pMinMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MinMaskId"); + if (_cfg.self->hasOption("MaxMaskId")) { + int id = boost::lexical_cast<int>(_cfg.self->getOption("MaxMaskId")); + m_pMaxMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("MaxMaskId"); + + + m_pAlgo = new astraCUDA::SIRT(); + m_bAlgoInit = false; + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int _iGPUindex, int _iDetectorSuperSampling, + int _iPixelSuperSampling) +{ + m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_pProjector, _pSinogram, _pReconstruction, _iGPUindex, _iDetectorSuperSampling, _iPixelSuperSampling); + + if (!m_bIsInitialized) + return false; + + + + m_pAlgo = new astraCUDA::SIRT(); + m_bAlgoInit = false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaSirtAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + if (!m_bAlgoInit) { + // We only override the initialisation step to copy the min/max masks + + bool ok = setupGeometry(); + ASTRA_ASSERT(ok); + + ok = m_pAlgo->allocateBuffers(); + ASTRA_ASSERT(ok); + + if (m_pMinMask || m_pMaxMask) { + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo); + const float *pfMinMaskData = 0; + const float *pfMaxMaskData = 0; + if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst(); + if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst(); + ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount()); + ASTRA_ASSERT(ok); + } + + m_bAlgoInit = true; + } + + CCudaReconstructionAlgorithm2D::run(_iNrIterations); +} + + +} // namespace astra + +#endif // ASTRA_CUDA diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp new file mode 100644 index 0000000..f23d0f6 --- /dev/null +++ b/src/CudaSirtAlgorithm3D.cpp @@ -0,0 +1,306 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/CudaSirtAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +#include "astra/ConeProjectionGeometry3D.h" +#include "astra/ParallelProjectionGeometry3D.h" +#include "astra/ParallelVecProjectionGeometry3D.h" +#include "astra/ConeVecProjectionGeometry3D.h" + +#include "../cuda/3d/astra3d.h" + +using namespace std; + +namespace astra { + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CCudaSirtAlgorithm3D::type = "SIRT3D_CUDA"; + +//---------------------------------------------------------------------------------------- +// Constructor +CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D() +{ + m_bIsInitialized = false; + m_pSirt = 0; + m_iGPUIndex = 0; + m_iVoxelSuperSampling = 1; + m_iDetectorSuperSampling = 1; +} + +//---------------------------------------------------------------------------------------- +// Constructor with initialization +CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pProjectionData, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pProjectionData, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CCudaSirtAlgorithm3D::~CCudaSirtAlgorithm3D() +{ + delete m_pSirt; + m_pSirt = 0; + + CReconstructionAlgorithm3D::_clear(); +} + + +//--------------------------------------------------------------------------------------- +// Check +bool CCudaSirtAlgorithm3D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm3D::_check(), "SIRT3D", "Error in ReconstructionAlgorithm3D initialization"); + + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("CudaSirtAlgorithm3D", this, _cfg); + + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm3D::initialize(_cfg)) { + return false; + } + + m_iGPUIndex = (int)_cfg.self->getOptionNumerical("GPUindex", 0); + CC.markOptionParsed("GPUindex"); + m_iDetectorSuperSampling = (int)_cfg.self->getOptionNumerical("DetectorSuperSampling", 1); + CC.markOptionParsed("DetectorSuperSampling"); + m_iVoxelSuperSampling = (int)_cfg.self->getOptionNumerical("VoxelSuperSampling", 1); + CC.markOptionParsed("VoxelSuperSampling"); + + m_pSirt = new AstraSIRT3d(); + + m_bAstraSIRTInit = false; + + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CCudaSirtAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3DMemory* _pSinogram, + CFloat32VolumeData3DMemory* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + m_pSirt = new AstraSIRT3d; + + m_bAstraSIRTInit = false; + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CCudaSirtAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CCudaSirtAlgorithm3D::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CCudaSirtAlgorithm3D::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + const CProjectionGeometry3D* projgeom = m_pSinogram->getGeometry(); + const CConeProjectionGeometry3D* conegeom = dynamic_cast<const CConeProjectionGeometry3D*>(projgeom); + const CParallelProjectionGeometry3D* par3dgeom = dynamic_cast<const CParallelProjectionGeometry3D*>(projgeom); + const CParallelVecProjectionGeometry3D* parvec3dgeom = dynamic_cast<const CParallelVecProjectionGeometry3D*>(projgeom); + const CConeVecProjectionGeometry3D* conevec3dgeom = dynamic_cast<const CConeVecProjectionGeometry3D*>(projgeom); + const CVolumeGeometry3D& volgeom = *m_pReconstruction->getGeometry(); + + bool ok = true; + + if (!m_bAstraSIRTInit) { + + ok &= m_pSirt->setGPUIndex(m_iGPUIndex); + + ok &= m_pSirt->setReconstructionGeometry(volgeom.getGridColCount(), + volgeom.getGridRowCount(), + volgeom.getGridSliceCount()); + fprintf(stderr, "01: %d\n", ok); + + if (conegeom) { + ok &= m_pSirt->setConeGeometry(conegeom->getProjectionCount(), + conegeom->getDetectorColCount(), + conegeom->getDetectorRowCount(), + conegeom->getOriginSourceDistance(), + conegeom->getOriginDetectorDistance(), + conegeom->getDetectorSpacingX(), + conegeom->getDetectorSpacingY(), + conegeom->getProjectionAngles()); + } else if (par3dgeom) { + ok &= m_pSirt->setPar3DGeometry(par3dgeom->getProjectionCount(), + par3dgeom->getDetectorColCount(), + par3dgeom->getDetectorRowCount(), + par3dgeom->getDetectorSpacingX(), + par3dgeom->getDetectorSpacingY(), + par3dgeom->getProjectionAngles()); + } else if (parvec3dgeom) { + ok &= m_pSirt->setPar3DGeometry(parvec3dgeom->getProjectionCount(), + parvec3dgeom->getDetectorColCount(), + parvec3dgeom->getDetectorRowCount(), + parvec3dgeom->getProjectionVectors()); + } else if (conevec3dgeom) { + ok &= m_pSirt->setConeGeometry(conevec3dgeom->getProjectionCount(), + conevec3dgeom->getDetectorColCount(), + conevec3dgeom->getDetectorRowCount(), + conevec3dgeom->getProjectionVectors()); + } else { + ASTRA_ASSERT(false); + } + fprintf(stderr, "02: %d\n", ok); + + ok &= m_pSirt->enableSuperSampling(m_iVoxelSuperSampling, m_iDetectorSuperSampling); + + if (m_bUseReconstructionMask) + ok &= m_pSirt->enableVolumeMask(); + if (m_bUseSinogramMask) + ok &= m_pSirt->enableSinogramMask(); + + ASTRA_ASSERT(ok); + fprintf(stderr, "03: %d\n", ok); + + ok &= m_pSirt->init(); + fprintf(stderr, "04: %d\n", ok); + + ASTRA_ASSERT(ok); + + m_bAstraSIRTInit = true; + + } + + CFloat32ProjectionData3DMemory* pSinoMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogram); + ASTRA_ASSERT(pSinoMem); + + ok = m_pSirt->setSinogram(pSinoMem->getDataConst(), m_pSinogram->getGeometry()->getDetectorColCount()); + + fprintf(stderr, "1: %d\n", ok); + ASTRA_ASSERT(ok); + + if (m_bUseReconstructionMask) { + CFloat32VolumeData3DMemory* pRMaskMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstructionMask); + ASTRA_ASSERT(pRMaskMem); + ok &= m_pSirt->setVolumeMask(pRMaskMem->getDataConst(), volgeom.getGridColCount()); + } + if (m_bUseSinogramMask) { + CFloat32ProjectionData3DMemory* pSMaskMem = dynamic_cast<CFloat32ProjectionData3DMemory*>(m_pSinogramMask); + ASTRA_ASSERT(pSMaskMem); + ok &= m_pSirt->setSinogramMask(pSMaskMem->getDataConst(), m_pSinogramMask->getGeometry()->getDetectorColCount()); + } + fprintf(stderr, "2: %d\n", ok); + + CFloat32VolumeData3DMemory* pReconMem = dynamic_cast<CFloat32VolumeData3DMemory*>(m_pReconstruction); + ASTRA_ASSERT(pReconMem); + ok &= m_pSirt->setStartReconstruction(pReconMem->getDataConst(), + volgeom.getGridColCount()); + + ASTRA_ASSERT(ok); + fprintf(stderr, "3: %d\n", ok); + + if (m_bUseMinConstraint) + ok &= m_pSirt->setMinConstraint(m_fMinValue); + if (m_bUseMaxConstraint) + ok &= m_pSirt->setMaxConstraint(m_fMaxValue); + fprintf(stderr, "4: %d\n", ok); + + ok &= m_pSirt->iterate(_iNrIterations); + ASTRA_ASSERT(ok); + fprintf(stderr, "5: %d\n", ok); + + ok &= m_pSirt->getReconstruction(pReconMem->getData(), + volgeom.getGridColCount()); + fprintf(stderr, "6: %d\n", ok); + ASTRA_ASSERT(ok); + + +} +//---------------------------------------------------------------------------------------- +void CCudaSirtAlgorithm3D::signalAbort() +{ + if (m_bIsInitialized && m_pSirt) { + m_pSirt->signalAbort(); + } +} + +bool CCudaSirtAlgorithm3D::getResidualNorm(float32& _fNorm) +{ + if (!m_bIsInitialized || !m_pSirt) + return false; + + _fNorm = m_pSirt->computeDiffNorm(); + + return true; +} + + +} // namespace astra diff --git a/src/DataProjector.cpp b/src/DataProjector.cpp new file mode 100644 index 0000000..d4b2f84 --- /dev/null +++ b/src/DataProjector.cpp @@ -0,0 +1,36 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/DataProjector.h" + +namespace astra { + + // EMPTY + + +} // end namespace astra diff --git a/src/DataProjectorPolicies.cpp b/src/DataProjectorPolicies.cpp new file mode 100644 index 0000000..2535706 --- /dev/null +++ b/src/DataProjectorPolicies.cpp @@ -0,0 +1,36 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/DataProjectorPolicies.h" + +namespace astra { + + // EMPTY + + +} // end namespace astra diff --git a/src/FanFlatBeamLineKernelProjector2D.cpp b/src/FanFlatBeamLineKernelProjector2D.cpp new file mode 100644 index 0000000..0891801 --- /dev/null +++ b/src/FanFlatBeamLineKernelProjector2D.cpp @@ -0,0 +1,179 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatBeamLineKernelProjector2D.h" + +#include <cmath> +#include <cstring> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/FanFlatBeamLineKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CFanFlatBeamLineKernelProjector2D::type = "line_fanflat"; + + +//---------------------------------------------------------------------------------------- +// default constructor +CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CFanFlatBeamLineKernelProjector2D::CFanFlatBeamLineKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CFanFlatBeamLineKernelProjector2D::~CFanFlatBeamLineKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFanFlatBeamLineKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFanFlatBeamLineKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CFanFlatBeamLineKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamLineKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry) || dynamic_cast<CFanFlatVecProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamLineKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFanFlatBeamLineKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CFanFlatBeamLineKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CFanFlatBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CFanFlatBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CFanFlatBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + std::vector<SDetector2D> res; + return res; +} + +//---------------------------------------------------------------------------------------- +//Result is always in [-PI/2; PI/2] +float32 CFanFlatBeamLineKernelProjector2D::angleBetweenVectors(float32 _fAX, float32 _fAY, float32 _fBX, float32 _fBY) +{ + float32 sinAB = (_fAX*_fBY - _fAY*_fBX)/sqrt((_fAX*_fAX + _fAY*_fAY)*(_fBX*_fBX + _fBY*_fBY)); + return asin(sinAB); +} + +//---------------------------------------------------------------------------------------- diff --git a/src/FanFlatBeamStripKernelProjector2D.cpp b/src/FanFlatBeamStripKernelProjector2D.cpp new file mode 100644 index 0000000..87ae8d6 --- /dev/null +++ b/src/FanFlatBeamStripKernelProjector2D.cpp @@ -0,0 +1,223 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatBeamStripKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/FanFlatBeamStripKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CFanFlatBeamStripKernelProjector2D::type = "strip_fanflat"; + +//---------------------------------------------------------------------------------------- +// default constructor +CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CFanFlatBeamStripKernelProjector2D::CFanFlatBeamStripKernelProjector2D(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CFanFlatBeamStripKernelProjector2D::~CFanFlatBeamStripKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFanFlatBeamStripKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFanFlatBeamStripKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CFanFlatBeamStripKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "FanFlatBeamStripKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CFanFlatProjectionGeometry2D*>(m_pProjectionGeometry), "FanFlatBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "FanFlatBeamStripKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFanFlatBeamStripKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CFanFlatBeamStripKernelProjector2D::initialize(CFanFlatProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CFanFlatBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 10 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CFanFlatBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CFanFlatBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + //float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + //float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + //float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + //// loop projectors and detectors + //for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // // get projection angle + // float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + // if (theta >= 7*PIdiv4) theta -= 2*PI; + // bool inverse = false; + // if (theta >= 3*PIdiv4) { + // theta -= PI; + // inverse = true; + // } + + // // calculate distance from the center of the voxel to the ray though the origin + // float32 tUL = xUL * cos(theta) + yUL * sin(theta); + // float32 tUR = xUR * cos(theta) + yUR * sin(theta); + // float32 tLL = xLL * cos(theta) + yLL * sin(theta); + // float32 tLR = xLR * cos(theta) + yLR * sin(theta); + // if (inverse) { + // tUL *= -1.0f; + // tUR *= -1.0f; + // tLL *= -1.0f; + // tLR *= -1.0f; + // } + // float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + // float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // // calculate the offset on the detectorarray (in indices) + // int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + // int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // // add affected detectors to the list + // for (int i = dmin; i <= dmax; ++i) { + // if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + // SDetector2D det; + // det.m_iAngleIndex = iProjection; + // det.m_iDetectorIndex = i; + // det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + // res.push_back(det); + // } + // } + //} + + //// return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/FanFlatProjectionGeometry2D.cpp b/src/FanFlatProjectionGeometry2D.cpp new file mode 100644 index 0000000..b74536a --- /dev/null +++ b/src/FanFlatProjectionGeometry2D.cpp @@ -0,0 +1,209 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatProjectionGeometry2D.h" + +#include <cstring> +#include <sstream> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. Sets all variables to zero. +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D() +{ + _clear(); + m_fOriginSourceDistance = 0.0f; + m_fOriginDetectorDistance = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + this->initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _fOriginSourceDistance, + _fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Copy Constructor +CFanFlatProjectionGeometry2D::CFanFlatProjectionGeometry2D(const CFanFlatProjectionGeometry2D& _projGeom) +{ + _clear(); + this->initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_fDetectorWidth, + _projGeom.m_pfProjectionAngles, + _projGeom.m_fOriginSourceDistance, + _projGeom.m_fOriginDetectorDistance); +} + +//---------------------------------------------------------------------------------------- +// Assignment operator. +CFanFlatProjectionGeometry2D& CFanFlatProjectionGeometry2D::operator=(const CFanFlatProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pfProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + m_fOriginSourceDistance = _other.m_fOriginSourceDistance; + m_fOriginDetectorDistance = _other.m_fOriginDetectorDistance; + } + return *this; +} +//---------------------------------------------------------------------------------------- +// Destructor. +CFanFlatProjectionGeometry2D::~CFanFlatProjectionGeometry2D() +{ + +} + + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CFanFlatProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + float32 _fOriginSourceDistance, + float32 _fOriginDetectorDistance) +{ + m_fOriginSourceDistance = _fOriginSourceDistance; + m_fOriginDetectorDistance = _fOriginDetectorDistance; + _initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CFanFlatProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatProjectionGeometry2D", this, _cfg); + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // Required: DistanceOriginDetector + XMLNode* node = _cfg.self->getSingleNode("DistanceOriginDetector"); + ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginDetector tag specified."); + m_fOriginDetectorDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginDetector"); + + // Required: DetectorOriginSource + node = _cfg.self->getSingleNode("DistanceOriginSource"); + ASTRA_CONFIG_CHECK(node, "FanFlatProjectionGeometry2D", "No DistanceOriginSource tag specified."); + m_fOriginSourceDistance = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DistanceOriginSource"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CFanFlatProjectionGeometry2D::clone() +{ + return new CFanFlatProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CFanFlatProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CFanFlatProjectionGeometry2D + CFanFlatProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + if (m_fOriginSourceDistance != pGeom2->m_fOriginSourceDistance) return false; + if (m_fOriginDetectorDistance != pGeom2->m_fOriginDetectorDistance) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// Is of type +bool CFanFlatProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "fanflat"); +} + +CVector3D CFanFlatProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented + ASTRA_ASSERT(false); + + return vOutput; +} + +//---------------------------------------------------------------------------------------- + + +} // namespace astra diff --git a/src/FanFlatVecProjectionGeometry2D.cpp b/src/FanFlatVecProjectionGeometry2D.cpp new file mode 100644 index 0000000..e42a4f1 --- /dev/null +++ b/src/FanFlatVecProjectionGeometry2D.cpp @@ -0,0 +1,232 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FanFlatVecProjectionGeometry2D.h" + +#include <cstring> +#include <sstream> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. Sets all variables to zero. +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D() +{ + _clear(); + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pProjectionAngles) +{ + this->initialize(_iProjectionAngleCount, + _iDetectorCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Copy Constructor +CFanFlatVecProjectionGeometry2D::CFanFlatVecProjectionGeometry2D(const CFanFlatVecProjectionGeometry2D& _projGeom) +{ + _clear(); + this->initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Assignment operator. +CFanFlatVecProjectionGeometry2D& CFanFlatVecProjectionGeometry2D::operator=(const CFanFlatVecProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + memcpy(m_pProjectionAngles, _other.m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + } + return *this; +} +//---------------------------------------------------------------------------------------- +// Destructor. +CFanFlatVecProjectionGeometry2D::~CFanFlatVecProjectionGeometry2D() +{ + // TODO + delete[] m_pProjectionAngles; +} + + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CFanFlatVecProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const SFanProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CFanFlatVecProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("FanFlatVecProjectionGeometry2D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry2D::initialize(_cfg); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorCount"); + ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "FanFlatVecProjectionGeometry3D", "No Vectors tag specified."); + vector<float32> data = node->getContentNumericalArray(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 6 == 0, "FanFlatVecProjectionGeometry3D", "Vectors doesn't consist of 6-tuples."); + m_iProjectionAngleCount = data.size() / 6; + m_pProjectionAngles = new SFanProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SFanProjection& p = m_pProjectionAngles[i]; + p.fSrcX = data[6*i + 0]; + p.fSrcY = data[6*i + 1]; + p.fDetUX = data[6*i + 4]; + p.fDetUY = data[6*i + 5]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[6*i + 2] - 0.5f * m_iDetectorCount * p.fDetUX; + p.fDetSY = data[6*i + 3] - 0.5f * m_iDetectorCount * p.fDetUY; + } + + + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CFanFlatVecProjectionGeometry2D::clone() +{ + return new CFanFlatVecProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CFanFlatVecProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CFanFlatVecProjectionGeometry2D + CFanFlatVecProjectionGeometry2D* pGeom2 = dynamic_cast<CFanFlatVecProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// Is of type +bool CFanFlatVecProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "fanflat_vec"); +} + +//---------------------------------------------------------------------------------------- + +CVector3D CFanFlatVecProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented + ASTRA_ASSERT(false); + + return vOutput; +} + +//---------------------------------------------------------------------------------------- + +void CFanFlatVecProjectionGeometry2D::getRayParams(int _iRow, int _iColumn, float32& _fT, float32& _fTheta) const +{ + // not implemented + ASTRA_ASSERT(false); +} + +//---------------------------------------------------------------------------------------- + +bool CFanFlatVecProjectionGeometry2D::_check() +{ + // TODO + return true; +} + + +//---------------------------------------------------------------------------------------- + + +} // namespace astra diff --git a/src/FilteredBackProjectionAlgorithm.cpp b/src/FilteredBackProjectionAlgorithm.cpp new file mode 100644 index 0000000..8063f7b --- /dev/null +++ b/src/FilteredBackProjectionAlgorithm.cpp @@ -0,0 +1,336 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/FilteredBackProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include <iostream> +#include <iomanip> +#include <math.h> + +#include "astra/AstraObjectManager.h" +#include "astra/ParallelBeamLineKernelProjector2D.h" +#include "astra/Fourier.h" +#include "astra/DataProjector.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CFilteredBackProjectionAlgorithm::type = "FBP"; +const int FFT = 1; +const int IFFT = -1; + +//---------------------------------------------------------------------------------------- +// Constructor +CFilteredBackProjectionAlgorithm::CFilteredBackProjectionAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFilteredBackProjectionAlgorithm::~CFilteredBackProjectionAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CFilteredBackProjectionAlgorithm::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CFilteredBackProjectionAlgorithm::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bIsInitialized = false; +} + + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "FilteredBackProjection", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + node = _cfg.self->getSingleNode("ProjectionIndex"); + if (node) + { + vector<float32> projectionIndex = node->getContentNumericalArray(); + + int angleCount = projectionIndex.size(); + int detectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount(); + + float32 * sinogramData2D = new float32[angleCount* detectorCount]; + float32 ** sinogramData = new float32*[angleCount]; + for (int i = 0; i < angleCount; i++) + { + sinogramData[i] = &(sinogramData2D[i * detectorCount]); + } + + float32 * projectionAngles = new float32[angleCount]; + float32 detectorWidth = m_pProjector->getProjectionGeometry()->getDetectorWidth(); + + for (int i = 0; i < angleCount; i ++) { + if (projectionIndex[i] > m_pProjector->getProjectionGeometry()->getProjectionAngleCount() -1 ) + { + cout << "Invalid Projection Index" << endl; + return false; + } else { + int orgIndex = (int)projectionIndex[i]; + + for (int iDetector=0; iDetector < detectorCount; iDetector++) + { + sinogramData2D[i*detectorCount+ iDetector] = m_pSinogram->getData2D()[orgIndex][iDetector]; + } +// sinogramData[i] = m_pSinogram->getSingleProjectionData(projectionIndex[i]); + projectionAngles[i] = m_pProjector->getProjectionGeometry()->getProjectionAngle((int)projectionIndex[i] ); + + } + } + + CParallelProjectionGeometry2D * pg = new CParallelProjectionGeometry2D(angleCount, detectorCount,detectorWidth,projectionAngles); + m_pProjector = new CParallelBeamLineKernelProjector2D(pg,m_pReconstruction->getGeometry()); + m_pSinogram = new CFloat32ProjectionData2D(pg, sinogramData2D); + } + ASTRA_DELETE(node); + + // TODO: check that the angles are linearly spaced between 0 and pi + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Get Information - all +map<string,boost::any> CFilteredBackProjectionAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["ProjectorId"] = getInformation("ProjectorId"); + result["ProjectionDataId"] = getInformation("ProjectionDataId"); + result["VolumeDataId"] = getInformation("VolumeDataId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result); +}; + +//--------------------------------------------------------------------------------------- +// Get Information - specific +boost::any CFilteredBackProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Initialize +bool CFilteredBackProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram) +{ + // store classes + m_pProjector = _pProjector; + m_pReconstruction = _pVolume; + m_pSinogram = _pSinogram; + + + // TODO: check that the angles are linearly spaced between 0 and pi + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CFilteredBackProjectionAlgorithm::_check() +{ + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "FBP", "Error in ReconstructionAlgorithm2D initialization"); + + // success + return true; +} + + +//---------------------------------------------------------------------------------------- +// Iterate +void CFilteredBackProjectionAlgorithm::run(int _iNrIterations) +{ + ASTRA_ASSERT(m_bIsInitialized); + + // Filter sinogram + CFloat32ProjectionData2D filteredSinogram(m_pSinogram->getGeometry(), m_pSinogram->getData()); + performFiltering(&filteredSinogram); + + // Back project + m_pReconstruction->setData(0.0f); + projectData(m_pProjector, + DefaultBPPolicy(m_pReconstruction, &filteredSinogram)); + + // Scale data + int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + (*m_pReconstruction) *= (PI/2)/iAngleCount; + + m_pReconstruction->updateStatistics(); +} + + +//---------------------------------------------------------------------------------------- +void CFilteredBackProjectionAlgorithm::performFiltering(CFloat32ProjectionData2D * _pFilteredSinogram) +{ + ASTRA_ASSERT(_pFilteredSinogram != NULL); + ASTRA_ASSERT(_pFilteredSinogram->getAngleCount() == m_pSinogram->getAngleCount()); + ASTRA_ASSERT(_pFilteredSinogram->getDetectorCount() == m_pSinogram->getDetectorCount()); + + + int iAngleCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + int iDetectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount(); + + + // We'll zero-pad to the smallest power of two at least 64 and + // at least 2*iDetectorCount + int zpDetector = 64; + int nextPow2 = 5; + while (zpDetector < iDetectorCount*2) { + zpDetector *= 2; + nextPow2++; + } + + // Create filter + float32* filter = new float32[zpDetector]; + + for (int iDetector = 0; iDetector <= zpDetector/2; iDetector++) + filter[iDetector] = (2.0f * iDetector)/zpDetector; + + for (int iDetector = zpDetector/2+1; iDetector < zpDetector; iDetector++) + filter[iDetector] = (2.0f * (zpDetector - iDetector)) / zpDetector; + + + float32* pfRe = new float32[iAngleCount * zpDetector]; + float32* pfIm = new float32[iAngleCount * zpDetector]; + + // Copy and zero-pad data + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount; + for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) { + pfReRow[iDetector] = pfDataRow[iDetector]; + pfImRow[iDetector] = 0.0f; + } + for (int iDetector = iDetectorCount; iDetector < zpDetector; ++iDetector) { + pfReRow[iDetector] = 0.0f; + pfImRow[iDetector] = 0.0f; + } + } + + // in-place FFT + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + + fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, false); + } + + // Filter + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + for (int iDetector = 0; iDetector < zpDetector; ++iDetector) { + pfReRow[iDetector] *= filter[iDetector]; + pfImRow[iDetector] *= filter[iDetector]; + } + } + + // in-place inverse FFT + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfImRow = pfIm + iAngle * zpDetector; + + fastTwoPowerFourierTransform1D(zpDetector, pfReRow, pfImRow, pfReRow, pfImRow, 1, 1, true); + } + + // Copy data back + for (int iAngle = 0; iAngle < iAngleCount; ++iAngle) { + float32* pfReRow = pfRe + iAngle * zpDetector; + float32* pfDataRow = _pFilteredSinogram->getData() + iAngle * iDetectorCount; + for (int iDetector = 0; iDetector < iDetectorCount; ++iDetector) + pfDataRow[iDetector] = pfReRow[iDetector]; + } + + delete[] pfRe; + delete[] pfIm; + delete[] filter; +} + +} diff --git a/src/Float32Data.cpp b/src/Float32Data.cpp new file mode 100644 index 0000000..47bbcc9 --- /dev/null +++ b/src/Float32Data.cpp @@ -0,0 +1,50 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data::CFloat32Data() +{ + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CFloat32Data::~CFloat32Data() +{ + +} + + +} // end namespace diff --git a/src/Float32Data2D.cpp b/src/Float32Data2D.cpp new file mode 100644 index 0000000..e51935f --- /dev/null +++ b/src/Float32Data2D.cpp @@ -0,0 +1,523 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data2D.h" +#include <iostream> +#include <cstring> + +#ifdef _MSC_VER +#include <malloc.h> +#else +#include <cstdlib> +#endif + +namespace astra { + + + //---------------------------------------------------------------------------------------- + // Constructors +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data2D::CFloat32Data2D() +{ + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class with initialization of the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, const float32* _pfData) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32Data2D class with initialization of the data block. +CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, float32 _fScalar) +{ + m_bInitialized = false; + _initialize(_iWidth, _iHeight, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32Data2D::CFloat32Data2D(const CFloat32Data2D& _other) +{ + m_bInitialized = false; + *this = _other; +} + +//---------------------------------------------------------------------------------------- +// Assignment operator +CFloat32Data2D& CFloat32Data2D::operator=(const CFloat32Data2D& _dataIn) +{ + ASTRA_ASSERT(_dataIn.m_bInitialized); + + if (m_bInitialized) { + if (m_iWidth == _dataIn.m_iWidth && m_iHeight == _dataIn.m_iHeight) { + // Same dimensions, so no need to re-allocate memory + + m_fGlobalMin = _dataIn.m_fGlobalMin; + m_fGlobalMax = _dataIn.m_fGlobalMax; + m_fGlobalMean = _dataIn.m_fGlobalMean; + + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight); + ASTRA_ASSERT(m_pfData); + + memcpy(m_pfData, _dataIn.m_pfData, m_iSize * sizeof(float32)); + } else { + // Re-allocate data + _unInit(); + _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst()); + } + } else { + _initialize(_dataIn.getWidth(), _dataIn.getHeight(), _dataIn.getDataConst()); + } + + return (*this); +} + +//---------------------------------------------------------------------------------------- +// Destructor. Free allocated memory +CFloat32Data2D::~CFloat32Data2D() +{ + if (m_bInitialized) + { + _unInit(); + } +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data, but do not fill it + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // set minmax to default values + m_fGlobalMin = 0.0; + m_fGlobalMax = 0.0; + m_fGlobalMean = 0.0; + + // initialization complete + return true; + +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, const float32 *_pfData) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_pfData != NULL); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = _pfData[i]; + } + + // initialization complete + return true; +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with a scalar initialization of the data block. +bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iSize = (size_t)m_iWidth * m_iHeight; + + // allocate memory for the data + m_pfData = 0; + m_ppfData2D = 0; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } + + // initialization complete + return true; +} + + + //---------------------------------------------------------------------------------------- + // Memory Allocation +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Allocate memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data2D::_allocateData() +{ + // basic checks + ASTRA_ASSERT(!m_bInitialized); + + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight); + ASTRA_ASSERT(m_pfData == NULL); + ASTRA_ASSERT(m_ppfData2D == NULL); + + // allocate contiguous block +#ifdef _MSC_VER + m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16); +#else + int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32)); + ASTRA_ASSERT(ret == 0); +#endif + + // create array of pointers to each row of the data block + m_ppfData2D = new float32*[m_iHeight]; + for (int iy = 0; iy < m_iHeight; iy++) + { + m_ppfData2D[iy] = &(m_pfData[iy * m_iWidth]); + } +} + +//---------------------------------------------------------------------------------------- +// Free memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data2D::_freeData() +{ + // basic checks + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_ppfData2D != NULL); + + // free memory for index table + delete[] m_ppfData2D; + // free memory for data block +#ifdef _MSC_VER + _aligned_free(m_pfData); +#else + free(m_pfData); +#endif +} + + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CFloat32Data2D::_clear() +{ + m_iWidth = 0; + m_iHeight = 0; + m_iSize = 0; + + m_pfData = NULL; + m_ppfData2D = NULL; + + m_fGlobalMin = 0.0f; + m_fGlobalMax = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Un-initialize the object, bringing it back in the unitialized state. +void CFloat32Data2D::_unInit() +{ + ASTRA_ASSERT(m_bInitialized); + + _freeData(); + _clear(); + m_bInitialized = false; +} +//---------------------------------------------------------------------------------------- + + + + //---------------------------------------------------------------------------------------- + // Data Operations +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data2D::copyData(const float32* _pfData) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_pfData != NULL); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = _pfData[i]; + } +} + +//---------------------------------------------------------------------------------------- +// scale m_pfData from 0 to 255. + +void CFloat32Data2D::scale() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + _computeGlobalMinMax(); + for (size_t i = 0; i < m_iSize; i++) + { + // do checks + m_pfData[i]= (m_pfData[i] - m_fGlobalMin) / (m_fGlobalMax - m_fGlobalMin) * 255; ; + } + + +} + +//---------------------------------------------------------------------------------------- +// Set each element of the data to a specific scalar value +void CFloat32Data2D::setData(float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } +} + +//---------------------------------------------------------------------------------------- +// Clear Data +void CFloat32Data2D::clearData() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // set data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = 0.0f; + } +} +//---------------------------------------------------------------------------------------- + + + + //---------------------------------------------------------------------------------------- + // Statistics Operations +//---------------------------------------------------------------------------------------- + +//---------------------------------------------------------------------------------------- +// Update data statistics, such as minimum and maximum value, after the data has been modified. +void CFloat32Data2D::updateStatistics() +{ + _computeGlobalMinMax(); +} + +//---------------------------------------------------------------------------------------- +// Find the minimum and maximum data value. +void CFloat32Data2D::_computeGlobalMinMax() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // initial values + m_fGlobalMin = m_pfData[0]; + m_fGlobalMax = m_pfData[0]; + m_fGlobalMean = 0.0f; + + // loop + for (size_t i = 0; i < m_iSize; i++) + { + // do checks + float32 v = m_pfData[i]; + if (v < m_fGlobalMin) { + m_fGlobalMin = v; + } + if (v > m_fGlobalMax) { + m_fGlobalMax = v; + } + m_fGlobalMean +=v; + } + m_fGlobalMean /= m_iSize; +} +//---------------------------------------------------------------------------------------- + + +CFloat32Data2D& CFloat32Data2D::clampMin(float32& _fMin) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] < _fMin) + m_pfData[i] = _fMin; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::clampMax(float32& _fMax) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] > _fMax) + m_pfData[i] = _fMax; + } + return (*this); +} + + +//---------------------------------------------------------------------------------------- +// Operator Overloading +//---------------------------------------------------------------------------------------- +CFloat32Data2D& CFloat32Data2D::operator+=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] += v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator-=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] -= v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator*=(const CFloat32Data2D& v) +{ + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(v.m_bInitialized); + ASTRA_ASSERT(getSize() == v.getSize()); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] *= v.m_pfData[i]; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator*=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] *= f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator/=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] /= f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator+=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] += f; + } + return (*this); +} + +CFloat32Data2D& CFloat32Data2D::operator-=(const float32& f) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + m_pfData[i] -= f; + } + return (*this); +} + + + + +} // end namespace astra diff --git a/src/Float32Data3D.cpp b/src/Float32Data3D.cpp new file mode 100644 index 0000000..4280b3b --- /dev/null +++ b/src/Float32Data3D.cpp @@ -0,0 +1,55 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data3D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data3D::CFloat32Data3D() +{ + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CFloat32Data3D::~CFloat32Data3D() +{ + +} +//---------------------------------------------------------------------------------------- + +bool CFloat32Data3D::_data3DSizesEqual(const CFloat32Data3D * _pA, const CFloat32Data3D * _pB) +{ + return ((_pA->m_iWidth == _pB->m_iWidth) && (_pA->m_iHeight == _pB->m_iHeight) && (_pA->m_iDepth == _pB->m_iDepth)); +} + +} // end namespace astra diff --git a/src/Float32Data3DMemory.cpp b/src/Float32Data3DMemory.cpp new file mode 100644 index 0000000..386770c --- /dev/null +++ b/src/Float32Data3DMemory.cpp @@ -0,0 +1,356 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32Data3DMemory.h" +#include <iostream> + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32Data3DMemory::CFloat32Data3DMemory() +{ + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor. Free allocated memory +CFloat32Data3DMemory::~CFloat32Data3DMemory() +{ + if (m_bInitialized) + { + _unInit(); + } +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class, allocating (but not initializing) the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + + if (m_bInitialized) + { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // set minmax to default values + m_fGlobalMin = 0.0; + m_fGlobalMax = 0.0; + + // initialization complete + return true; + +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, const float32* _pfData) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + ASTRA_ASSERT(_pfData != NULL); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _pfData[i]; + } + + // initialization complete + return true; +} + +//---------------------------------------------------------------------------------------- +// Initializes an instance of the CFloat32Data2D class with initialization of the data block. +bool CFloat32Data3DMemory::_initialize(int _iWidth, int _iHeight, int _iDepth, float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(_iWidth > 0); + ASTRA_ASSERT(_iHeight > 0); + ASTRA_ASSERT(_iDepth > 0); + + if (m_bInitialized) { + _unInit(); + } + + // calculate size + m_iWidth = _iWidth; + m_iHeight = _iHeight; + m_iDepth = _iDepth; + m_iSize = (size_t)m_iWidth * m_iHeight * m_iDepth; + + // allocate memory for the data, but do not fill it + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + _allocateData(); + + // fill the data block with a copy of the input data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } + + // initialization complete + return true; +} +//---------------------------------------------------------------------------------------- + + +//---------------------------------------------------------------------------------------- +// Allocate memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data3DMemory::_allocateData() +{ + // basic checks + ASTRA_ASSERT(!m_bInitialized); + + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == (size_t)m_iWidth * m_iHeight * m_iDepth); + ASTRA_ASSERT(m_pfData == NULL); + ASTRA_ASSERT(m_ppfDataRowInd == NULL); + ASTRA_ASSERT(m_pppfDataSliceInd == NULL); + + // allocate contiguous block +#ifdef _MSC_VER + m_pfData = (float32*)_aligned_malloc(m_iSize * sizeof(float32), 16); +#else + int ret = posix_memalign((void**)&m_pfData, 16, m_iSize * sizeof(float32)); + ASTRA_ASSERT(ret == 0); +#endif + ASTRA_ASSERT(((size_t)m_pfData & 15) == 0); + + // create array of pointers to each row of the data block + m_ppfDataRowInd = new float32*[m_iHeight*m_iDepth]; + for (int iy = 0; iy < m_iHeight*m_iDepth; iy++) + { + m_ppfDataRowInd[iy] = &(m_pfData[iy * m_iWidth]); + } + + // create array of pointers to each row of the data block + m_pppfDataSliceInd = new float32**[m_iDepth]; + for (int iy = 0; iy < m_iDepth; iy++) + { + m_pppfDataSliceInd[iy] = &(m_ppfDataRowInd[iy * m_iHeight]); + } +} + +//---------------------------------------------------------------------------------------- +// Free memory for m_pfData and m_ppfData2D arrays. +void CFloat32Data3DMemory::_freeData() +{ + // basic checks + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_ppfDataRowInd != NULL); + ASTRA_ASSERT(m_pppfDataSliceInd != NULL); + + // free memory for index table + delete[] m_pppfDataSliceInd; + // free memory for index table + delete[] m_ppfDataRowInd; + // free memory for data block +#ifdef _MSC_VER + _aligned_free(m_pfData); +#else + free(m_pfData); +#endif +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CFloat32Data3DMemory::_clear() +{ + m_iWidth = 0; + m_iHeight = 0; + m_iDepth = 0; + m_iSize = 0; + + m_pfData = NULL; + m_ppfDataRowInd = NULL; + m_pppfDataSliceInd = NULL; + + //m_fGlobalMin = 0.0f; + //m_fGlobalMax = 0.0f; +} + +//---------------------------------------------------------------------------------------- +// Un-initialize the object, bringing it back in the unitialized state. +void CFloat32Data3DMemory::_unInit() +{ + ASTRA_ASSERT(m_bInitialized); + + _freeData(); + _clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Update data statistics, such as minimum and maximum value, after the data has been modified. +void CFloat32Data3DMemory::updateStatistics() +{ + _computeGlobalMinMax(); +} + +//---------------------------------------------------------------------------------------- +// Find the minimum and maximum data value. +void CFloat32Data3DMemory::_computeGlobalMinMax() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // initial values + m_fGlobalMin = m_pfData[0]; + m_fGlobalMax = m_pfData[0]; + + // loop + size_t i; + float32 v; + for (i = 0; i < m_iSize; ++i) + { + v = m_pfData[i]; + if (v < m_fGlobalMin) m_fGlobalMin = v; + if (v > m_fGlobalMax) m_fGlobalMax = v; + } +} + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data3DMemory::copyData(const float32* _pfData, size_t _iSize) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(_pfData != NULL); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + ASTRA_ASSERT(m_iSize == _iSize); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _pfData[i]; + } +} + +//---------------------------------------------------------------------------------------- +// Copy the data block pointed to by _pfData to the data block pointed to by m_pfData. +void CFloat32Data3DMemory::setData(float32 _fScalar) +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // copy data + size_t i; + for (i = 0; i < m_iSize; ++i) + { + m_pfData[i] = _fScalar; + } +} + +//---------------------------------------------------------------------------------------- +// Clear Data +void CFloat32Data3DMemory::clearData() +{ + // basic checks + ASTRA_ASSERT(m_bInitialized); + ASTRA_ASSERT(m_pfData != NULL); + ASTRA_ASSERT(m_iSize > 0); + + // set data + size_t i; + for (i = 0; i < m_iSize; ++i) { + m_pfData[i] = 0.0f; + } +} + +//---------------------------------------------------------------------------------------- + +CFloat32Data3D& CFloat32Data3DMemory::clampMin(float32& _fMin) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] < _fMin) + m_pfData[i] = _fMin; + } + return (*this); +} + +CFloat32Data3D& CFloat32Data3DMemory::clampMax(float32& _fMax) +{ + ASTRA_ASSERT(m_bInitialized); + for (size_t i = 0; i < m_iSize; i++) { + if (m_pfData[i] > _fMax) + m_pfData[i] = _fMax; + } + return (*this); +} + + + + +} // end namespace astra diff --git a/src/Float32ProjectionData2D.cpp b/src/Float32ProjectionData2D.cpp new file mode 100644 index 0000000..a74fc14 --- /dev/null +++ b/src/Float32ProjectionData2D.cpp @@ -0,0 +1,139 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData2D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32ProjectionData2D::CFloat32ProjectionData2D() : + CFloat32Data2D() +{ + m_bInitialized = false; + m_pGeometry = NULL; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry) +{ + m_bInitialized = false; + initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with scalar initialization of the data. +CFloat32ProjectionData2D::CFloat32ProjectionData2D(CProjectionGeometry2D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32ProjectionData2D::CFloat32ProjectionData2D(const CFloat32ProjectionData2D& _other) : CFloat32Data2D(_other) +{ + // Data is copied by parent constructor + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; +} + +// Assignment operator + +CFloat32ProjectionData2D& CFloat32ProjectionData2D::operator=(const CFloat32ProjectionData2D& _other) +{ + ASTRA_ASSERT(_other.m_bInitialized); + + if (m_bInitialized) + delete m_pGeometry; + *((CFloat32Data2D*)this) = _other; + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; + + return *this; +} + + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData2D::initialize(CProjectionGeometry2D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorCount(), m_pGeometry->getProjectionAngleCount(), _fScalar); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32ProjectionData2D::~CFloat32ProjectionData2D() +{ + if (m_bInitialized) + delete m_pGeometry; + m_pGeometry = 0; +} + +//---------------------------------------------------------------------------------------- +void CFloat32ProjectionData2D::changeGeometry(CProjectionGeometry2D* _pGeometry) +{ + if (!m_bInitialized) return; + + delete m_pGeometry; + m_pGeometry = _pGeometry->clone(); +} + +} // end namespace astra diff --git a/src/Float32ProjectionData3D.cpp b/src/Float32ProjectionData3D.cpp new file mode 100644 index 0000000..66bb5e3 --- /dev/null +++ b/src/Float32ProjectionData3D.cpp @@ -0,0 +1,273 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData3D.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructors +//---------------------------------------------------------------------------------------- + + +// Default constructor +CFloat32ProjectionData3D::CFloat32ProjectionData3D() : + CFloat32Data3D() { +} + +// Destructor +CFloat32ProjectionData3D::~CFloat32ProjectionData3D() { + delete m_pGeometry; + m_pGeometry = 0; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue += fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue -= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const CFloat32ProjectionData3D& _data) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); +#ifdef _DEBUG + CProjectionGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisProjectionDetectorCount = pThisGeometry->getDetectorRowCount() * pThisGeometry->getDetectorColCount(); + int iDataProjectionDetectorCount = pDataGeometry->getDetectorRowCount() * pDataGeometry->getDetectorColCount(); + + ASTRA_ASSERT(iProjectionCount == pDataGeometry->getProjectionCount()); + ASTRA_ASSERT(iThisProjectionDetectorCount == iDataProjectionDetectorCount); +#endif + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue *= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator*=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue *= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator/=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue /= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator+=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue += _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32ProjectionData3D& CFloat32ProjectionData3D::operator-=(const float32& _fScalar) +{ + CProjectionGeometry3D * pThisGeometry = getGeometry(); + + int iProjectionCount = pThisGeometry->getProjectionCount(); + + for(int iProjectionIndex = 0; iProjectionIndex < iProjectionCount; iProjectionIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchProjection(iProjectionIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue -= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnProjection(iProjectionIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +} // end namespace astra diff --git a/src/Float32ProjectionData3DMemory.cpp b/src/Float32ProjectionData3DMemory.cpp new file mode 100644 index 0000000..4d23688 --- /dev/null +++ b/src/Float32ProjectionData3DMemory.cpp @@ -0,0 +1,221 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32ProjectionData3DMemory.h" +#include "astra/ParallelProjectionGeometry3D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory() : + CFloat32Data3DMemory() +{ + m_bInitialized = false; + m_pGeometry = NULL; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class, allocating (but not initializing) the data block. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry) +{ + m_bInitialized = false; + initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32ProjectionData2D class with initialization of the data. +CFloat32ProjectionData3DMemory::CFloat32ProjectionData3DMemory(CProjectionGeometry3D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount()); // depth + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount(), // depth + _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32ProjectionData3DMemory::initialize(CProjectionGeometry3D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getDetectorColCount(), // width + m_pGeometry->getProjectionCount(), // height + m_pGeometry->getDetectorRowCount(), // depth + _fScalar); + return m_bInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32ProjectionData3DMemory::~CFloat32ProjectionData3DMemory() +{ + //delete m_pGeometry; //delete geom inherited from CFloat32ProjectionData3D + //_unInit(); //delete stuff inherited from CFloat32Data3DMemory +} + +//---------------------------------------------------------------------------------------- +// Fetch a projection +CFloat32VolumeData2D* CFloat32ProjectionData3DMemory::fetchProjection(int _iProjectionNr) const +{ + // fetch slice of the geometry + CVolumeGeometry2D volGeom(m_pGeometry->getDetectorColCount(), m_pGeometry->getDetectorRowCount()); + // create new volume data + CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom); + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + res->getData()[row*m_pGeometry->getDetectorColCount() + col] = + m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col]; + } + } + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a projection +void CFloat32ProjectionData3DMemory::returnProjection(int _iProjectionNr, CFloat32VolumeData2D* _pProjection) +{ + /// TODO: check geometry + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getDetectorRowCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + m_pfData[_iProjectionNr * m_pGeometry->getDetectorColCount() + m_pGeometry->getDetectorColCount()* m_pGeometry->getProjectionCount() * row + col] = + _pProjection->getData()[row*m_pGeometry->getDetectorColCount() + col]; + } + } +} + +//---------------------------------------------------------------------------------------- +// Fetch a sinogram +CFloat32ProjectionData2D* CFloat32ProjectionData3DMemory::fetchSinogram(int _iSliceNr) const +{ + CParallelProjectionGeometry3D * pParallelProjGeo = (CParallelProjectionGeometry3D *)m_pGeometry; + CParallelProjectionGeometry2D * pProjGeo2D = pParallelProjGeo->createProjectionGeometry2D(); + + // create new projection data + CFloat32ProjectionData2D* res = new CFloat32ProjectionData2D(pProjGeo2D); + // copy data + int row, col; + + int iDetectorColumnCount = m_pGeometry->getDetectorColCount(); + int iProjectionAngleCount = m_pGeometry->getProjectionCount(); + + for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) + { + int iTargetIndex = row * iDetectorColumnCount + col; + int iSourceIndex = _iSliceNr * iDetectorColumnCount * iProjectionAngleCount + row * iDetectorColumnCount + col; + + float32 fStoredValue = m_pfData[iSourceIndex]; + + res->getData()[iTargetIndex] = fStoredValue; + } + } + + delete pProjGeo2D; + + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a sinogram +void CFloat32ProjectionData3DMemory::returnSinogram(int _iSliceNr, CFloat32ProjectionData2D* _pSinogram2D) +{ + /// TODO: check geometry + // copy data + int row, col; + for (row = 0; row < m_pGeometry->getProjectionCount(); ++row) { + for (col = 0; col < m_pGeometry->getDetectorColCount(); ++col) { + m_pfData[_iSliceNr*m_pGeometry->getDetectorColCount()*m_pGeometry->getProjectionCount() + row*m_pGeometry->getDetectorColCount() + col] = + _pSinogram2D->getData()[row*m_pGeometry->getDetectorColCount() + col]; + } + } +} + +//---------------------------------------------------------------------------------------- +// Returns a specific value +float32 CFloat32ProjectionData3DMemory::getDetectorValue(int _iIndex) +{ + return m_pfData[_iIndex]; +} + +//---------------------------------------------------------------------------------------- +// Sets a specific value +void CFloat32ProjectionData3DMemory::setDetectorValue(int _iIndex, float32 _fValue) +{ + m_pfData[_iIndex] = _fValue; +} +//---------------------------------------------------------------------------------------- + +CFloat32ProjectionData3DMemory& CFloat32ProjectionData3DMemory::operator=(const CFloat32ProjectionData3DMemory& _dataIn) +{ + memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getDetectorTotCount()); + + return *this; +} + +} // end namespace astra diff --git a/src/Float32VolumeData2D.cpp b/src/Float32VolumeData2D.cpp new file mode 100644 index 0000000..f07fd71 --- /dev/null +++ b/src/Float32VolumeData2D.cpp @@ -0,0 +1,135 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData2D.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32VolumeData2D::CFloat32VolumeData2D() : + CFloat32Data2D() +{ + m_pGeometry = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData2D::CFloat32VolumeData2D(CVolumeGeometry2D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor +CFloat32VolumeData2D::CFloat32VolumeData2D(const CFloat32VolumeData2D& _other) : CFloat32Data2D(_other) +{ + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; +} + +// Assignment operator + +CFloat32VolumeData2D& CFloat32VolumeData2D::operator=(const CFloat32VolumeData2D& _other) +{ + ASTRA_ASSERT(_other.m_bInitialized); + + if (m_bInitialized) + delete m_pGeometry; + *((CFloat32Data2D*)this) = _other; + m_pGeometry = _other.m_pGeometry->clone(); + m_bInitialized = true; + + return *this; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData2D::~CFloat32VolumeData2D() +{ + if (m_bInitialized) + delete m_pGeometry; + m_pGeometry = 0; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData2D::initialize(CVolumeGeometry2D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), _fScalar); + return m_bInitialized; +} +//---------------------------------------------------------------------------------------- +void CFloat32VolumeData2D::changeGeometry(CVolumeGeometry2D* _pGeometry) +{ + if (!m_bInitialized) return; + + delete m_pGeometry; + m_pGeometry = _pGeometry->clone(); +} + + +} // end namespace astra diff --git a/src/Float32VolumeData3D.cpp b/src/Float32VolumeData3D.cpp new file mode 100644 index 0000000..d269aa8 --- /dev/null +++ b/src/Float32VolumeData3D.cpp @@ -0,0 +1,269 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData3D.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CFloat32VolumeData3D::CFloat32VolumeData3D() : + CFloat32Data3D() { + +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData3D::~CFloat32VolumeData3D() { + +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue += fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue -= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const CFloat32VolumeData3D& _data) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); +#ifdef _DEBUG + CVolumeGeometry3D * pDataGeometry = _data.getGeometry(); + int iThisSlicePixelCount = pThisGeometry->getGridRowCount() * pThisGeometry->getGridColCount(); + int iDataSlicePixelCount = pDataGeometry->getGridRowCount() * pDataGeometry->getGridColCount(); + + ASTRA_ASSERT(iSliceCount == pDataGeometry->getGridSliceCount()); + ASTRA_ASSERT(iThisSlicePixelCount == iDataSlicePixelCount); +#endif + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + CFloat32VolumeData2D * pDataProjection = _data.fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + float32 fDataValue = pDataProjection->getDataConst()[iDetectorIndex]; + + fThisValue *= fDataValue; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + delete pDataProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator*=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue *= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator/=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue /= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator+=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue += _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +CFloat32VolumeData3D& CFloat32VolumeData3D::operator-=(const float32& _fScalar) +{ + CVolumeGeometry3D * pThisGeometry = getGeometry(); + + int iSliceCount = pThisGeometry->getGridSliceCount(); + + for(int iSliceIndex = 0; iSliceIndex < iSliceCount; iSliceIndex++) + { + CFloat32VolumeData2D * pThisProjection = fetchSliceZ(iSliceIndex); + + for(int iDetectorIndex = 0; iDetectorIndex < iDetectorIndex; iDetectorIndex++) + { + float32 fThisValue = pThisProjection->getData()[iDetectorIndex]; + + fThisValue -= _fScalar; + + pThisProjection->getData()[iDetectorIndex] = fThisValue; + } + + returnSliceZ(iSliceIndex, pThisProjection); + + delete pThisProjection; + } + + return *this; +} + +} // end namespace astra diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp new file mode 100644 index 0000000..aa3832b --- /dev/null +++ b/src/Float32VolumeData3DMemory.cpp @@ -0,0 +1,208 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Float32VolumeData3DMemory.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory() : + CFloat32Data3DMemory() +{ + m_pGeometry = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class, allocating (but not initializing) the data block. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, const float32* _pfData) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _pfData); +} + +//---------------------------------------------------------------------------------------- +// Create an instance of the CFloat32VolumeData2D class with initialization of the data. +CFloat32VolumeData3DMemory::CFloat32VolumeData3DMemory(CVolumeGeometry3D* _pGeometry, float32 _fScalar) +{ + m_bInitialized = false; + m_bInitialized = initialize(_pGeometry, _fScalar); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CFloat32VolumeData3DMemory::~CFloat32VolumeData3DMemory() +{ + if(m_pGeometry){ + delete m_pGeometry; + } + m_pGeometry = 0; + +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount()); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, const float32* _pfData) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _pfData); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization +bool CFloat32VolumeData3DMemory::initialize(CVolumeGeometry3D* _pGeometry, float32 _fScalar) +{ + m_pGeometry = _pGeometry->clone(); + m_bInitialized = _initialize(m_pGeometry->getGridColCount(), m_pGeometry->getGridRowCount(), m_pGeometry->getGridSliceCount(), _fScalar); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Fetch a slice +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceZ(int _iSliceIndex) const +{ + // fetch slice of the geometry + int iRowCount = m_pGeometry->getGridRowCount(); + int iColumnCount = m_pGeometry->getGridColCount(); + CVolumeGeometry2D volGeom(iColumnCount, iRowCount); + + // create new volume data + CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom); + + // copy data + int iSliceCount = m_pGeometry->getGridSliceCount(); + float * pfTargetData = res->getData(); + for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++) + { + for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++) + { + int iSourceIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex; + int iTargetIndex = iRowIndex * iColumnCount + iColumnIndex; + float fStoredValue = m_pfData[iSourceIndex]; + pfTargetData[iTargetIndex] = fStoredValue; + } + } + // return + return res; +} + +//---------------------------------------------------------------------------------------- +// Return a slice +void CFloat32VolumeData3DMemory::returnSliceZ(int _iSliceIndex, CFloat32VolumeData2D * _pSlice) +{ + int iRowCount = _pSlice->getGeometry()->getGridRowCount(); + int iColumnCount = _pSlice->getGeometry()->getGridColCount(); + + assert(iRowCount == m_pGeometry->getGridRowCount()); + assert(iColumnCount == m_pGeometry->getGridColCount()); + + for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++) + { + for(int iColumnIndex = 0; iColumnIndex < iColumnCount; iColumnIndex++) + { + int iSourceIndex = iRowIndex * iColumnCount + iColumnIndex; + int iTargetIndex = _iSliceIndex * iColumnCount * iRowCount + iRowIndex * iColumnCount + iColumnIndex; + float fStoredValue = _pSlice->getDataConst()[iSourceIndex]; + m_pfData[iTargetIndex] = fStoredValue; + } + } +} + +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceX(int _iColumnIndex) const +{ + // TODO: + assert(false); + return NULL; +} + +CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceY(int _iRowIndex) const +{ + // TODO: + assert(false); + return NULL; +} + +void CFloat32VolumeData3DMemory::returnSliceX(int _iColumnIndex, CFloat32VolumeData2D * _pSliceData) +{ + // TODO: + assert(false); +} + +void CFloat32VolumeData3DMemory::returnSliceY(int _iRowIndex, CFloat32VolumeData2D * _pSliceData) +{ + // TODO: + assert(false); +} + +//---------------------------------------------------------------------------------------- +// Returns a specific value +float32 CFloat32VolumeData3DMemory::getVoxelValue(int _iIndex) +{ + return m_pfData[_iIndex]; +} + +//---------------------------------------------------------------------------------------- +// Sets a specific value +void CFloat32VolumeData3DMemory::setVoxelValue(int _iIndex, float32 _fValue) +{ + m_pfData[_iIndex] = _fValue; +} +//---------------------------------------------------------------------------------------- + +CFloat32VolumeData3DMemory& CFloat32VolumeData3DMemory::operator=(const CFloat32VolumeData3DMemory& _dataIn) +{ + memcpy(m_pfData, _dataIn.m_pfData, sizeof(float32) * _dataIn.m_pGeometry->getGridTotCount()); + + return *this; +} + +} // end namespace astra diff --git a/src/ForwardProjectionAlgorithm.cpp b/src/ForwardProjectionAlgorithm.cpp new file mode 100644 index 0000000..970d5b0 --- /dev/null +++ b/src/ForwardProjectionAlgorithm.cpp @@ -0,0 +1,280 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ForwardProjectionAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CForwardProjectionAlgorithm::type = "FP"; + +//---------------------------------------------------------------------------------------- +// Constructor - Default +CForwardProjectionAlgorithm::CForwardProjectionAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CForwardProjectionAlgorithm::CForwardProjectionAlgorithm(CProjector2D* _pProjector, CFloat32VolumeData2D* _pVolume, CFloat32ProjectionData2D* _pSinogram) +{ + _clear(); + initialize(_pProjector, _pVolume, _pSinogram); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CForwardProjectionAlgorithm::~CForwardProjectionAlgorithm() +{ + delete m_pForwardProjector; + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CForwardProjectionAlgorithm::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pVolume = NULL; + m_pForwardProjector = NULL; + m_bUseSinogramMask = false; + m_bUseVolumeMask = false; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CForwardProjectionAlgorithm::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pVolume = NULL; + m_bUseSinogramMask = false; + m_bUseVolumeMask = false; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CForwardProjectionAlgorithm::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjector, "ForwardProjection", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "ForwardProjection", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pVolume, "ForwardProjection", "Invalid Volume Data Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ForwardProjection", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "ForwardProjection", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolume->isInitialized(), "ForwardProjection", "Volume Data Object Not Initialized."); + + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "ForwardProjection", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pVolume->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "ForwardProjection", "Volume Data not compatible with the specified Projector."); + + ASTRA_CONFIG_CHECK(m_pForwardProjector, "ForwardProjection", "Invalid FP Policy"); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CForwardProjectionAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume data + node = _cfg.self->getSingleNode("VolumeDataId"); + ASTRA_CONFIG_CHECK(node, "ForwardProjection", "No VolumeDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pVolume = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + + // volume mask + if (_cfg.self->hasOption("VolumeMaskId")) { + m_bUseVolumeMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("VolumeMaskId")); + m_pVolumeMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + + // sino mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + + // ray or voxel-driven projector? + //m_bUseVoxelProjector = _cfg.self->getOptionBool("VoxelDriven", false); + + // init data projector + _init(); + + // return success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Get Information - all +map<string,boost::any> CForwardProjectionAlgorithm::getInformation() +{ + map<string, boost::any> result; + result["ProjectorId"] = getInformation("ProjectorId"); + result["ProjectionDataId"] = getInformation("ProjectionDataId"); + result["VolumeDataId"] = getInformation("VolumeDataId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), result); +}; + +//--------------------------------------------------------------------------------------- +// Get Information - specific +boost::any CForwardProjectionAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } else if (_sIdentifier == "VolumeDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pVolume); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Initialize +bool CForwardProjectionAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32VolumeData2D* _pVolume, + CFloat32ProjectionData2D* _pSinogram) +{ + // store classes + m_pProjector = _pProjector; + m_pVolume = _pVolume; + m_pSinogram = _pSinogram; + + // init data projector + _init(); + + // return success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CForwardProjectionAlgorithm::_init() +{ + // forward projection data projector + m_pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pVolumeMask), // reconstruction mask + DefaultFPPolicy(m_pVolume, m_pSinogram), // forward projection + m_bUseSinogramMask, m_bUseVolumeMask, true // options on/off + ); +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CForwardProjectionAlgorithm::setVolumeMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseVolumeMask = _bEnable; + m_pVolumeMask = _pMask; + if (m_pVolumeMask == NULL) { + m_bUseVolumeMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CForwardProjectionAlgorithm::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Iterate +void CForwardProjectionAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_pSinogram->setData(0.0f); + +// if (m_bUseVoxelProjector) { +// m_pForwardProjector->projectAllVoxels(); +// } else { + m_pForwardProjector->project(); +// } + +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/Fourier.cpp b/src/Fourier.cpp new file mode 100644 index 0000000..0f7da28 --- /dev/null +++ b/src/Fourier.cpp @@ -0,0 +1,233 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Fourier.h" + +namespace astra { + + +void discreteFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool inverse) +{ + for (unsigned int w = 0; w < iLength; w++) + { + pfRealOut[iStrideOut*w] = pfImaginaryOut[iStrideOut*w] = 0; + for (unsigned int y = 0; y < iLength; y++) + { + float32 a = 2 * PI * w * y / float32(iLength); + if (!inverse) + a = -a; + float32 ca = cos(a); + float32 sa = sin(a); + pfRealOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * ca - pfImaginaryIn[iStrideIn*y] * sa; + pfImaginaryOut[iStrideOut*w] += pfRealIn[iStrideIn*y] * sa + pfImaginaryIn[iStrideIn*y] * ca; + } + } + + if (inverse) { + for (unsigned int x = 0; x < iLength; ++x) { + pfRealOut[iStrideOut*x] /= iLength; + pfImaginaryOut[iStrideOut*x] /= iLength; + } + } +} + +void discreteFourierTransform2D(unsigned int iHeight, unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool inverse) +{ + float32* reTemp = new float32[iWidth * iHeight]; + float32* imTemp = new float32[iWidth * iHeight]; + + //calculate the fourier transform of the columns + for (unsigned int x = 0; x < iWidth; x++) + { + discreteFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x, + reTemp+x, imTemp+x, + iWidth, iWidth, inverse); + } + + //calculate the fourier transform of the rows + for(unsigned int y = 0; y < iHeight; y++) + { + discreteFourierTransform1D(iWidth, + reTemp+y*iWidth, + imTemp+y*iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + 1, 1, inverse); + } + + delete[] reTemp; + delete[] imTemp; +} + +/** permute the entries from pfDataIn into pfDataOut to prepare for an + * in-place FFT. pfDataIn may be equal to pfDataOut. + */ +static void bitReverse(unsigned int iLength, + const float32* pfDataIn, float32* pfDataOut, + unsigned int iStrideShiftIn, + unsigned int iStrideShiftOut) +{ + if (pfDataIn == pfDataOut) { + assert(iStrideShiftIn == iStrideShiftOut); + float32 t; + unsigned int j = 0; + for(unsigned int i = 0; i < iLength - 1; i++) { + if (i < j) { + t = pfDataOut[i<<iStrideShiftOut]; + pfDataOut[i<<iStrideShiftOut] = pfDataOut[j<<iStrideShiftOut]; + pfDataOut[j<<iStrideShiftOut] = t; + } + unsigned int k = iLength / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + } else { + unsigned int j = 0; + for(unsigned int i = 0; i < iLength - 1; i++) { + pfDataOut[i<<iStrideShiftOut] = pfDataIn[j<<iStrideShiftIn]; + unsigned int k = iLength / 2; + while (k <= j) { + j -= k; + k /= 2; + } + j += k; + } + pfDataOut[(iLength-1)<<iStrideShiftOut] = pfDataIn[(iLength-1)<<iStrideShiftOut]; + } +} + +static unsigned int log2(unsigned int n) +{ + unsigned int l = 0; + while (n > 1) { + n /= 2; + ++l; + } + return l; +} + +/** perform 1D FFT. iLength, iStrideIn, iStrideOut must be powers of two. */ +void fastTwoPowerFourierTransform1D(unsigned int iLength, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + unsigned int iStrideIn, + unsigned int iStrideOut, + bool inverse) +{ + unsigned int iStrideShiftIn = log2(iStrideIn); + unsigned int iStrideShiftOut = log2(iStrideOut); + unsigned int iLogLength = log2(iLength); + + bitReverse(iLength, pfRealIn, pfRealOut, iStrideShiftIn, iStrideShiftOut); + bitReverse(iLength, pfImaginaryIn, pfImaginaryOut, iStrideShiftIn, iStrideShiftOut); + + float32 ca = -1.0; + float32 sa = 0.0; + unsigned int l1 = 1, l2 = 1; + for(unsigned int l=0; l < iLogLength; ++l) + { + l1 = l2; + l2 *= 2; + float32 u1 = 1.0; + float32 u2 = 0.0; + for(unsigned int j = 0; j < l1; j++) + { + for(unsigned int i = j; i < iLength; i += l2) + { + unsigned int i1 = i + l1; + float32 t1 = u1 * pfRealOut[i1<<iStrideShiftOut] - u2 * pfImaginaryOut[i1<<iStrideShiftOut]; + float32 t2 = u1 * pfImaginaryOut[i1<<iStrideShiftOut] + u2 * pfRealOut[i1<<iStrideShiftOut]; + pfRealOut[i1<<iStrideShiftOut] = pfRealOut[i<<iStrideShiftOut] - t1; + pfImaginaryOut[i1<<iStrideShiftOut] = pfImaginaryOut[i<<iStrideShiftOut] - t2; + pfRealOut[i<<iStrideShiftOut] += t1; + pfImaginaryOut[i<<iStrideShiftOut] += t2; + } + float32 z = u1 * ca - u2 * sa; + u2 = u1 * sa + u2 * ca; + u1 = z; + } + sa = sqrt((1.0 - ca) / 2.0); + if (!inverse) + sa = -sa; + ca = sqrt((1.0 + ca) / 2.0); + } + + if (inverse) { + for (unsigned int i = 0; i < iLength; ++i) { + pfRealOut[i<<iStrideShiftOut] /= iLength; + pfImaginaryOut[i<<iStrideShiftOut] /= iLength; + } + } +} + +void fastTwoPowerFourierTransform2D(unsigned int iHeight, + unsigned int iWidth, + const float32* pfRealIn, + const float32* pfImaginaryIn, + float32* pfRealOut, + float32* pfImaginaryOut, + bool inverse) +{ + //calculate the fourier transform of the columns + for (unsigned int x = 0; x < iWidth; x++) + { + fastTwoPowerFourierTransform1D(iHeight, pfRealIn+x, pfImaginaryIn+x, + pfRealOut+x, pfImaginaryOut+x, + iWidth, iWidth, inverse); + } + + //calculate the fourier transform of the rows + for (unsigned int y = 0; y < iHeight; y++) + { + fastTwoPowerFourierTransform1D(iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + pfRealOut+y*iWidth, + pfImaginaryOut+y*iWidth, + 1, 1, inverse); + } +} + +} diff --git a/src/Globals.cpp b/src/Globals.cpp new file mode 100644 index 0000000..7f93fae --- /dev/null +++ b/src/Globals.cpp @@ -0,0 +1,32 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Globals.h" + +// nothing to see here :) + diff --git a/src/Logger.cpp b/src/Logger.cpp new file mode 100644 index 0000000..28368b2 --- /dev/null +++ b/src/Logger.cpp @@ -0,0 +1,77 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <astra/Logger.h> + +using namespace astra; + +const char * g_loggerFileName = "astra_logger.txt"; + +void CLogger::_assureIsInitialized() +{ + if(!m_bInitialized) + { + m_pOutFile = fopen(g_loggerFileName, "r"); + if(m_pOutFile != NULL) + { + // file exists, users wants to log + fclose(m_pOutFile); + m_pOutFile = fopen(g_loggerFileName, "w"); + } + + m_bInitialized = true; + } +} + +void CLogger::writeLine(const char * _text) +{ + _assureIsInitialized(); + + if(m_pOutFile != NULL) + { + fprintf(m_pOutFile, "%s\n", _text); + fflush(m_pOutFile); + } +} + +void CLogger::writeTerminalCUDAError(const char * _fileName, int _iLine, const char * _errString) +{ + char buffer[256]; + + sprintf(buffer, "Cuda error in file '%s' in line %i : %s.", _fileName, _iLine, _errString); + + writeLine(buffer); +} + +CLogger::CLogger() +{ + ; +} + +FILE * CLogger::m_pOutFile = NULL; +bool CLogger::m_bInitialized = false; diff --git a/src/ParallelBeamBlobKernelProjector2D.cpp b/src/ParallelBeamBlobKernelProjector2D.cpp new file mode 100644 index 0000000..e08f616 --- /dev/null +++ b/src/ParallelBeamBlobKernelProjector2D.cpp @@ -0,0 +1,271 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamBlobKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamBlobKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamBlobKernelProjector2D::type = "blob"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamBlobKernelProjector2D::CParallelBeamBlobKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues) +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry, _fBlobSize, _fBlobSampleRate, _iBlobSampleCount, _pfBlobValues); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamBlobKernelProjector2D::~CParallelBeamBlobKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamBlobKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_pfBlobValues = NULL; + m_iBlobSampleCount = 0; + m_fBlobSize = 0; + m_fBlobSampleRate = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamBlobKernelProjector2D::clear() +{ + CProjector2D::clear(); + if (m_pfBlobValues) { + delete[] m_pfBlobValues; + m_pfBlobValues = NULL; + } + m_iBlobSampleCount = 0; + m_fBlobSize = 0; + m_fBlobSampleRate = 0; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamBlobKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamBlobKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamBlobKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_iBlobSampleCount > 0, "ParallelBeamBlobKernelProjector2D", "m_iBlobSampleCount should be strictly positive."); + ASTRA_CONFIG_CHECK(m_pfBlobValues, "ParallelBeamBlobKernelProjector2D", "Invalid Volume Geometry Object."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamBlobKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // required: Kernel + XMLNode* node = _cfg.self->getSingleNode("Kernel"); + ASTRA_CONFIG_CHECK(node, "BlobProjector", "No Kernel tag specified."); + { + // Required: KernelSize + XMLNode* node2 = node->getSingleNode("KernelSize"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelSize tag specified."); + m_fBlobSize = boost::lexical_cast<float32>(node2->getContent()); + + // Required: SampleRate + node2 = node->getSingleNode("SampleRate"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleRate tag specified."); + m_fBlobSampleRate = boost::lexical_cast<float32>(node2->getContent()); + + // Required: SampleCount + node2 = node->getSingleNode("SampleCount"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/SampleCount tag specified."); + m_iBlobSampleCount = boost::lexical_cast<int>(node2->getContent()); + + // Required: KernelValues + node2 = node->getSingleNode("KernelValues"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValues tag specified."); + vector<float32> values = node2->getContentNumericalArray(); + ASTRA_CONFIG_CHECK(values.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount."); + m_pfBlobValues = new float32[m_iBlobSampleCount]; + for (int i = 0; i < m_iBlobSampleCount; i++) { + m_pfBlobValues[i] = values[i]; + } + + // Required: KernelValues + node2 = node->getSingleNode("KernelValuesNeg"); + ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValuesNeg tag specified."); + vector<float32> values2 = node2->getContentNumericalArray(); + ASTRA_CONFIG_CHECK(values2.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount."); + m_pfBlobValuesNeg = new float32[m_iBlobSampleCount]; + for (int i = 0; i < m_iBlobSampleCount; i++) { + m_pfBlobValuesNeg[i] = values2[i]; + } + + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// initialize +bool CParallelBeamBlobKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry, + float32 _fBlobSize, + float32 _fBlobSampleRate, + int _iBlobSampleCount, + float32* _pfBlobValues) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + ASTRA_CONFIG_CHECK(_pProjectionGeometry, "BlobProjector", "Invalid ProjectionGeometry Object"); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "BlobProjector", "Invalid ProjectionGeometry Object"); + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + m_fBlobSize = _fBlobSize; + m_fBlobSampleRate = _fBlobSampleRate; + m_iBlobSampleCount = _iBlobSampleCount; + m_pfBlobValues = new float32[_iBlobSampleCount]; + for (int i = 0; i <_iBlobSampleCount; i++) { + m_pfBlobValues[i] = _pfBlobValues[i]; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamBlobKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return (int)(maxDim * 2 * (m_fBlobSize+2) + 1); +} +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamBlobKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamBlobKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 x = m_pVolumeGeometry->pixelColToCenterX(_iCol); + float32 y = m_pVolumeGeometry->pixelRowToCenterY(_iRow); + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 t = x * cos(theta) + y * sin(theta); + if (inverse) t *= -1.0f; + + // calculate the offset on the detectorarray (in indices) + float32 d = m_pProjectionGeometry->detectorOffsetToIndexFloat(t); + int dmin = (int)ceil(d - m_fBlobSize); + int dmax = (int)floor(d + m_fBlobSize); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (d >= 0 && d < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} diff --git a/src/ParallelBeamLineKernelProjector2D.cpp b/src/ParallelBeamLineKernelProjector2D.cpp new file mode 100644 index 0000000..16cc614 --- /dev/null +++ b/src/ParallelBeamLineKernelProjector2D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamLineKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamLineKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamLineKernelProjector2D::type = "line"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamLineKernelProjector2D::CParallelBeamLineKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamLineKernelProjector2D::~CParallelBeamLineKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamLineKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamLineKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamLineKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLineKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLineKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLineKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamLineKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamLineKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamLineKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamLineKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Project Point +std::vector<SDetector2D> CParallelBeamLineKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/ParallelBeamLinearKernelProjector2D.cpp b/src/ParallelBeamLinearKernelProjector2D.cpp new file mode 100644 index 0000000..5f1679d --- /dev/null +++ b/src/ParallelBeamLinearKernelProjector2D.cpp @@ -0,0 +1,222 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamLinearKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamLinearKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamLinearKernelProjector2D::type = "linear"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D() +{ + _clear(); +} + + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamLinearKernelProjector2D::CParallelBeamLinearKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamLinearKernelProjector2D::~CParallelBeamLinearKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - CParallelBeamLinearKernelProjector2D +void CParallelBeamLinearKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamLinearKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamLinearKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamLinearKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamLinearKernelProjector2D", "Unsupported projection geometry"); + + /// TODO: ADD PIXEL H/W LIMITATIONS + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamLinearKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamLinearKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamLinearKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamLinearKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + return maxDim * 2 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamLinearKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamLinearKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 1.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 1.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} diff --git a/src/ParallelBeamStripKernelProjector2D.cpp b/src/ParallelBeamStripKernelProjector2D.cpp new file mode 100644 index 0000000..78997af --- /dev/null +++ b/src/ParallelBeamStripKernelProjector2D.cpp @@ -0,0 +1,224 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelBeamStripKernelProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/ParallelBeamStripKernelProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CParallelBeamStripKernelProjector2D::type = "strip"; + +//---------------------------------------------------------------------------------------- +// default constructor +CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CParallelBeamStripKernelProjector2D::CParallelBeamStripKernelProjector2D(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CParallelBeamStripKernelProjector2D::~CParallelBeamStripKernelProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CParallelBeamStripKernelProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CParallelBeamStripKernelProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CParallelBeamStripKernelProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamStripKernelProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamStripKernelProjector2D", "Unsupported projection geometry"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->getPixelLengthX() == m_pVolumeGeometry->getPixelLengthY(), "ParallelBeamStripKernelProjector2D", "Pixel height must equal pixel width."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CParallelBeamStripKernelProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CParallelBeamStripKernelProjector2D::initialize(CParallelProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CParallelBeamStripKernelProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + int maxDim = max(m_pVolumeGeometry->getGridRowCount(), m_pVolumeGeometry->getGridColCount()); + int scale = m_pProjectionGeometry->getDetectorWidth() / min(m_pVolumeGeometry->getPixelLengthX(), m_pVolumeGeometry->getPixelLengthY()); + return maxDim * scale * 10 + 1; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CParallelBeamStripKernelProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CParallelBeamStripKernelProjector2D::projectPoint(int _iRow, int _iCol) +{ + float32 xUL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xUR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yUR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) - m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLL = m_pVolumeGeometry->pixelColToCenterX(_iCol) - m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLL = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + float32 xLR = m_pVolumeGeometry->pixelColToCenterX(_iCol) + m_pVolumeGeometry->getPixelLengthX() * 0.5f; + float32 yLR = m_pVolumeGeometry->pixelRowToCenterY(_iRow) + m_pVolumeGeometry->getPixelLengthY() * 0.5f; + + std::vector<SDetector2D> res; + // loop projectors and detectors + for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + + // get projection angle + float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); + if (theta >= 7*PIdiv4) theta -= 2*PI; + bool inverse = false; + if (theta >= 3*PIdiv4) { + theta -= PI; + inverse = true; + } + + // calculate distance from the center of the voxel to the ray though the origin + float32 tUL = xUL * cos(theta) + yUL * sin(theta); + float32 tUR = xUR * cos(theta) + yUR * sin(theta); + float32 tLL = xLL * cos(theta) + yLL * sin(theta); + float32 tLR = xLR * cos(theta) + yLR * sin(theta); + if (inverse) { + tUL *= -1.0f; + tUR *= -1.0f; + tLL *= -1.0f; + tLR *= -1.0f; + } + float32 tMin = min(tUL, min(tUR, min(tLL,tLR))); + float32 tMax = max(tUL, max(tUR, max(tLL,tLR))); + + // calculate the offset on the detectorarray (in indices) + int dmin = (int)floor(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMin)); + int dmax = (int)ceil(m_pProjectionGeometry->detectorOffsetToIndexFloat(tMax)); + + // add affected detectors to the list + for (int i = dmin; i <= dmax; ++i) { + if (i >= 0 && i < m_pProjectionGeometry->getDetectorCount()) { + SDetector2D det; + det.m_iAngleIndex = iProjection; + det.m_iDetectorIndex = i; + det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; + res.push_back(det); + } + } + } + + // return result vector + return res; + +} + +//---------------------------------------------------------------------------------------- diff --git a/src/ParallelProjectionGeometry2D.cpp b/src/ParallelProjectionGeometry2D.cpp new file mode 100644 index 0000000..79a325b --- /dev/null +++ b/src/ParallelProjectionGeometry2D.cpp @@ -0,0 +1,186 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelProjectionGeometry2D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D() : + CProjectionGeometry2D() +{ + +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + _clear(); + initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _pfExtraDetectorOffsets); +} + +//---------------------------------------------------------------------------------------- +CParallelProjectionGeometry2D::CParallelProjectionGeometry2D(const CParallelProjectionGeometry2D& _projGeom) +{ + _clear(); + initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_fDetectorWidth, + _projGeom.m_pfProjectionAngles, + _projGeom.m_pfExtraDetectorOffset); +} + +//---------------------------------------------------------------------------------------- + +CParallelProjectionGeometry2D& CParallelProjectionGeometry2D::operator=(const CParallelProjectionGeometry2D& _other) +{ + if (m_bInitialized) + delete[] m_pfProjectionAngles; + m_bInitialized = _other.m_bInitialized; + if (_other.m_bInitialized) { + m_iProjectionAngleCount = _other.m_iProjectionAngleCount; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(m_pfProjectionAngles, _other.m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + } + return *this; + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelProjectionGeometry2D::~CParallelProjectionGeometry2D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("ParallelProjectionGeometry2D", this, _cfg); + + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + _initialize(_iProjectionAngleCount, + _iDetectorCount, + _fDetectorWidth, + _pfProjectionAngles, + _pfExtraDetectorOffsets); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CParallelProjectionGeometry2D::clone() +{ + return new CParallelProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry2D + CParallelProjectionGeometry2D* pGeom2 = dynamic_cast<CParallelProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + // if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "parallel"); +} +//---------------------------------------------------------------------------------------- + +CVector3D CParallelProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex /* = 0 */) +{ + CVector3D vOutput; + + float32 fProjectionAngle = getProjectionAngle(_iProjectionIndex); + + vOutput.setX(cosf(fProjectionAngle)); + vOutput.setY(sinf(fProjectionAngle)); + vOutput.setZ(0.0f); + + return vOutput; +} + +} // end namespace astra diff --git a/src/ParallelProjectionGeometry3D.cpp b/src/ParallelProjectionGeometry3D.cpp new file mode 100644 index 0000000..c0366bc --- /dev/null +++ b/src/ParallelProjectionGeometry3D.cpp @@ -0,0 +1,211 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelProjectionGeometry3D.h" + +#include <cstring> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelProjectionGeometry3D::CParallelProjectionGeometry3D() : + CProjectionGeometry3D() +{ + +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelProjectionGeometry3D::CParallelProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX, + const float32* _pfExtraDetectorOffsetsY) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelProjectionGeometry3D::~CParallelProjectionGeometry3D() +{ + +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ParallelProjectionGeometry3D", this, _cfg); + + + // initialization of parent class + CProjectionGeometry3D::initialize(_cfg); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorWidth, + float32 _fDetectorHeight, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsetsX, + const float32* _pfExtraDetectorOffsetsY) +{ + _initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorWidth, + _fDetectorHeight, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CParallelProjectionGeometry3D::clone() const +{ + CParallelProjectionGeometry3D* res = new CParallelProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfProjectionAngles, m_pfProjectionAngles, sizeof(float32)*m_iProjectionAngleCount); + res->m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfExtraDetectorOffsetsX, m_pfExtraDetectorOffsetsX, sizeof(float32)*m_iProjectionAngleCount); + res->m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + memcpy(res->m_pfExtraDetectorOffsetsY, m_pfExtraDetectorOffsetsY, sizeof(float32)*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CParallelProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (m_pfProjectionAngles[i] != pGeom2->m_pfProjectionAngles[i]) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "parallel"); +} + +//---------------------------------------------------------------------------------------- +void CParallelProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","parallel3d"); + _sNode->addChildNode("DetectorSpacingX", m_fDetectorSpacingX); + _sNode->addChildNode("DetectorSpacingY", m_fDetectorSpacingY); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + _sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); + _sNode->addChildNode("ExtraDetectorOffsetsX", m_pfExtraDetectorOffsetsX, m_iProjectionAngleCount); + _sNode->addChildNode("ExtraDetectorOffsetsY", m_pfExtraDetectorOffsetsY, m_iProjectionAngleCount); +} + +CVector3D CParallelProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + float fTheta = m_pfProjectionAngles[_iProjectionIndex]; + + float fDirX = cosf(fTheta); + float fDirY = sinf(fTheta); + float fDirZ = 0.0f; + + return CVector3D(fDirX, fDirY, fDirZ); +} + +CParallelProjectionGeometry2D * CParallelProjectionGeometry3D::createProjectionGeometry2D() const +{ + const float32 * pfProjectionAngles = getProjectionAngles(); //new float32[getProjectionCount()]; + //getProjectionAngles(pfProjectionAngles); + + CParallelProjectionGeometry2D * pOutput = new CParallelProjectionGeometry2D(getProjectionCount(), + getDetectorColCount(), getDetectorSpacingX(), pfProjectionAngles,getExtraDetectorOffsetsX()); + + //delete [] pfProjectionAngles; + + return pOutput; +} + +//---------------------------------------------------------------------------------------- + +} // end namespace astra diff --git a/src/ParallelVecProjectionGeometry3D.cpp b/src/ParallelVecProjectionGeometry3D.cpp new file mode 100644 index 0000000..c1265dd --- /dev/null +++ b/src/ParallelVecProjectionGeometry3D.cpp @@ -0,0 +1,230 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ParallelVecProjectionGeometry3D.h" + +#include <cstring> +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D() : + CProjectionGeometry3D() +{ + m_pProjectionAngles = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CParallelVecProjectionGeometry3D::CParallelVecProjectionGeometry3D(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles + ) : + CProjectionGeometry3D() +{ + initialize(_iProjectionAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _pProjectionAngles); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CParallelVecProjectionGeometry3D::~CParallelVecProjectionGeometry3D() +{ + delete[] m_pProjectionAngles; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CParallelVecProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ParallelVecProjectionGeometry3D", this, _cfg); + + XMLNode* node; + + // TODO: Fix up class hierarchy... this class doesn't fit very well. + // initialization of parent class + //CProjectionGeometry3D::initialize(_cfg); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: Vectors + node = _cfg.self->getSingleNode("Vectors"); + ASTRA_CONFIG_CHECK(node, "ParallelVecProjectionGeometry3D", "No Vectors tag specified."); + vector<double> data = node->getContentNumericalArrayDouble(); + CC.markNodeParsed("Vectors"); + ASTRA_DELETE(node); + ASTRA_CONFIG_CHECK(data.size() % 12 == 0, "ParallelVecProjectionGeometry3D", "Vectors doesn't consist of 12-tuples."); + m_iProjectionAngleCount = data.size() / 12; + m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + SPar3DProjection& p = m_pProjectionAngles[i]; + p.fRayX = data[12*i + 0]; + p.fRayY = data[12*i + 1]; + p.fRayZ = data[12*i + 2]; + p.fDetUX = data[12*i + 6]; + p.fDetUY = data[12*i + 7]; + p.fDetUZ = data[12*i + 8]; + p.fDetVX = data[12*i + 9]; + p.fDetVY = data[12*i + 10]; + p.fDetVZ = data[12*i + 11]; + + // The backend code currently expects the corner of the detector, while + // the matlab interface supplies the center + p.fDetSX = data[12*i + 3] - 0.5f * m_iDetectorRowCount * p.fDetVX - 0.5f * m_iDetectorColCount * p.fDetUX; + p.fDetSY = data[12*i + 4] - 0.5f * m_iDetectorRowCount * p.fDetVY - 0.5f * m_iDetectorColCount * p.fDetUY; + p.fDetSZ = data[12*i + 5] - 0.5f * m_iDetectorRowCount * p.fDetVZ - 0.5f * m_iDetectorColCount * p.fDetUZ; + } + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CParallelVecProjectionGeometry3D::initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + const SPar3DProjection* _pProjectionAngles) +{ + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pProjectionAngles[i] = _pProjectionAngles[i]; + + // TODO: check? + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry3D* CParallelVecProjectionGeometry3D::clone() const +{ + CParallelVecProjectionGeometry3D* res = new CParallelVecProjectionGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iProjectionAngleCount = m_iProjectionAngleCount; + res->m_iDetectorRowCount = m_iDetectorRowCount; + res->m_iDetectorColCount = m_iDetectorColCount; + res->m_iDetectorTotCount = m_iDetectorTotCount; + res->m_fDetectorSpacingX = m_fDetectorSpacingX; + res->m_fDetectorSpacingY = m_fDetectorSpacingY; + res->m_pProjectionAngles = new SPar3DProjection[m_iProjectionAngleCount]; + memcpy(res->m_pProjectionAngles, m_pProjectionAngles, sizeof(m_pProjectionAngles[0])*m_iProjectionAngleCount); + return res; +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CParallelVecProjectionGeometry3D::isEqual(const CProjectionGeometry3D * _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CParallelProjectionGeometry3D + const CParallelVecProjectionGeometry3D* pGeom2 = dynamic_cast<const CParallelVecProjectionGeometry3D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorRowCount != pGeom2->m_iDetectorRowCount) return false; + if (m_iDetectorColCount != pGeom2->m_iDetectorColCount) return false; + if (m_iDetectorTotCount != pGeom2->m_iDetectorTotCount) return false; + //if (m_fDetectorSpacingX != pGeom2->m_fDetectorSpacingX) return false; + //if (m_fDetectorSpacingY != pGeom2->m_fDetectorSpacingY) return false; + + for (int i = 0; i < m_iProjectionAngleCount; ++i) { + if (memcmp(&m_pProjectionAngles[i], &pGeom2->m_pProjectionAngles[i], sizeof(m_pProjectionAngles[i])) != 0) return false; + } + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CParallelVecProjectionGeometry3D::isOfType(const std::string& _sType) const +{ + return (_sType == "parallel3d_vec"); +} + +//---------------------------------------------------------------------------------------- +void CParallelVecProjectionGeometry3D::toXML(XMLNode* _sNode) const +{ + _sNode->addAttribute("type","parallel3d_vec"); + _sNode->addChildNode("DetectorRowCount", m_iDetectorRowCount); + _sNode->addChildNode("DetectorColCount", m_iDetectorColCount); + // TODO: + //_sNode->addChildNode("ProjectionAngles", m_pfProjectionAngles, m_iProjectionAngleCount); +} + +CVector3D CParallelVecProjectionGeometry3D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) const +{ + const SPar3DProjection& p = m_pProjectionAngles[_iProjectionIndex]; + + return CVector3D(p.fRayX, p.fRayY, p.fRayZ); +} + + +//---------------------------------------------------------------------------------------- + +bool CParallelVecProjectionGeometry3D::_check() +{ + // TODO + return true; +} + +} // end namespace astra diff --git a/src/PlatformDepSystemCode.cpp b/src/PlatformDepSystemCode.cpp new file mode 100644 index 0000000..a628aeb --- /dev/null +++ b/src/PlatformDepSystemCode.cpp @@ -0,0 +1,76 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/PlatformDepSystemCode.h" + +using namespace astra; + +#ifdef _WIN32 +#include "windows.h" +// windows API available + +unsigned long CPlatformDepSystemCode::getMSCount() +{ + return ::GetTickCount(); +} + +int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin) +{ + return _fseeki64(_pStream, _iOffset, _iOrigin); +} + +astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream) +{ + return _ftelli64(_pStream); +} + +#else +// linux, ... + +#include <sys/time.h> + +unsigned long CPlatformDepSystemCode::getMSCount() +{ + struct timeval tv; + gettimeofday(&tv, 0); + return (tv.tv_sec * 1000) + (tv.tv_usec/1000); +} + +int CPlatformDepSystemCode::fseek64(FILE * _pStream, astra::int64 _iOffset, int _iOrigin) +{ + return fseeko(_pStream, _iOffset, _iOrigin); +} + +astra::int64 CPlatformDepSystemCode::ftell64(FILE * _pStream) +{ + return ftello(_pStream); +} + + + +#endif diff --git a/src/ProjectionGeometry2D.cpp b/src/ProjectionGeometry2D.cpp new file mode 100644 index 0000000..982a1e4 --- /dev/null +++ b/src/ProjectionGeometry2D.cpp @@ -0,0 +1,203 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ProjectionGeometry2D.h" + +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CProjectionGeometry2D::CProjectionGeometry2D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CProjectionGeometry2D::CProjectionGeometry2D(int _iAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) : configCheckData(0) +{ + _clear(); + _initialize(_iAngleCount, _iDetectorCount, _fDetectorWidth, _pfProjectionAngles,_pfExtraDetectorOffsets); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CProjectionGeometry2D::~CProjectionGeometry2D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +// Should only be used by constructors. Otherwise use the clear() function. +void CProjectionGeometry2D::_clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorCount = 0; + m_fDetectorWidth = 0.0f; + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffset = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CProjectionGeometry2D::clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorCount = 0; + m_fDetectorWidth = 0.0f; + if (m_bInitialized){ + delete[] m_pfProjectionAngles; + delete[] m_pfExtraDetectorOffset; + } + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffset = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check all variable values. +bool CProjectionGeometry2D::_check() +{ + ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "Detector Count should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "Detector Width should be positive."); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "ProjectionAngleCount should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized"); + + // autofix: angles in [0,2pi[ + for (int i = 0; i < m_iProjectionAngleCount; i++) { + while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI; + while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI; + } + + // success + return true; +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("ProjectionGeometry2D", this, _cfg); + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: DetectorWidth + XMLNode* node = _cfg.self->getSingleNode("DetectorWidth"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorWidth tag specified."); + m_fDetectorWidth = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorWidth"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No DetectorCount tag specified."); + m_iDetectorCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorCount"); + + // Required: ProjectionAngles + node = _cfg.self->getSingleNode("ProjectionAngles"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry2D", "No ProjectionAngles tag specified."); + vector<float32> angles = node->getContentNumericalArray(); + delete node; + m_iProjectionAngleCount = angles.size(); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry2D", "Not enough ProjectionAngles specified."); + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = angles[i]; + } + CC.markNodeParsed("ProjectionAngles"); + + vector<float32> offset = _cfg.self->getOptionNumericalArray("ExtraDetectorOffset"); + m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount]; + if (offset.size() == (size_t)m_iProjectionAngleCount) { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffset[i] = offset[i]; + } + } else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffset[i] = 0.0f; + } + } + CC.markOptionParsed("ExtraDetectorOffset"); + + // some checks + ASTRA_CONFIG_CHECK(m_iDetectorCount > 0, "ProjectionGeometry2D", "DetectorCount should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorWidth > 0.0f, "ProjectionGeometry2D", "DetectorWidth should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry2D", "ProjectionAngles not initialized"); + + // Interface class, so don't return true + return false; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CProjectionGeometry2D::_initialize(int _iProjectionAngleCount, + int _iDetectorCount, + float32 _fDetectorWidth, + const float32* _pfProjectionAngles, + const float32* _pfExtraDetectorOffsets) +{ + if (m_bInitialized) { + clear(); + } + + // copy parameters + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + m_fDetectorWidth = _fDetectorWidth; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffset = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = _pfProjectionAngles[i]; + m_pfExtraDetectorOffset[i] = _pfExtraDetectorOffsets ? _pfExtraDetectorOffsets[i]:0; + } + + // Interface class, so don't set m_bInitialized to true + return true; +} +//--------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ProjectionGeometry3D.cpp b/src/ProjectionGeometry3D.cpp new file mode 100644 index 0000000..b78b7b8 --- /dev/null +++ b/src/ProjectionGeometry3D.cpp @@ -0,0 +1,329 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ProjectionGeometry3D.h" + +#include <boost/lexical_cast.hpp> + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values. +bool CProjectionGeometry3D::_check() +{ + ASTRA_CONFIG_CHECK(m_iDetectorRowCount > 0, "ProjectionGeometry3D", "DetectorRowCount should be positive."); + ASTRA_CONFIG_CHECK(m_iDetectorColCount > 0, "ProjectionGeometry3D", "DetectorColCount should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorSpacingX > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingX should be positive."); + ASTRA_CONFIG_CHECK(m_fDetectorSpacingY > 0.0f, "ProjectionGeometry3D", "m_fDetectorSpacingY should be positive."); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "ProjectionAngleCount should be positive."); + ASTRA_CONFIG_CHECK(m_pfProjectionAngles != NULL, "ProjectionGeometry3D", "ProjectionAngles not initialized"); + +/* + // autofix: angles in [0,2pi[ + for (int i = 0; i < m_iProjectionAngleCount; i++) { + while (2*PI <= m_pfProjectionAngles[i]) m_pfProjectionAngles[i] -= 2*PI; + while (m_pfProjectionAngles[i] < 0) m_pfProjectionAngles[i] += 2*PI; + } +*/ + + // succes + return true; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CProjectionGeometry3D::CProjectionGeometry3D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CProjectionGeometry3D::CProjectionGeometry3D(int _iAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32 *_pfProjectionAngles, + const float32 *_pfExtraDetectorOffsetsX, + const float32 *_pfExtraDetectorOffsetsY) : configCheckData(0) +{ + _clear(); + _initialize(_iAngleCount, + _iDetectorRowCount, + _iDetectorColCount, + _fDetectorSpacingX, + _fDetectorSpacingY, + _pfProjectionAngles, + _pfExtraDetectorOffsetsX, + _pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Copy constructor. +CProjectionGeometry3D::CProjectionGeometry3D(const CProjectionGeometry3D& _projGeom) +{ + _clear(); + _initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorRowCount, + _projGeom.m_iDetectorColCount, + _projGeom.m_fDetectorSpacingX, + _projGeom.m_fDetectorSpacingY, + _projGeom.m_pfProjectionAngles, + _projGeom.m_pfExtraDetectorOffsetsX, + _projGeom.m_pfExtraDetectorOffsetsY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CProjectionGeometry3D::~CProjectionGeometry3D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +// Should only be used by constructors. Otherwise use the clear() function. +void CProjectionGeometry3D::_clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorRowCount = 0; + m_iDetectorColCount = 0; + m_fDetectorSpacingX = 0.0f; + m_fDetectorSpacingY = 0.0f; + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffsetsX = NULL; + m_pfExtraDetectorOffsetsY = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CProjectionGeometry3D::clear() +{ + m_iProjectionAngleCount = 0; + m_iDetectorRowCount = 0; + m_iDetectorColCount = 0; + m_fDetectorSpacingX = 0.0f; + m_fDetectorSpacingY = 0.0f; + if (m_pfProjectionAngles != NULL) { + delete [] m_pfProjectionAngles; + } + if (m_pfExtraDetectorOffsetsX != NULL) { + delete [] m_pfExtraDetectorOffsetsX; + } + if (m_pfExtraDetectorOffsetsY != NULL) { + delete [] m_pfExtraDetectorOffsetsY; + } + m_pfProjectionAngles = NULL; + m_pfExtraDetectorOffsetsX = NULL; + m_pfExtraDetectorOffsetsY = NULL; + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Initialization witha Config object +bool CProjectionGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry3D> CC("ProjectionGeometry3D", this, _cfg); + + if (m_bInitialized) { + clear(); + } + + ASTRA_ASSERT(_cfg.self); + + // Required: DetectorWidth + XMLNode* node = _cfg.self->getSingleNode("DetectorSpacingX"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingX tag specified."); + m_fDetectorSpacingX = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorSpacingX"); + + // Required: DetectorHeight + node = _cfg.self->getSingleNode("DetectorSpacingY"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorSpacingY tag specified."); + m_fDetectorSpacingY = boost::lexical_cast<float32>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorSpacingY"); + + // Required: DetectorRowCount + node = _cfg.self->getSingleNode("DetectorRowCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorRowCount tag specified."); + m_iDetectorRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorRowCount"); + + // Required: DetectorCount + node = _cfg.self->getSingleNode("DetectorColCount"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No DetectorColCount tag specified."); + m_iDetectorColCount = boost::lexical_cast<int>(node->getContent()); + m_iDetectorTotCount = m_iDetectorRowCount * m_iDetectorColCount; + ASTRA_DELETE(node); + CC.markNodeParsed("DetectorColCount"); + + // Required: ProjectionAngles + node = _cfg.self->getSingleNode("ProjectionAngles"); + ASTRA_CONFIG_CHECK(node, "ProjectionGeometry3D", "No ProjectionAngles tag specified."); + vector<float32> angles = node->getContentNumericalArray(); + m_iProjectionAngleCount = angles.size(); + ASTRA_CONFIG_CHECK(m_iProjectionAngleCount > 0, "ProjectionGeometry3D", "Not enough ProjectionAngles specified."); + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = angles[i]; + } + CC.markNodeParsed("ProjectionAngles"); + ASTRA_DELETE(node); + + // Optional: ExtraDetectorOffsetX + node = _cfg.self->getSingleNode("ExtraDetectorOffsetsX"); + m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + if (node) { + vector<float32> translationsX = node->getContentNumericalArray(); + if (translationsX.size() < m_iProjectionAngleCount){ + cout << "Not enough ExtraDetectorOffsetsX components specified. " << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = 0; + } + } + else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = translationsX[i]; + } + } + } + else { + //cout << "No ExtraDetectorOffsetsX tag specified." << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsX[i] = 0; + } + } + CC.markOptionParsed("ExtraDetectorOffsetsX"); + ASTRA_DELETE(node); + + // Optional: ExtraDetectorOffsetsY + node = _cfg.self->getSingleNode("ExtraDetectorOffsetsY"); + m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + if (node) { + vector<float32> translationsX = node->getContentNumericalArray(); + if (translationsX.size() < m_iProjectionAngleCount){ + cout << "Not enough ExtraDetectorOffsetsY components specified. " << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = 0; + } + } + else { + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = translationsX[i]; + } + } + } + else { + //cout << "No ExtraDetectorOffsetsY tag specified." << endl; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfExtraDetectorOffsetsY[i] = 0; + } + } + CC.markOptionParsed("ExtraDetectorOffsetsY"); + ASTRA_DELETE(node); + + // Interface class, so don't return true + return false; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CProjectionGeometry3D::_initialize(int _iProjectionAngleCount, + int _iDetectorRowCount, + int _iDetectorColCount, + float32 _fDetectorSpacingX, + float32 _fDetectorSpacingY, + const float32 *_pfProjectionAngles, + const float32 *_pfExtraDetectorOffsetsX, + const float32 *_pfExtraDetectorOffsetsY) +{ + if (m_bInitialized) { + clear(); + } + + // copy parameters + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorRowCount = _iDetectorRowCount; + m_iDetectorColCount = _iDetectorColCount; + m_iDetectorTotCount = _iDetectorRowCount * _iDetectorColCount; + m_fDetectorSpacingX = _fDetectorSpacingX; + m_fDetectorSpacingY = _fDetectorSpacingY; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffsetsX = new float32[m_iProjectionAngleCount]; + m_pfExtraDetectorOffsetsY = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; i++) { + m_pfProjectionAngles[i] = _pfProjectionAngles[i]; + m_pfExtraDetectorOffsetsX[i] = _pfExtraDetectorOffsetsX ? _pfExtraDetectorOffsetsX[i]:0; + m_pfExtraDetectorOffsetsY[i] = _pfExtraDetectorOffsetsY ? _pfExtraDetectorOffsetsY[i]:0; + //m_pfExtraDetectorOffsetsX[i] = 0; + //m_pfExtraDetectorOffsetsY[i] = 0; + } + + m_iDetectorTotCount = m_iProjectionAngleCount * m_iDetectorRowCount * m_iDetectorColCount; + + // Interface class, so don't return true + return false; +} + +//--------------------------------------------------------------------------------------- +// +AstraError CProjectionGeometry3D::setExtraDetectorOffsetsX(float32* _pfExtraDetectorOffsetsX) +{ + if (!m_bInitialized) + return ASTRA_ERROR_NOT_INITIALIZED; + + for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++) + m_pfExtraDetectorOffsetsX[iAngle] = _pfExtraDetectorOffsetsX[iAngle]; + + return ASTRA_SUCCESS; +} + +//--------------------------------------------------------------------------------------- +// +AstraError CProjectionGeometry3D::setExtraDetectorOffsetsY(float32* _pfExtraDetectorOffsetsY) +{ + if (!m_bInitialized) + return ASTRA_ERROR_NOT_INITIALIZED; + + for (int iAngle = 0; iAngle<m_iProjectionAngleCount; iAngle++) + m_pfExtraDetectorOffsetsY[iAngle] = _pfExtraDetectorOffsetsY[iAngle]; + + return ASTRA_SUCCESS; +} +} // namespace astra diff --git a/src/Projector2D.cpp b/src/Projector2D.cpp new file mode 100644 index 0000000..e67cd0c --- /dev/null +++ b/src/Projector2D.cpp @@ -0,0 +1,217 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Projector2D.h" + +#include "astra/FanFlatProjectionGeometry2D.h" +#include "astra/FanFlatVecProjectionGeometry2D.h" +#include "astra/SparseMatrixProjectionGeometry2D.h" +#include "astra/SparseMatrix.h" + + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// constructor +CProjector2D::CProjector2D() : configCheckData(0) +{ + + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// constructor +CProjector2D::CProjector2D(CProjectionGeometry2D* _pProjectionGeometry, CVolumeGeometry2D* _pVolumeGeometry) : configCheckData(0) +{ + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + m_bIsInitialized = true; +} + +//---------------------------------------------------------------------------------------- +// destructor +CProjector2D::~CProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CProjector2D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CProjector2D::clear() +{ + if (m_pProjectionGeometry) { + delete m_pProjectionGeometry; + m_pProjectionGeometry = NULL; + } + if (m_pVolumeGeometry) { + delete m_pVolumeGeometry; + m_pVolumeGeometry = NULL; + } + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CProjector2D::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector2D", "Invalid Projection Geometry Object."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector2D", "Invalid Volume Geometry Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "Projection Geometry Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "Volume Geometry Object Not Initialized."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjector2D> CC("Projector2D", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required: ProjectionGeometry + XMLNode* node = _cfg.self->getSingleNode("ProjectionGeometry"); + ASTRA_CONFIG_CHECK(node, "Projector2D", "No ProjectionGeometry tag specified."); + + // FIXME: Change how the base class is created. (This is duplicated + // in astra_mex_data2d.cpp.) + std::string type = node->getAttribute("type"); + if (type == "sparse_matrix") { + m_pProjectionGeometry = new CSparseMatrixProjectionGeometry2D(); + m_pProjectionGeometry->initialize(Config(node)); + } else if (type == "fanflat") { + CFanFlatProjectionGeometry2D* pFanFlatProjectionGeometry = new CFanFlatProjectionGeometry2D(); + pFanFlatProjectionGeometry->initialize(Config(node)); + m_pProjectionGeometry = pFanFlatProjectionGeometry; + } else if (type == "fanflat_vec") { + CFanFlatVecProjectionGeometry2D* pFanFlatVecProjectionGeometry = new CFanFlatVecProjectionGeometry2D(); + pFanFlatVecProjectionGeometry->initialize(Config(node)); + m_pProjectionGeometry = pFanFlatVecProjectionGeometry; + } else { + m_pProjectionGeometry = new CParallelProjectionGeometry2D(); + m_pProjectionGeometry->initialize(Config(node)); + } + // "node" is deleted by the temp Config(node) objects + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector2D", "ProjectionGeometry not initialized."); + CC.markNodeParsed("ProjectionGeometry"); + + + // required: VolumeGeometry + node = _cfg.self->getSingleNode("VolumeGeometry"); + ASTRA_CONFIG_CHECK(node, "Projector2D", "No VolumeGeometry tag specified."); + m_pVolumeGeometry = new CVolumeGeometry2D(); + m_pVolumeGeometry->initialize(Config(node)); + // "node" is deleted by the temp Config(node) object + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector2D", "VolumeGeometry not initialized."); + CC.markNodeParsed("VolumeGeometry"); + + return true; +} + +//---------------------------------------------------------------------------------------- +// weights of each detector in a projection angle +void CProjector2D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount) +{ + int iPixelBufferSize = getProjectionWeightsCount(_iProjection); + + int iDetector; + for(iDetector = m_pProjectionGeometry->getDetectorCount()-1; iDetector >= 0; --iDetector) { + computeSingleRayWeights(_iProjection, // projector index + iDetector, // detector index + &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer + iPixelBufferSize, // pixel buffer size + _piRayStoredPixelCount[iDetector]); // stored pixel count + } + +} + +//---------------------------------------------------------------------------------------- +// explicit projection matrix +CSparseMatrix* CProjector2D::getMatrix() +{ + unsigned int iProjectionCount = m_pProjectionGeometry->getProjectionAngleCount(); + unsigned int iDetectorCount = m_pProjectionGeometry->getDetectorCount(); + unsigned int iRayCount = iProjectionCount * iDetectorCount; + unsigned int iVolumeSize = m_pVolumeGeometry->getGridTotCount(); + unsigned long lSize = 0; + unsigned int iMaxRayLength = 0; + for (unsigned int i = 0; i < iProjectionCount; ++i) { + unsigned int iRayLength = getProjectionWeightsCount(i); + lSize += iDetectorCount * iRayLength; + if (iRayLength > iMaxRayLength) + iMaxRayLength = iRayLength; + } + CSparseMatrix* pMatrix = new CSparseMatrix(iRayCount, iVolumeSize, lSize); + + if (!pMatrix || !pMatrix->isInitialized()) { + delete pMatrix; + return 0; + } + + SPixelWeight* pEntries = new SPixelWeight[iMaxRayLength]; + unsigned long lMatrixIndex = 0; + for (unsigned int iRay = 0; iRay < iRayCount; ++iRay) { + pMatrix->m_plRowStarts[iRay] = lMatrixIndex; + int iPixelCount; + int iProjIndex, iDetIndex; + m_pProjectionGeometry->indexToAngleDetectorIndex(iRay, iProjIndex, iDetIndex); + computeSingleRayWeights(iProjIndex, iDetIndex, pEntries, iMaxRayLength, iPixelCount); + + for (int i = 0; i < iPixelCount; ++i) { + pMatrix->m_piColIndices[lMatrixIndex] = pEntries[i].m_iIndex; + pMatrix->m_pfValues[lMatrixIndex] = pEntries[i].m_fWeight; + ++lMatrixIndex; + } + + } + pMatrix->m_plRowStarts[iRayCount] = lMatrixIndex; + + delete[] pEntries; + return pMatrix; +} + +} // end namespace diff --git a/src/Projector3D.cpp b/src/Projector3D.cpp new file mode 100644 index 0000000..f8fddf4 --- /dev/null +++ b/src/Projector3D.cpp @@ -0,0 +1,121 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Projector3D.h" + + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor +CProjector3D::CProjector3D() : configCheckData(0) +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CProjector3D::~CProjector3D() +{ + if (m_bIsInitialized) clear(); +} + +//---------------------------------------------------------------------------------------- +// Clear for constructors +void CProjector3D::_clear() +{ + m_pProjectionGeometry = NULL; + m_pVolumeGeometry = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Clear +void CProjector3D::clear() +{ + ASTRA_DELETE(m_pProjectionGeometry); + ASTRA_DELETE(m_pVolumeGeometry); + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CProjector3D::_check() +{ + // projection geometry + ASTRA_CONFIG_CHECK(m_pProjectionGeometry, "Projector3D", "ProjectionGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "Projector3D", "ProjectionGeometry3D not initialized."); + + // volume geometry + ASTRA_CONFIG_CHECK(m_pVolumeGeometry, "Projector3D", "VolumeGeometry3D not initialized."); + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "Projector3D", "VolumeGeometry3D not initialized."); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CProjector3D::initialize(const Config& _cfg) +{ + assert(_cfg.self); + + return true; +} + +/* +bool CProjector3D::initialize(astra::CProjectionGeometry3D *, astra::CVolumeGeometry3D *) +{ + ASTRA_ASSERT(false); + + return false; +} +*/ + +//---------------------------------------------------------------------------------------- +// Weights of each detector in a projection angle +void CProjector3D::computeProjectionRayWeights(int _iProjection, SPixelWeight* _pfWeightedPixels, int* _piRayStoredPixelCount) +{ + int iPixelBufferSize = getProjectionWeightsCount(_iProjection); + + int iDetector = 0; + for(iDetector = m_pProjectionGeometry->getDetectorTotCount()-1; iDetector >= 0; --iDetector) { + int iSliceIndex = iDetector / m_pProjectionGeometry->getDetectorColCount(); + int iDetectorColIndex = iDetector % m_pProjectionGeometry->getDetectorColCount(); + + computeSingleRayWeights(_iProjection, // projector index + iSliceIndex, // slice index + iDetectorColIndex, // detector index + &_pfWeightedPixels[iDetector*iPixelBufferSize], // pixel buffer + iPixelBufferSize, // pixel buffer size + _piRayStoredPixelCount[iDetector]); // stored pixel count + } +} +//---------------------------------------------------------------------------------------- + +} // end namespace diff --git a/src/ReconstructionAlgorithm2D.cpp b/src/ReconstructionAlgorithm2D.cpp new file mode 100644 index 0000000..ea693e3 --- /dev/null +++ b/src/ReconstructionAlgorithm2D.cpp @@ -0,0 +1,275 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithm2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithm2D::CReconstructionAlgorithm2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithm2D::~CReconstructionAlgorithm2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithm2D::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithm2D::clear() +{ + // Nothing to delete, so just _clear() + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithm2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm2D", this, _cfg); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectorId"); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithm2D::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithm2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithm2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CReconstructionAlgorithm2D::setSinogramMask(CFloat32ProjectionData2D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +}//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithm2D::_check() +{ + // check pointers + ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction2D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction2D", "Invalid Reconstruction Data Object."); + + // check initializations + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction2D", "Projector Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction2D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction2D", "Reconstruction Data Object Not Initialized."); + + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector."); + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithm2D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithm2D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ReconstructionAlgorithm3D.cpp b/src/ReconstructionAlgorithm3D.cpp new file mode 100644 index 0000000..4d9bbc6 --- /dev/null +++ b/src/ReconstructionAlgorithm3D.cpp @@ -0,0 +1,306 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithm3D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithm3D::CReconstructionAlgorithm3D() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithm3D::~CReconstructionAlgorithm3D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithm3D::_clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithm3D::clear() +{ + m_pProjector = NULL; + m_pSinogram = NULL; + m_pReconstruction = NULL; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithm3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithm3D", this, _cfg); + + XMLNode* node; + int id; +#if 0 + // projector + node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectorId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector3DManager::getSingleton().get(id); + ASTRA_DELETE(node); +#endif + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ProjectionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pSinogram = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction3D", "No ReconstructionDataId tag specified."); + id = boost::lexical_cast<int>(node->getContent()); + m_pReconstruction = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id)); + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // fixed mask + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData3D*>(CData3DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // fixed mask + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData3D*>(CData3DManager::getSingleton().get(id)); + } + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithm3D::initialize(CProjector3D* _pProjector, + CFloat32ProjectionData3D* _pSinogram, + CFloat32VolumeData3D* _pReconstruction) +{ + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithm3D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithm3D::setReconstructionMask(CFloat32VolumeData3D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches volume + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Sinogram Mask +void CReconstructionAlgorithm3D::setSinogramMask(CFloat32ProjectionData3D* _pMask, bool _bEnable) +{ + // TODO: check geometry matches sinogram + m_bUseSinogramMask = _bEnable; + m_pSinogramMask = _pMask; + if (m_pSinogramMask == NULL) { + m_bUseSinogramMask = false; + } +}//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithm3D::_check() +{ + // check pointers +#if 0 + ASTRA_CONFIG_CHECK(m_pProjector, "Reconstruction3D", "Invalid Projector Object."); +#endif + ASTRA_CONFIG_CHECK(m_pSinogram, "Reconstruction3D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_pReconstruction, "Reconstruction3D", "Invalid Reconstruction Data Object."); + + // check initializations +#if 0 + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "Reconstruction3D", "Projector Object Not Initialized."); +#endif + ASTRA_CONFIG_CHECK(m_pSinogram->isInitialized(), "Reconstruction3D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_pReconstruction->isInitialized(), "Reconstruction3D", "Reconstruction Data Object Not Initialized."); + +#if 0 + // check compatibility between projector and data classes + ASTRA_CONFIG_CHECK(m_pSinogram->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction3D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_pReconstruction->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction3D", "Reconstruction Data not compatible with the specified Projector."); +#endif + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithm3D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); + res["ProjectionDataId"] = getInformation("ProjectionDataId"); + res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithm3D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } +#if 0 + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector3DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } +#endif + if (_sIdentifier == "ProjectionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pSinogram); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionDataId") { + int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstruction); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData3DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/ReconstructionAlgorithmMultiSlice2D.cpp b/src/ReconstructionAlgorithmMultiSlice2D.cpp new file mode 100644 index 0000000..648db61 --- /dev/null +++ b/src/ReconstructionAlgorithmMultiSlice2D.cpp @@ -0,0 +1,288 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/ReconstructionAlgorithmMultiSlice2D.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" + +using namespace std; + +namespace astra { + +//---------------------------------------------------------------------------------------- +// Constructor +CReconstructionAlgorithmMultiSlice2D::CReconstructionAlgorithmMultiSlice2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CReconstructionAlgorithmMultiSlice2D::~CReconstructionAlgorithmMultiSlice2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CReconstructionAlgorithmMultiSlice2D::_clear() +{ + m_pProjector = NULL; + m_iSliceCount = 0; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CReconstructionAlgorithmMultiSlice2D::clear() +{ + m_pProjector = NULL; + m_vpSinogram.clear(); + m_vpReconstruction.clear(); + m_iSliceCount = 0; + m_bUseMinConstraint = false; + m_fMinValue = 0.0f; + m_bUseMaxConstraint = false; + m_fMaxValue = 0.0f; + m_bUseReconstructionMask = false; + m_pReconstructionMask = NULL; + m_bUseSinogramMask = false; + m_pSinogramMask = NULL; + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CReconstructionAlgorithmMultiSlice2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("ReconstructionAlgorithmMultiSlice2D", this, _cfg); + + // projector + XMLNode* node = _cfg.self->getSingleNode("ProjectorId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectorId tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pProjector = CProjector2DManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectorId"); + + // sinogram data + node = _cfg.self->getSingleNode("ProjectionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ProjectionDataId tag specified."); + vector<float32> tmpvector = node->getContentNumericalArray(); + for (unsigned int i = 0; i < tmpvector.size(); ++i) { + m_vpSinogram.push_back(dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i])))); + } + m_iSliceCount = tmpvector.size(); + ASTRA_DELETE(node); + CC.markNodeParsed("ProjectionDataId"); + + // reconstruction data + node = _cfg.self->getSingleNode("ReconstructionDataId"); + ASTRA_CONFIG_CHECK(node, "Reconstruction2D", "No ReconstructionDataId tag specified."); + tmpvector = node->getContentNumericalArray(); + for (unsigned int i = 0; i < tmpvector.size(); ++i) { + m_vpReconstruction.push_back(dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(int(tmpvector[i])))); + } + ASTRA_DELETE(node); + CC.markNodeParsed("ReconstructionDataId"); + + // reconstruction masks + if (_cfg.self->hasOption("ReconstructionMaskId")) { + m_bUseReconstructionMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("ReconstructionMaskId")); + m_pReconstructionMask = dynamic_cast<CFloat32VolumeData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("ReconstructionMaskId"); + + // sinogram masks + if (_cfg.self->hasOption("SinogramMaskId")) { + m_bUseSinogramMask = true; + id = boost::lexical_cast<int>(_cfg.self->getOption("SinogramMaskId")); + m_pSinogramMask = dynamic_cast<CFloat32ProjectionData2D*>(CData2DManager::getSingleton().get(id)); + } + CC.markOptionParsed("SinogramMaskId"); + + // Constraints - NEW + if (_cfg.self->hasOption("MinConstraint")) { + m_bUseMinConstraint = true; + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraint", 0.0f); + CC.markOptionParsed("MinConstraint"); + } else { + // Constraint - OLD + m_bUseMinConstraint = _cfg.self->getOptionBool("UseMinConstraint", false); + CC.markOptionParsed("UseMinConstraint"); + if (m_bUseMinConstraint) { + m_fMinValue = _cfg.self->getOptionNumerical("MinConstraintValue", 0.0f); + CC.markOptionParsed("MinConstraintValue"); + } + } + if (_cfg.self->hasOption("MaxConstraint")) { + m_bUseMaxConstraint = true; + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraint", 255.0f); + CC.markOptionParsed("MaxConstraint"); + } else { + // Constraint - OLD + m_bUseMaxConstraint = _cfg.self->getOptionBool("UseMaxConstraint", false); + CC.markOptionParsed("UseMaxConstraint"); + if (m_bUseMaxConstraint) { + m_fMaxValue = _cfg.self->getOptionNumerical("MaxConstraintValue", 0.0f); + CC.markOptionParsed("MaxConstraintValue"); + } + } + + // return success + return _check(); +} + +//---------------------------------------------------------------------------------------- +// Initialize - C++ +bool CReconstructionAlgorithmMultiSlice2D::initialize(CProjector2D* _pProjector, + vector<CFloat32ProjectionData2D*> _vpSinogram, + vector<CFloat32VolumeData2D*> _vpReconstruction) +{ + m_pProjector = _pProjector; + m_vpSinogram = _vpSinogram; + m_vpReconstruction = _vpReconstruction; + m_iSliceCount = _vpSinogram.size(); + + // return success + return _check(); +} + +//--------------------------------------------------------------------------------------- +// Set Constraints +void CReconstructionAlgorithmMultiSlice2D::setConstraints(bool _bUseMin, float32 _fMinValue, bool _bUseMax, float32 _fMaxValue) +{ + m_bUseMinConstraint = _bUseMin; + m_fMinValue = _fMinValue; + m_bUseMaxConstraint = _bUseMax; + m_fMaxValue = _fMaxValue; +} + +//---------------------------------------------------------------------------------------- +// Set Fixed Reconstruction Mask +void CReconstructionAlgorithmMultiSlice2D::setReconstructionMask(CFloat32VolumeData2D* _pMask, bool _bEnable) +{ + m_bUseReconstructionMask = _bEnable; + m_pReconstructionMask = _pMask; + if (m_pReconstructionMask == NULL) { + m_bUseReconstructionMask = false; + } +} + +//---------------------------------------------------------------------------------------- +// Check +bool CReconstructionAlgorithmMultiSlice2D::_check() +{ + // check projector + ASTRA_CONFIG_CHECK(m_pProjector, "ReconstructionMultiSlice2D", "Invalid Projector Object."); + ASTRA_CONFIG_CHECK(m_pProjector->isInitialized(), "ReconstructionMultiSlice2D", "Projector Object Not Initialized."); + + // check list + ASTRA_CONFIG_CHECK(m_vpSinogram.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Sinogram slicecount mismatch."); + ASTRA_CONFIG_CHECK(m_vpReconstruction.size() == (unsigned int)m_iSliceCount, "ReconstructionMultiSlice2D", "Volume slicecount mismatch."); + + for (int i = 0; i < m_iSliceCount; ++i) { + // pointers + ASTRA_CONFIG_CHECK(m_vpSinogram[i], "ReconstructionMultiSlice2D", "Invalid Projection Data Object."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i], "ReconstructionMultiSlice2D", "Invalid Volume Data Object."); + + // initialized + ASTRA_CONFIG_CHECK(m_vpSinogram[i]->isInitialized(), "ReconstructionMultiSlice2D", "Projection Data Object Not Initialized."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->isInitialized(), "ReconstructionMultiSlice2D", "Volume Data Object Not Initialized."); + + // geometry compatibility + ASTRA_CONFIG_CHECK(m_vpSinogram[i]->getGeometry()->isEqual(m_pProjector->getProjectionGeometry()), "Reconstruction2D", "Projection Data not compatible with the specified Projector."); + ASTRA_CONFIG_CHECK(m_vpReconstruction[i]->getGeometry()->isEqual(m_pProjector->getVolumeGeometry()), "Reconstruction2D", "Reconstruction Data not compatible with the specified Projector."); + } + + // success + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CReconstructionAlgorithmMultiSlice2D::getInformation() +{ + map<string, boost::any> res; + res["ProjectorId"] = getInformation("ProjectorId"); +// res["ProjectionDataId"] = getInformation("ProjectionDataId"); +// res["ReconstructionDataId"] = getInformation("ReconstructionDataId"); + res["UseMinConstraint"] = getInformation("UseMinConstraint"); + res["MinConstraintValue"] = getInformation("MinConstraintValue"); + res["UseMaxConstraint"] = getInformation("UseMaxConstraint"); + res["MaxConstraintValue"] = getInformation("MaxConstraintValue"); + res["ReconstructionMaskId"] = getInformation("ReconstructionMaskId"); + return mergeMap<string,boost::any>(CAlgorithm::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CReconstructionAlgorithmMultiSlice2D::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "UseMinConstraint") { return m_bUseMinConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MinConstraintValue") { return m_fMinValue; } + if (_sIdentifier == "UseMaxConstraint") { return m_bUseMaxConstraint ? string("yes") : string("no"); } + if (_sIdentifier == "MaxConstraintValue") { return m_fMaxValue; } + if (_sIdentifier == "ProjectorId") { + int iIndex = CProjector2DManager::getSingleton().getIndex(m_pProjector); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } +// if (_sIdentifier == "ProjectionDataId") { +// int iIndex = CData2DManager::getSingleton().getIndex(m_pSinogram); +// if (iIndex != 0) return iIndex; +// return std::string("not in manager"); +// } +// if (_sIdentifier == "ReconstructionDataId") { +// int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstruction); +// if (iIndex != 0) return iIndex; +// return std::string("not in manager"); +// } + if (_sIdentifier == "ReconstructionMaskId") { + if (!m_bUseReconstructionMask) return string("not used"); + int iIndex = CData2DManager::getSingleton().getIndex(m_pReconstructionMask); + if (iIndex != 0) return iIndex; + return std::string("not in manager"); + } + return CAlgorithm::getInformation(_sIdentifier); +}; +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp new file mode 100644 index 0000000..d898297 --- /dev/null +++ b/src/SartAlgorithm.cpp @@ -0,0 +1,452 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SartAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CSartAlgorithm::type = "SART"; + + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSartAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_piProjectionOrder = NULL; + m_iProjectionCount = 0; + m_iCurrentProjection = 0; + m_bIsInitialized = false; + m_iIterationCount = 0; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSartAlgorithm::clear() +{ + CReconstructionAlgorithm2D::clear(); + if (m_piProjectionOrder) { + delete[] m_piProjectionOrder; + m_piProjectionOrder = NULL; + } + m_iProjectionCount = 0; + m_iCurrentProjection = 0; + m_bIsInitialized = false; + m_iIterationCount = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Constructor +CSartAlgorithm::CSartAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction, _piProjectionOrder, _iProjectionCount); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CSartAlgorithm::~CSartAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSartAlgorithm::initialize(const Config& _cfg) +{ + assert(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("SartAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // projection order + m_iCurrentProjection = 0; + m_iProjectionCount = m_pProjector->getProjectionGeometry()->getProjectionAngleCount(); + string projOrder = _cfg.self->getOption("ProjectionOrder", "sequential"); + CC.markOptionParsed("ProjectionOrder"); + if (projOrder == "sequential") { + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + } else if (projOrder == "random") { + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + for (int i = 0; i < m_iProjectionCount-1; i++) { + int k = (rand() % (m_iProjectionCount - i)); + int t = m_piProjectionOrder[i]; + m_piProjectionOrder[i] = m_piProjectionOrder[i + k]; + m_piProjectionOrder[i + k] = t; + } + } else if (projOrder == "custom") { + vector<float32> projOrderList = _cfg.self->getOptionNumericalArray("ProjectionOrderList"); + m_piProjectionOrder = new int[projOrderList.size()]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = static_cast<int>(projOrderList[i]); + } + CC.markOptionParsed("ProjectionOrderList"); + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentProjection = 0; + m_iProjectionCount = _pProjector->getProjectionGeometry()->getProjectionAngleCount(); + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = i; + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSartAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction, + int* _piProjectionOrder, + int _iProjectionCount) +{ + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // ray order + m_iCurrentProjection = 0; + m_iProjectionCount = _iProjectionCount; + m_piProjectionOrder = new int[m_iProjectionCount]; + for (int i = 0; i < m_iProjectionCount; i++) { + m_piProjectionOrder[i] = _piProjectionOrder[i]; + } + + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//---------------------------------------------------------------------------------------- +bool CSartAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SART", "Error in ReconstructionAlgorithm2D initialization"); + + // check projection order all within range + for (int i = 0; i < m_iProjectionCount; ++i) { + ASTRA_CONFIG_CHECK(0 <= m_piProjectionOrder[i] && m_piProjectionOrder[i] < m_pProjector->getProjectionGeometry()->getProjectionAngleCount(), "SART", "Projection Order out of range."); + } + + return true; +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CSartAlgorithm::getInformation() +{ + map<string, boost::any> res; + res["ProjectionOrder"] = getInformation("ProjectionOrder"); + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CSartAlgorithm::getInformation(std::string _sIdentifier) +{ + if (_sIdentifier == "ProjectionOrder") { + vector<float32> res; + for (int i = 0; i < m_iProjectionCount; i++) { + res.push_back(m_piProjectionOrder[i]); + } + return res; + } + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CSartAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + int iIteration = 0; + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + + m_pTotalRayLength->setData(0.0f); + m_pTotalPixelWeight->setData(0.0f); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength), // SIRT backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // first time forward projection data projector, + // also computes total pixel weight and total ray length + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights + TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + // iteration loop + for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + + int iProjection = m_piProjectionOrder[m_iIterationCount % m_iProjectionCount]; + + // forward projection and difference calculation + m_pTotalPixelWeight->setData(0.0f); + pForwardProjector->projectSingleProjection(iProjection); + // backprojection + pBackProjector->projectSingleProjection(iProjection); + // update iteration count + m_iIterationCount++; + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + } + + + ASTRA_DELETE(pForwardProjector); + ASTRA_DELETE(pBackProjector); + + + + + + + + + + + + + + + //// check initialized + // ASTRA_ASSERT(m_bIsInitialized); + + //// variables + //int iIteration, iDetector; + //int baseIndex, iPixel; + //float32* pfGamma = new float32[m_pReconstruction->getSize()]; + //float32* pfBeta = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + //float32* pfProjectionDiff = new float32[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + + //// ITERATE + //for (iIteration = _iNrIterations-1; iIteration >= 0; --iIteration) { + // + // // reset gamma + // memset(pfGamma, 0, sizeof(float32) * m_pReconstruction->getSize()); + // memset(pfBeta, 0, sizeof(float32) * m_pProjector->getProjectionGeometry()->getDetectorCount()); + // + // // get current projection angle + // int iProjection = m_piProjectionOrder[m_iCurrentProjection]; + // m_iCurrentProjection = (m_iCurrentProjection + 1) % m_iProjectionCount; + // int iProjectionWeightCount = m_pProjector->getProjectionWeightsCount(iProjection); + // + // // allocate memory for the pixel buffer + // SPixelWeight* pPixels = new SPixelWeight[m_pProjector->getProjectionWeightsCount(iProjection) * m_pProjector->getProjectionGeometry()->getDetectorCount()]; + // int* piRayStoredPixelCount = new int[m_pProjector->getProjectionGeometry()->getDetectorCount()]; + + // // compute weights for this projection + // m_pProjector->computeProjectionRayWeights(iProjection, pPixels, piRayStoredPixelCount); + // + // // calculate projection difference in each detector + // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) { + + // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + // // index base of the pixel in question + // baseIndex = iDetector * iProjectionWeightCount; + // + // // set the initial projection difference to the sinogram value + // pfProjectionDiff[iDetector] = m_pSinogram->getData2DConst()[iProjection][iDetector]; + // + // // update projection difference, beta and gamma + // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) { + + // // pixel must be loose + // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue; + + // // subtract projection value from projection difference + // pfProjectionDiff[iDetector] -= + // pPixels[baseIndex+iPixel].m_fWeight * m_pReconstruction->getDataConst()[pPixels[baseIndex+iPixel].m_iIndex]; + // + // // update beta and gamma if this pixel lies inside a loose part + // pfBeta[iDetector] += pPixels[baseIndex+iPixel].m_fWeight; + // pfGamma[pPixels[baseIndex+iPixel].m_iIndex] += pPixels[baseIndex+iPixel].m_fWeight; + // } + // + // } + // + // // back projection + // for (iDetector = m_pProjector->getProjectionGeometry()->getDetectorCount()-1; iDetector >= 0; --iDetector) { + // + // if (m_bUseSinogramMask && m_pSinogramMask->getData2D()[iProjection][iDetector] == 0) continue; + + // // index base of the pixel in question + // baseIndex = iDetector * iProjectionWeightCount; + + // // update pixel values + // for (iPixel = piRayStoredPixelCount[iDetector]-1; iPixel >= 0; --iPixel) { + + // + // // pixel must be loose + // if (m_bUseReconstructionMask && m_pReconstructionMask->getData()[pPixels[baseIndex+iPixel].m_iIndex] == 0) continue; + + // + + // // update reconstruction volume + // float32 fGammaBeta = pfGamma[pPixels[baseIndex+iPixel].m_iIndex] * pfBeta[iDetector]; + // if ((fGammaBeta > 0.01f) || (fGammaBeta < -0.01f)) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] += + // pPixels[baseIndex+iPixel].m_fWeight * pfProjectionDiff[iDetector] / fGammaBeta; + // } + + // // constraints + // if (m_bUseMinConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] < m_fMinValue) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMinValue; + // } + // if (m_bUseMaxConstraint && m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] > m_fMaxValue) { + // m_pReconstruction->getData()[pPixels[baseIndex+iPixel].m_iIndex] = m_fMaxValue; + // } + // } + // } + // + // // garbage disposal + // delete[] pPixels; + // delete[] piRayStoredPixelCount; + //} + + //// garbage disposal + //delete[] pfGamma; + //delete[] pfBeta; + //delete[] pfProjectionDiff; + + //// update statistics + //m_pReconstruction->updateStatistics(); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp new file mode 100644 index 0000000..60cee8a --- /dev/null +++ b/src/SirtAlgorithm.cpp @@ -0,0 +1,321 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SirtAlgorithm.h" + +#include <boost/lexical_cast.hpp> + +#include "astra/AstraObjectManager.h" +#include "astra/DataProjectorPolicies.h" + +using namespace std; + +namespace astra { + +#include "astra/Projector2DImpl.inl" + +// type of the algorithm, needed to register with CAlgorithmFactory +std::string CSirtAlgorithm::type = "SIRT"; + +//---------------------------------------------------------------------------------------- +// Constructor +CSirtAlgorithm::CSirtAlgorithm() +{ + _clear(); +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +CSirtAlgorithm::CSirtAlgorithm(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + _clear(); + initialize(_pProjector, _pSinogram, _pReconstruction); +} + +//---------------------------------------------------------------------------------------- +// Destructor +CSirtAlgorithm::~CSirtAlgorithm() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSirtAlgorithm::_clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; + + m_pTotalRayLength = NULL; + m_pTotalPixelWeight = NULL; + m_pDiffSinogram = NULL; + m_pTmpVolume = NULL; + + m_iIterationCount = 0; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSirtAlgorithm::clear() +{ + CReconstructionAlgorithm2D::_clear(); + m_bIsInitialized = false; + + ASTRA_DELETE(m_pTotalRayLength); + ASTRA_DELETE(m_pTotalPixelWeight); + ASTRA_DELETE(m_pDiffSinogram); + ASTRA_DELETE(m_pTmpVolume); + + m_iIterationCount = 0; +} + +//---------------------------------------------------------------------------------------- +// Check +bool CSirtAlgorithm::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CReconstructionAlgorithm2D::_check(), "SIRT", "Error in ReconstructionAlgorithm2D initialization"); + + ASTRA_CONFIG_CHECK(m_pTotalRayLength, "SIRT", "Invalid TotalRayLength Object"); + ASTRA_CONFIG_CHECK(m_pTotalRayLength->isInitialized(), "SIRT", "Invalid TotalRayLength Object"); + ASTRA_CONFIG_CHECK(m_pTotalPixelWeight, "SIRT", "Invalid TotalPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pTotalPixelWeight->isInitialized(), "SIRT", "Invalid TotalPixelWeight Object"); + ASTRA_CONFIG_CHECK(m_pDiffSinogram, "SIRT", "Invalid DiffSinogram Object"); + ASTRA_CONFIG_CHECK(m_pDiffSinogram->isInitialized(), "SIRT", "Invalid DiffSinogram Object"); + + return true; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSirtAlgorithm::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CAlgorithm> CC("SirtAlgorithm", this, _cfg); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CReconstructionAlgorithm2D::initialize(_cfg)) { + return false; + } + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize - C++ +bool CSirtAlgorithm::initialize(CProjector2D* _pProjector, + CFloat32ProjectionData2D* _pSinogram, + CFloat32VolumeData2D* _pReconstruction) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // required classes + m_pProjector = _pProjector; + m_pSinogram = _pSinogram; + m_pReconstruction = _pReconstruction; + + // init data objects and data projectors + _init(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize Data Projectors - private +void CSirtAlgorithm::_init() +{ + // create data objects + m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); + m_pDiffSinogram = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); + m_pTmpVolume = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); +} + +//--------------------------------------------------------------------------------------- +// Information - All +map<string,boost::any> CSirtAlgorithm::getInformation() +{ + map<string, boost::any> res; + return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); +}; + +//--------------------------------------------------------------------------------------- +// Information - Specific +boost::any CSirtAlgorithm::getInformation(std::string _sIdentifier) +{ + return CAlgorithm::getInformation(_sIdentifier); +}; + +//---------------------------------------------------------------------------------------- +// Iterate +void CSirtAlgorithm::run(int _iNrIterations) +{ + // check initialized + ASTRA_ASSERT(m_bIsInitialized); + + m_bShouldAbort = false; + + int iIteration = 0; + + // data projectors + CDataProjectorInterface* pForwardProjector; + CDataProjectorInterface* pBackProjector; + CDataProjectorInterface* pFirstForwardProjector; + + m_pTotalRayLength->setData(0.0f); + m_pTotalPixelWeight->setData(0.0f); + + // forward projection data projector + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // backprojection data projector + pBackProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + DefaultBPPolicy(m_pTmpVolume, m_pDiffSinogram), // backprojection + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + // first time forward projection data projector, + // also computes total pixel weight and total ray length + pFirstForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + Combine3Policy<DiffFPPolicy, TotalPixelWeightPolicy, TotalRayLengthPolicy>( // 3 basic operations + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + TotalPixelWeightPolicy(m_pTotalPixelWeight), // calculate the total pixel weights + TotalRayLengthPolicy(m_pTotalRayLength)), // calculate the total ray lengths + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + + + + // forward projection, difference calculation and raylength/pixelweight computation + pFirstForwardProjector->project(); + + float32* pfT = m_pTotalPixelWeight->getData(); + for (int i = 0; i < m_pTotalPixelWeight->getSize(); ++i) { + float32 x = pfT[i]; + if (x < -eps || x > eps) + x = 1.0f / x; + else + x = 0.0f; + pfT[i] = x; + } + pfT = m_pTotalRayLength->getData(); + for (int i = 0; i < m_pTotalRayLength->getSize(); ++i) { + float32 x = pfT[i]; + if (x < -eps || x > eps) + x = 1.0f / x; + else + x = 0.0f; + pfT[i] = x; + } + + // divide by line weights + (*m_pDiffSinogram) *= (*m_pTotalRayLength); + + // backprojection + m_pTmpVolume->setData(0.0f); + pBackProjector->project(); + + // divide by pixel weights + (*m_pTmpVolume) *= (*m_pTotalPixelWeight); + (*m_pReconstruction) += (*m_pTmpVolume); + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + + // update iteration count + m_iIterationCount++; + iIteration++; + + + + + // iteration loop + for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + // forward projection and difference calculation + pForwardProjector->project(); + + // divide by line weights + (*m_pDiffSinogram) *= (*m_pTotalRayLength); + + + // backprojection + m_pTmpVolume->setData(0.0f); + pBackProjector->project(); + + // divide by pixel weights + (*m_pTmpVolume) *= (*m_pTotalPixelWeight); + (*m_pReconstruction) += (*m_pTmpVolume); + + if (m_bUseMinConstraint) + m_pReconstruction->clampMin(m_fMinValue); + if (m_bUseMaxConstraint) + m_pReconstruction->clampMax(m_fMaxValue); + + // update iteration count + m_iIterationCount++; + } + + + ASTRA_DELETE(pForwardProjector); + ASTRA_DELETE(pBackProjector); + ASTRA_DELETE(pFirstForwardProjector); +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/SparseMatrix.cpp b/src/SparseMatrix.cpp new file mode 100644 index 0000000..e6d115f --- /dev/null +++ b/src/SparseMatrix.cpp @@ -0,0 +1,91 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include <sstream> + +#include "astra/Globals.h" +#include "astra/SparseMatrix.h" + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// constructor + +CSparseMatrix::CSparseMatrix() +{ + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// constructor +CSparseMatrix::CSparseMatrix(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize) +{ + initialize(_iHeight, _iWidth, _lSize); +} + + +//---------------------------------------------------------------------------------------- +// destructor +CSparseMatrix::~CSparseMatrix() +{ + delete[] m_pfValues; + delete[] m_piColIndices; + delete[] m_plRowStarts; +} + +//---------------------------------------------------------------------------------------- +// initialize +bool CSparseMatrix::initialize(unsigned int _iHeight, unsigned int _iWidth, + unsigned long _lSize) +{ + m_iHeight = _iHeight; + m_iWidth = _iWidth; + m_lSize = _lSize; + + m_pfValues = new float32[_lSize]; + m_piColIndices = new unsigned int[_lSize]; + m_plRowStarts = new unsigned long[_iHeight+1]; + m_bInitialized = true; + + return m_bInitialized; +} + + +std::string CSparseMatrix::description() const +{ + std::stringstream res; + res << m_iHeight << "x" << m_iWidth << " sparse matrix"; + return res.str(); +} + + + + +} // end namespace diff --git a/src/SparseMatrixProjectionGeometry2D.cpp b/src/SparseMatrixProjectionGeometry2D.cpp new file mode 100644 index 0000000..b95bbf4 --- /dev/null +++ b/src/SparseMatrixProjectionGeometry2D.cpp @@ -0,0 +1,203 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SparseMatrixProjectionGeometry2D.h" + +#include <boost/lexical_cast.hpp> +#include "astra/AstraObjectManager.h" + + +using namespace std; + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Default constructor. +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D() : + CProjectionGeometry2D() +{ + m_pMatrix = 0; +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix) +{ + _clear(); + initialize(_iProjectionAngleCount, + _iDetectorCount, + _pMatrix); +} + +//---------------------------------------------------------------------------------------- +CSparseMatrixProjectionGeometry2D::CSparseMatrixProjectionGeometry2D(const CSparseMatrixProjectionGeometry2D& _projGeom) +{ + _clear(); + initialize(_projGeom.m_iProjectionAngleCount, + _projGeom.m_iDetectorCount, + _projGeom.m_pMatrix); +} + +//---------------------------------------------------------------------------------------- + +CSparseMatrixProjectionGeometry2D& CSparseMatrixProjectionGeometry2D::operator=(const CSparseMatrixProjectionGeometry2D& _other) +{ + m_bInitialized = _other.m_bInitialized; + if (_other.m_bInitialized) { + m_pMatrix = _other.m_pMatrix; + m_iDetectorCount = _other.m_iDetectorCount; + m_fDetectorWidth = _other.m_fDetectorWidth; + } + return *this; + +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CSparseMatrixProjectionGeometry2D::~CSparseMatrixProjectionGeometry2D() +{ + m_pMatrix = 0; +} + +//--------------------------------------------------------------------------------------- +// Initialize - Config +bool CSparseMatrixProjectionGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CProjectionGeometry2D> CC("SparseMatrixProjectionGeometry2D", this, _cfg); + + // initialization of parent class + CProjectionGeometry2D::initialize(_cfg); + + // get matrix + XMLNode* node = _cfg.self->getSingleNode("MatrixID"); + ASTRA_CONFIG_CHECK(node, "SparseMatrixProjectionGeometry2D", "No MatrixID tag specified."); + int id = boost::lexical_cast<int>(node->getContent()); + m_pMatrix = CMatrixManager::getSingleton().get(id); + ASTRA_DELETE(node); + CC.markNodeParsed("MatrixID"); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CSparseMatrixProjectionGeometry2D::initialize(int _iProjectionAngleCount, + int _iDetectorCount, + const CSparseMatrix* _pMatrix) +{ + if (m_bInitialized) { + clear(); + } + + m_iProjectionAngleCount = _iProjectionAngleCount; + m_iDetectorCount = _iDetectorCount; + + // FIXME: We should probably require these for consistency? + m_fDetectorWidth = 1.0f; + m_pfProjectionAngles = new float32[m_iProjectionAngleCount]; + for (int i = 0; i < m_iProjectionAngleCount; ++i) + m_pfProjectionAngles[i] = 0.0f; + + m_pMatrix = _pMatrix; + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Check. +bool CSparseMatrixProjectionGeometry2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjectionGeometry2D::_check(), "SparseMatrixProjectionGeometry2D", "Error in ProjectionGeometry2D initialization"); + + ASTRA_CONFIG_CHECK(m_pMatrix, "SparseMatrixProjectionGeometry2D", "No matrix specified"); + + ASTRA_CONFIG_CHECK(m_pMatrix->m_iHeight == (unsigned int)(m_iProjectionAngleCount * m_iDetectorCount), "SparseMatrixProjectionGeometry2D", "Matrix height doesn't match projection geometry"); + + return true; +} + + +//---------------------------------------------------------------------------------------- +// Clone +CProjectionGeometry2D* CSparseMatrixProjectionGeometry2D::clone() +{ + return new CSparseMatrixProjectionGeometry2D(*this); +} + +//---------------------------------------------------------------------------------------- +// is equal +bool CSparseMatrixProjectionGeometry2D::isEqual(CProjectionGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // try to cast argument to CSparseMatrixProjectionGeometry2D + CSparseMatrixProjectionGeometry2D* pGeom2 = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(_pGeom2); + if (pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !pGeom2->m_bInitialized) return false; + + // check all values + if (m_iProjectionAngleCount != pGeom2->m_iProjectionAngleCount) return false; + if (m_iDetectorCount != pGeom2->m_iDetectorCount) return false; + if (m_fDetectorWidth != pGeom2->m_fDetectorWidth) return false; + + // Maybe check equality of matrices by element? + if (m_pMatrix != pGeom2->m_pMatrix) return false; + + return true; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CSparseMatrixProjectionGeometry2D::isOfType(const std::string& _sType) +{ + return (_sType == "sparse_matrix"); +} +//---------------------------------------------------------------------------------------- + +CVector3D CSparseMatrixProjectionGeometry2D::getProjectionDirection(int _iProjectionIndex, int _iDetectorIndex) +{ + CVector3D vOutput(0.0f, 0.0f, 0.0f); + + // not implemented, yet + ASTRA_ASSERT(false); + + return vOutput; +} + +} // end namespace astra diff --git a/src/SparseMatrixProjector2D.cpp b/src/SparseMatrixProjector2D.cpp new file mode 100644 index 0000000..ba3a46b --- /dev/null +++ b/src/SparseMatrixProjector2D.cpp @@ -0,0 +1,219 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/SparseMatrixProjector2D.h" + +#include <cmath> +#include <boost/lexical_cast.hpp> + +#include "astra/DataProjectorPolicies.h" + +using namespace std; +using namespace astra; + +#include "astra/SparseMatrixProjector2D.inl" + +// type of the projector, needed to register with CProjectorFactory +std::string CSparseMatrixProjector2D::type = "sparse_matrix"; + +//---------------------------------------------------------------------------------------- +// default constructor +CSparseMatrixProjector2D::CSparseMatrixProjector2D() +{ + _clear(); +} + +//---------------------------------------------------------------------------------------- +// constructor +CSparseMatrixProjector2D::CSparseMatrixProjector2D(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pReconstructionGeometry) + +{ + _clear(); + initialize(_pProjectionGeometry, _pReconstructionGeometry); +} + +//---------------------------------------------------------------------------------------- +// destructor +CSparseMatrixProjector2D::~CSparseMatrixProjector2D() +{ + clear(); +} + +//--------------------------------------------------------------------------------------- +// Clear - Constructors +void CSparseMatrixProjector2D::_clear() +{ + CProjector2D::_clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Clear - Public +void CSparseMatrixProjector2D::clear() +{ + CProjector2D::clear(); + m_bIsInitialized = false; +} + +//--------------------------------------------------------------------------------------- +// Check +bool CSparseMatrixProjector2D::_check() +{ + // check base class + ASTRA_CONFIG_CHECK(CProjector2D::_check(), "SparseMatrixProjector2D", "Error in Projector2D initialization"); + + ASTRA_CONFIG_CHECK(m_pVolumeGeometry->isInitialized(), "SparseMatrixProjector2D", "Volume geometry not initialized"); + ASTRA_CONFIG_CHECK(m_pProjectionGeometry->isInitialized(), "SparseMatrixProjector2D", "Projection geometry not initialized"); + + + ASTRA_CONFIG_CHECK(dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry), "SparseMatrixProjector2D", "Unsupported projection geometry"); + + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + ASTRA_CONFIG_CHECK(pMatrix, "SparseMatrixProjector2D", "No matrix specified in projection geometry"); + + ASTRA_CONFIG_CHECK(pMatrix->m_iWidth == (unsigned int)m_pVolumeGeometry->getGridTotCount(), "SparseMatrixProjector2D", "Matrix width doesn't match volume geometry"); + + return true; +} + + +//--------------------------------------------------------------------------------------- +// Initialize, use a Config object +bool CSparseMatrixProjector2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // initialization of parent class + if (!CProjector2D::initialize(_cfg)) { + return false; + } + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + +//--------------------------------------------------------------------------------------- +// Initialize +bool CSparseMatrixProjector2D::initialize(CSparseMatrixProjectionGeometry2D* _pProjectionGeometry, + CVolumeGeometry2D* _pVolumeGeometry) +{ + // if already initialized, clear first + if (m_bIsInitialized) { + clear(); + } + + // hardcopy geometries + m_pProjectionGeometry = _pProjectionGeometry->clone(); + m_pVolumeGeometry = _pVolumeGeometry->clone(); + + // success + m_bIsInitialized = _check(); + return m_bIsInitialized; +} + + +//---------------------------------------------------------------------------------------- +// Get maximum amount of weights on a single ray +int CSparseMatrixProjector2D::getProjectionWeightsCount(int _iProjectionIndex) +{ + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + + unsigned int iMax = 0; + unsigned long lSize = m_pProjectionGeometry->getDetectorCount(); + lSize *= m_pProjectionGeometry->getProjectionAngleCount(); + for (unsigned long i = 0; i < lSize; ++i) { + unsigned int iRowSize = pMatrix->getRowSize(i); + if (iRowSize > iMax) + iMax = pMatrix->getRowSize(i); + } + return iMax; +} + +//---------------------------------------------------------------------------------------- +// Single Ray Weights +void CSparseMatrixProjector2D::computeSingleRayWeights(int _iProjectionIndex, + int _iDetectorIndex, + SPixelWeight* _pWeightedPixels, + int _iMaxPixelCount, + int& _iStoredPixelCount) +{ + // TODO: Move this default implementation to Projector2D? + ASTRA_ASSERT(m_bIsInitialized); + StorePixelWeightsPolicy p(_pWeightedPixels, _iMaxPixelCount); + projectSingleRay(_iProjectionIndex, _iDetectorIndex, p); + _iStoredPixelCount = p.getStoredPixelCount(); +} + +//---------------------------------------------------------------------------------------- +// Splat a single point +std::vector<SDetector2D> CSparseMatrixProjector2D::projectPoint(int _iRow, int _iCol) +{ + unsigned int iVolumeIndex = _iCol * m_pVolumeGeometry->getGridRowCount() + _iRow; + + // NOTE: This is very slow currently because we don't have the + // sparse matrix stored in an appropriate form for this function. + std::vector<SDetector2D> ret; + + const CSparseMatrix* pMatrix = dynamic_cast<CSparseMatrixProjectionGeometry2D*>(m_pProjectionGeometry)->getMatrix(); + + for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) + { + for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) + { + int iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; + const unsigned int* piColIndices; + const float32* pfValues; + unsigned int iSize; + + pMatrix->getRowData(iRayIndex, iSize, pfValues, piColIndices); + + for (unsigned int i = 0; i < iSize; ++i) { + if (piColIndices[i] == iVolumeIndex) { + SDetector2D s; + s.m_iIndex = iRayIndex; + s.m_iAngleIndex = iAngle; + s.m_iDetectorIndex = iDetector; + ret.push_back(s); + break; + } else if (piColIndices[i] > iVolumeIndex) { + break; + } + } + } + } + return ret; +} + +//---------------------------------------------------------------------------------------- diff --git a/src/Utilities.cpp b/src/Utilities.cpp new file mode 100644 index 0000000..94992a9 --- /dev/null +++ b/src/Utilities.cpp @@ -0,0 +1,128 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/Utilities.h" + +using namespace std; +using namespace astra; + +//----------------------------------------------------------------------------- +// Trim Whitespace Characters +void StringUtil::trim(std::string& _sString, bool _bLeft, bool _bRight) +{ + // trim right + if (_bRight) + _sString.erase(_sString.find_last_not_of(" \t\r") + 1); + + // trim left + if (_bLeft) + _sString.erase(0, _sString.find_first_not_of(" \t\r")); +} +//----------------------------------------------------------------------------- +// Split String +vector<string> StringUtil::split(const string& _sString, const string& _sDelims) +{ + std::vector<string> ret; + + size_t start, pos; + start = 0; + do { + pos = _sString.find_first_of(_sDelims, start); + if (pos == start) { + // Do nothing + start = pos + 1; + } else if (pos == string::npos) { + // Copy the rest of the string + ret.push_back(_sString.substr(start)); + break; + } else { + // Copy up to newt delimiter + ret.push_back(_sString.substr(start, pos - start)); + start = pos + 1; + } + + // Parse up to next real data (in case there are two delims after each other) + start = _sString.find_first_not_of(_sDelims, start); + } while (pos != string::npos); + + return ret; +} +//----------------------------------------------------------------------------- +// Cast string to int +bool StringUtil::toInt(const string& _sString, int& _iValue) +{ + std::istringstream ss(_sString); + ss >> _iValue; + return !ss.fail(); +} +//----------------------------------------------------------------------------- +// Cast string to float +bool StringUtil::toFloat32(const string& _sString, float32& _fValue) +{ + std::istringstream ss(_sString); + ss >> _fValue; + return !ss.fail(); +} +//----------------------------------------------------------------------------- +// Convert string to Lower Case +void StringUtil::toLowerCase(std::string& _sString) +{ + std::transform(_sString.begin(), + _sString.end(), + _sString.begin(), + ::tolower); +} +//----------------------------------------------------------------------------- +// Convert string to Upper Case +void StringUtil::toUpperCase(std::string& _sString) +{ + std::transform(_sString.begin(), + _sString.end(), + _sString.begin(), + ::toupper); +} +//----------------------------------------------------------------------------- + + + + +//----------------------------------------------------------------------------- +// Get Extension +string FileSystemUtil::getExtension(string& _sFilename) +{ + string sExtension = ""; + for (int i = _sFilename.length() - 1; 0 < i; i--) { + if (_sFilename[i] == '.') { + std::transform(sExtension.begin(),sExtension.end(),sExtension.begin(),::tolower); + return sExtension; + } + sExtension = _sFilename[i] + sExtension; + } + return ""; +} +//----------------------------------------------------------------------------- diff --git a/src/Vector3D.cpp b/src/Vector3D.cpp new file mode 100644 index 0000000..1e571b1 --- /dev/null +++ b/src/Vector3D.cpp @@ -0,0 +1,29 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "../include/astra/Vector3D.h" diff --git a/src/VolumeGeometry2D.cpp b/src/VolumeGeometry2D.cpp new file mode 100644 index 0000000..01d9b9a --- /dev/null +++ b/src/VolumeGeometry2D.cpp @@ -0,0 +1,282 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/VolumeGeometry2D.h" + +#include <boost/lexical_cast.hpp> +#include <cmath> + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values +bool CVolumeGeometry2D::_check() +{ + ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry2D", "GridColCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry2D", "GridRowCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry2D", "WindowMinX should be lower than WindowMaxX."); + ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry2D", "WindowMinY should be lower than WindowMaxY."); + + ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry2D", "Internal configuration error."); + + ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY), "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthX * m_fPixelLengthX - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(fabsf(m_fDivPixelLengthY * m_fPixelLengthY - 1.0f) < eps, "VolumeGeometry2D", "Internal configuration error."); + + return true; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CVolumeGeometry2D::clear() +{ + m_iGridColCount = 0; + m_iGridRowCount = 0; + m_iGridTotCount = 0; + + m_fWindowLengthX = 0.0f; + m_fWindowLengthY = 0.0f; + m_fWindowArea = 0.0f; + + m_fPixelLengthX = 0.0f; + m_fPixelLengthY = 0.0f; + m_fPixelArea = 0.0f; + + m_fDivPixelLengthX = 0.0f; + m_fDivPixelLengthY = 0.0f; + + m_fWindowMinX = 0.0f; + m_fWindowMinY = 0.0f; + m_fWindowMaxX = 0.0f; + m_fWindowMaxY = 0.0f; + + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CVolumeGeometry2D::CVolumeGeometry2D() : configCheckData(0) +{ + clear(); +} + +//---------------------------------------------------------------------------------------- +// Default constructor +CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount, int _iGridRowCount) + : configCheckData(0) +{ + clear(); + initialize(_iGridColCount, _iGridRowCount); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CVolumeGeometry2D::CVolumeGeometry2D(int _iGridColCount, + int _iGridRowCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY) +{ + clear(); + initialize(_iGridColCount, + _iGridRowCount, + _fWindowMinX, + _fWindowMinY, + _fWindowMaxX, + _fWindowMaxY); +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CVolumeGeometry2D::~CVolumeGeometry2D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Clone +CVolumeGeometry2D* CVolumeGeometry2D::clone() +{ + CVolumeGeometry2D* res = new CVolumeGeometry2D(); + res->m_bInitialized = m_bInitialized; + res->m_iGridColCount = m_iGridColCount; + res->m_iGridRowCount = m_iGridRowCount; + res->m_iGridTotCount = m_iGridTotCount; + res->m_fWindowLengthX = m_fWindowLengthX; + res->m_fWindowLengthY = m_fWindowLengthY; + res->m_fWindowArea = m_fWindowArea; + res->m_fPixelLengthX = m_fPixelLengthX; + res->m_fPixelLengthY = m_fPixelLengthY; + res->m_fPixelArea = m_fPixelArea; + res->m_fDivPixelLengthX = m_fDivPixelLengthX; + res->m_fDivPixelLengthY = m_fDivPixelLengthY; + res->m_fWindowMinX = m_fWindowMinX; + res->m_fWindowMinY = m_fWindowMinY; + res->m_fWindowMaxX = m_fWindowMaxX; + res->m_fWindowMaxY = m_fWindowMaxY; + return res; +} + +//---------------------------------------------------------------------------------------- +// Initialization witha COnfig object +bool CVolumeGeometry2D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CVolumeGeometry2D> CC("VolumeGeometry2D", this, _cfg); + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: GridColCount + XMLNode* node = _cfg.self->getSingleNode("GridColCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified."); + m_iGridColCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridColCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridRowCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified."); + m_iGridRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridRowCount"); + + // Optional: Window minima and maxima + m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f); + m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f); + m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f); + m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f); + CC.markOptionParsed("WindowMinX"); + CC.markOptionParsed("WindowMaxX"); + CC.markOptionParsed("WindowMinY"); + CC.markOptionParsed("WindowMaxY"); + + _calculateDependents(); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry2D::initialize(int _iGridColCount, int _iGridRowCount) +{ + return initialize(_iGridColCount, + _iGridRowCount, + -_iGridColCount/2.0f, + -_iGridRowCount/2.0f, + _iGridColCount/2.0f, + _iGridRowCount/2.0f); +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry2D::initialize(int _iGridColCount, + int _iGridRowCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMaxX, + float32 _fWindowMaxY) +{ + if (m_bInitialized) { + clear(); + } + + m_iGridColCount = _iGridColCount; + m_iGridRowCount = _iGridRowCount; + + m_fWindowMinX = _fWindowMinX; + m_fWindowMinY = _fWindowMinY; + m_fWindowMaxX = _fWindowMaxX; + m_fWindowMaxY = _fWindowMaxY; + + _calculateDependents(); + + m_bInitialized = _check(); + return m_bInitialized; +} + +void CVolumeGeometry2D::_calculateDependents() +{ + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount); + + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY); + + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY); + + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CVolumeGeometry2D::isEqual(CVolumeGeometry2D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !_pGeom2->m_bInitialized) return false; + + // check all values + if (m_iGridColCount != _pGeom2->m_iGridColCount) return false; + if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false; + if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false; + if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false; + if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false; + if (m_fWindowArea != _pGeom2->m_fWindowArea) return false; + if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false; + if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false; + if (m_fPixelArea != _pGeom2->m_fPixelArea) return false; + if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false; + if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false; + if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false; + if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false; + if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false; + if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false; + + return true; +} +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/VolumeGeometry3D.cpp b/src/VolumeGeometry3D.cpp new file mode 100644 index 0000000..86b8642 --- /dev/null +++ b/src/VolumeGeometry3D.cpp @@ -0,0 +1,384 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/VolumeGeometry3D.h" + +#include <boost/lexical_cast.hpp> + +namespace astra +{ + +//---------------------------------------------------------------------------------------- +// Check all variable values +bool CVolumeGeometry3D::_check() +{ + ASTRA_CONFIG_CHECK(m_iGridColCount > 0, "VolumeGeometry3D", "GridColCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridRowCount > 0, "VolumeGeometry3D", "GridRowCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_iGridSliceCount > 0, "VolumeGeometry3D", "GridSliceCount must be strictly positive."); + ASTRA_CONFIG_CHECK(m_fWindowMinX < m_fWindowMaxX, "VolumeGeometry3D", "WindowMinX should be lower than WindowMaxX."); + ASTRA_CONFIG_CHECK(m_fWindowMinY < m_fWindowMaxY, "VolumeGeometry3D", "WindowMinY should be lower than WindowMaxY."); + ASTRA_CONFIG_CHECK(m_fWindowMinZ < m_fWindowMaxZ, "VolumeGeometry3D", "WindowMinZ should be lower than WindowMaxZ."); + + ASTRA_CONFIG_CHECK(m_iGridTotCount == (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthX == (m_fWindowMaxX - m_fWindowMinX), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthY == (m_fWindowMaxY - m_fWindowMinY), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowLengthZ == (m_fWindowMaxZ - m_fWindowMinZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fWindowArea == (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthX == (m_fWindowLengthX / (float32)m_iGridColCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthY == (m_fWindowLengthY / (float32)m_iGridRowCount), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fPixelLengthZ == (m_fWindowLengthZ / (float32)m_iGridSliceCount), "VolumeGeometry3D", "Internal configuration error."); + + ASTRA_CONFIG_CHECK(m_fPixelArea == (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthX == (1.0f / m_fPixelLengthX), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthY == (1.0f / m_fPixelLengthY), "VolumeGeometry3D", "Internal configuration error."); + ASTRA_CONFIG_CHECK(m_fDivPixelLengthZ == (1.0f / m_fPixelLengthZ), "VolumeGeometry3D", "Internal configuration error."); + + return true; +} + +//---------------------------------------------------------------------------------------- +// Clear all member variables, setting all numeric variables to 0 and all pointers to NULL. +void CVolumeGeometry3D::clear() +{ + m_iGridColCount = 0; + m_iGridRowCount = 0; + m_iGridSliceCount = 0; + m_iGridTotCount = 0; + + m_fWindowLengthX = 0.0f; + m_fWindowLengthY = 0.0f; + m_fWindowLengthZ = 0.0f; + m_fWindowArea = 0.0f; + + m_fPixelLengthX = 0.0f; + m_fPixelLengthY = 0.0f; + m_fPixelLengthZ = 0.0f; + m_fPixelArea = 0.0f; + + m_fDivPixelLengthX = 0.0f; + m_fDivPixelLengthY = 0.0f; + m_fDivPixelLengthZ = 0.0f; + + m_fWindowMinX = 0.0f; + m_fWindowMinY = 0.0f; + m_fWindowMinZ = 0.0f; + m_fWindowMaxX = 0.0f; + m_fWindowMaxY = 0.0f; + m_fWindowMaxZ = 0.0f; + + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor. +CVolumeGeometry3D::CVolumeGeometry3D() : configCheckData(0) +{ + clear(); + m_bInitialized = false; +} + +//---------------------------------------------------------------------------------------- +// Default constructor +CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount) + : configCheckData(0) +{ + clear(); + initialize(_iGridColCount, _iGridRowCount, _iGridSliceCount); +} + +//---------------------------------------------------------------------------------------- +// Constructor. +CVolumeGeometry3D::CVolumeGeometry3D(int _iGridColCount, + int _iGridRowCount, + int _iGridSliceCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ) +{ + clear(); + initialize(_iGridColCount, + _iGridRowCount, + _iGridSliceCount, + _fWindowMinX, + _fWindowMinY, + _fWindowMinZ, + _fWindowMaxX, + _fWindowMaxY, + _fWindowMaxZ); +} + +CVolumeGeometry3D::CVolumeGeometry3D(const CVolumeGeometry3D& _other) +{ + *this = _other; +} + +CVolumeGeometry3D& CVolumeGeometry3D::operator=(const CVolumeGeometry3D& _other) +{ + m_bInitialized = _other.m_bInitialized; + m_iGridColCount = _other.m_iGridColCount; + m_iGridRowCount = _other.m_iGridRowCount; + m_iGridSliceCount = _other.m_iGridSliceCount; + m_fWindowLengthX = _other.m_fWindowLengthX; + m_fWindowLengthY = _other.m_fWindowLengthY; + m_fWindowLengthZ = _other.m_fWindowLengthZ; + m_fWindowArea = _other.m_fWindowArea; + m_fPixelLengthX = _other.m_fPixelLengthX; + m_fPixelLengthY = _other.m_fPixelLengthY; + m_fPixelLengthZ = _other.m_fPixelLengthZ; + m_fDivPixelLengthX = _other.m_fDivPixelLengthX; + m_fDivPixelLengthY = _other.m_fDivPixelLengthY; + m_fDivPixelLengthZ = _other.m_fDivPixelLengthZ; + m_fWindowMinX = _other.m_fWindowMinX; + m_fWindowMinY = _other.m_fWindowMinY; + m_fWindowMinZ = _other.m_fWindowMinZ; + m_fWindowMaxX = _other.m_fWindowMaxX; + m_fWindowMaxY = _other.m_fWindowMaxY; + m_fWindowMaxZ = _other.m_fWindowMaxZ; + + m_iGridTotCount = _other.m_iGridTotCount; + m_fPixelArea = _other.m_fPixelArea; + + return *this; +} + +//---------------------------------------------------------------------------------------- +// Destructor. +CVolumeGeometry3D::~CVolumeGeometry3D() +{ + if (m_bInitialized) { + clear(); + } +} + +//---------------------------------------------------------------------------------------- +// Initialization with a Config object +bool CVolumeGeometry3D::initialize(const Config& _cfg) +{ + ASTRA_ASSERT(_cfg.self); + ConfigStackCheck<CVolumeGeometry3D> CC("VolumeGeometry3D", this, _cfg); + + + // uninitialize if the object was initialized before + if (m_bInitialized) { + clear(); + } + + // Required: GridColCount + XMLNode* node = _cfg.self->getSingleNode("GridColCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridColCount tag specified."); + m_iGridColCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridColCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridRowCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridRowCount tag specified."); + m_iGridRowCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridRowCount"); + + // Required: GridRowCount + node = _cfg.self->getSingleNode("GridSliceCount"); + ASTRA_CONFIG_CHECK(node, "ReconstructionGeometry2D", "No GridSliceCount tag specified."); + m_iGridSliceCount = boost::lexical_cast<int>(node->getContent()); + ASTRA_DELETE(node); + CC.markNodeParsed("GridSliceCount"); + + // Optional: Window minima and maxima + m_fWindowMinX = _cfg.self->getOptionNumerical("WindowMinX", -m_iGridColCount/2.0f); + m_fWindowMaxX = _cfg.self->getOptionNumerical("WindowMaxX", m_iGridColCount/2.0f); + m_fWindowMinY = _cfg.self->getOptionNumerical("WindowMinY", -m_iGridRowCount/2.0f); + m_fWindowMaxY = _cfg.self->getOptionNumerical("WindowMaxY", m_iGridRowCount/2.0f); + m_fWindowMinZ = _cfg.self->getOptionNumerical("WindowMinZ", -m_iGridSliceCount/2.0f); + m_fWindowMaxZ = _cfg.self->getOptionNumerical("WindowMaxZ", m_iGridSliceCount/2.0f); + CC.markOptionParsed("WindowMinX"); + CC.markOptionParsed("WindowMaxX"); + CC.markOptionParsed("WindowMinY"); + CC.markOptionParsed("WindowMaxY"); + CC.markOptionParsed("WindowMinZ"); + CC.markOptionParsed("WindowMaxZ"); + + // calculate some other things + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount); + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ); + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount); + + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY * m_fPixelLengthZ); + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); + m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ); + + // success + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry3D::initialize(int _iGridColCount, int _iGridRowCount, int _iGridSliceCount) +{ + return initialize(_iGridColCount, + _iGridRowCount, + _iGridSliceCount, + -_iGridColCount/2.0f, + -_iGridRowCount/2.0f, + -_iGridSliceCount/2.0f, + _iGridColCount/2.0f, + _iGridRowCount/2.0f, + _iGridSliceCount/2.0f); +} + +//---------------------------------------------------------------------------------------- +// Initialization. +bool CVolumeGeometry3D::initialize(int _iGridColCount, + int _iGridRowCount, + int _iGridSliceCount, + float32 _fWindowMinX, + float32 _fWindowMinY, + float32 _fWindowMinZ, + float32 _fWindowMaxX, + float32 _fWindowMaxY, + float32 _fWindowMaxZ) +{ + if (m_bInitialized) { + clear(); + } + + m_iGridColCount = _iGridColCount; + m_iGridRowCount = _iGridRowCount; + m_iGridSliceCount = _iGridSliceCount; + m_iGridTotCount = (m_iGridColCount * m_iGridRowCount * m_iGridSliceCount); + + m_fWindowMinX = _fWindowMinX; + m_fWindowMinY = _fWindowMinY; + m_fWindowMinZ = _fWindowMinZ; + m_fWindowMaxX = _fWindowMaxX; + m_fWindowMaxY = _fWindowMaxY; + m_fWindowMaxZ = _fWindowMaxZ; + + m_fWindowLengthX = (m_fWindowMaxX - m_fWindowMinX); + m_fWindowLengthY = (m_fWindowMaxY - m_fWindowMinY); + m_fWindowLengthZ = (m_fWindowMaxZ - m_fWindowMinZ); + m_fWindowArea = (m_fWindowLengthX * m_fWindowLengthY * m_fWindowLengthZ); + + m_fPixelLengthX = (m_fWindowLengthX / (float32)m_iGridColCount); + m_fPixelLengthY = (m_fWindowLengthY / (float32)m_iGridRowCount); + m_fPixelLengthZ = (m_fWindowLengthZ / (float32)m_iGridSliceCount); + m_fPixelArea = (m_fPixelLengthX * m_fPixelLengthY); + + m_fDivPixelLengthX = ((float32)m_iGridColCount / m_fWindowLengthX); // == (1.0f / m_fPixelLengthX); + m_fDivPixelLengthY = ((float32)m_iGridRowCount / m_fWindowLengthY); // == (1.0f / m_fPixelLengthY); + m_fDivPixelLengthZ = ((float32)m_iGridSliceCount / m_fWindowLengthZ); // == (1.0f / m_fPixelLengthZ); + + m_bInitialized = _check(); + return m_bInitialized; +} + +//---------------------------------------------------------------------------------------- +// Clone +CVolumeGeometry3D* CVolumeGeometry3D::clone() const +{ + CVolumeGeometry3D* res = new CVolumeGeometry3D(); + res->m_bInitialized = m_bInitialized; + res->m_iGridColCount = m_iGridColCount; + res->m_iGridRowCount = m_iGridRowCount; + res->m_iGridSliceCount = m_iGridSliceCount; + res->m_iGridTotCount = m_iGridTotCount; + res->m_fWindowLengthX = m_fWindowLengthX; + res->m_fWindowLengthY = m_fWindowLengthY; + res->m_fWindowLengthZ = m_fWindowLengthZ; + res->m_fWindowArea = m_fWindowArea; + res->m_fPixelLengthX = m_fPixelLengthX; + res->m_fPixelLengthY = m_fPixelLengthY; + res->m_fPixelLengthZ = m_fPixelLengthZ; + res->m_fPixelArea = m_fPixelArea; + res->m_fDivPixelLengthX = m_fDivPixelLengthX; + res->m_fDivPixelLengthY = m_fDivPixelLengthY; + res->m_fDivPixelLengthZ = m_fDivPixelLengthZ; + res->m_fWindowMinX = m_fWindowMinX; + res->m_fWindowMinY = m_fWindowMinY; + res->m_fWindowMinZ = m_fWindowMinZ; + res->m_fWindowMaxX = m_fWindowMaxX; + res->m_fWindowMaxY = m_fWindowMaxY; + res->m_fWindowMaxZ = m_fWindowMaxZ; + return res; +} + +//---------------------------------------------------------------------------------------- +// is of type +bool CVolumeGeometry3D::isEqual(const CVolumeGeometry3D* _pGeom2) const +{ + if (_pGeom2 == NULL) return false; + + // both objects must be initialized + if (!m_bInitialized || !_pGeom2->m_bInitialized) return false; + + // check all values + if (m_iGridColCount != _pGeom2->m_iGridColCount) return false; + if (m_iGridRowCount != _pGeom2->m_iGridRowCount) return false; + if (m_iGridSliceCount != _pGeom2->m_iGridSliceCount) return false; + if (m_iGridTotCount != _pGeom2->m_iGridTotCount) return false; + if (m_fWindowLengthX != _pGeom2->m_fWindowLengthX) return false; + if (m_fWindowLengthY != _pGeom2->m_fWindowLengthY) return false; + if (m_fWindowLengthZ != _pGeom2->m_fWindowLengthZ) return false; + if (m_fWindowArea != _pGeom2->m_fWindowArea) return false; + if (m_fPixelLengthX != _pGeom2->m_fPixelLengthX) return false; + if (m_fPixelLengthY != _pGeom2->m_fPixelLengthY) return false; + if (m_fPixelLengthZ != _pGeom2->m_fPixelLengthZ) return false; + if (m_fPixelArea != _pGeom2->m_fPixelArea) return false; + if (m_fDivPixelLengthX != _pGeom2->m_fDivPixelLengthX) return false; + if (m_fDivPixelLengthY != _pGeom2->m_fDivPixelLengthY) return false; + if (m_fDivPixelLengthZ != _pGeom2->m_fDivPixelLengthZ) return false; + if (m_fWindowMinX != _pGeom2->m_fWindowMinX) return false; + if (m_fWindowMinY != _pGeom2->m_fWindowMinY) return false; + if (m_fWindowMinZ != _pGeom2->m_fWindowMinZ) return false; + if (m_fWindowMaxX != _pGeom2->m_fWindowMaxX) return false; + if (m_fWindowMaxY != _pGeom2->m_fWindowMaxY) return false; + if (m_fWindowMaxZ != _pGeom2->m_fWindowMaxZ) return false; + + return true; +} + +CVolumeGeometry2D * CVolumeGeometry3D::createVolumeGeometry2D() const +{ + CVolumeGeometry2D * pOutput = new CVolumeGeometry2D(); + pOutput->initialize(getGridColCount(), getGridRowCount()); + return pOutput; +} + +//---------------------------------------------------------------------------------------- + +} // namespace astra diff --git a/src/XMLDocument.cpp b/src/XMLDocument.cpp new file mode 100644 index 0000000..96d0f80 --- /dev/null +++ b/src/XMLDocument.cpp @@ -0,0 +1,112 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/XMLDocument.h" +#include <string> +#include <fstream> +#include <iostream> +#include <sstream> + +#ifdef _MSC_VER +#include "rapidxml/rapidxml.hpp" +#include "rapidxml/rapidxml_print.hpp" +#else +#include "rapidxml.hpp" +#include "rapidxml_print.hpp" +#endif + +using namespace rapidxml; +using namespace astra; +using namespace std; + + + +//----------------------------------------------------------------------------- +XMLDocument::XMLDocument() +{ + fDOMDocument = 0; +} + +//----------------------------------------------------------------------------- +XMLDocument::~XMLDocument() +{ + delete fDOMDocument; + //parser->release(); +} + +//----------------------------------------------------------------------------- +XMLDocument* XMLDocument::readFromFile(string filename) +{ + // create the document + XMLDocument* res = new XMLDocument(); + res->fDOMDocument = new xml_document<>(); + + std::ifstream file(filename.c_str()); + std::stringstream reader; + reader << file.rdbuf(); + res->fBuf = reader.str(); + + res->fDOMDocument->parse<0>((char*)res->fBuf.c_str()); + + // return the document + return res; + +} + +//----------------------------------------------------------------------------- +// create an XML document with an empty root node +XMLDocument* XMLDocument::createDocument(string sRootName) +{ + XMLDocument* res = new XMLDocument(); + res->fDOMDocument = new xml_document<>(); + + char *node_name = res->fDOMDocument->allocate_string(sRootName.c_str()); + xml_node<> *node = res->fDOMDocument->allocate_node(node_element, node_name); + + res->fDOMDocument->append_node(node); + + return res; +} + +//----------------------------------------------------------------------------- +XMLNode* XMLDocument::getRootNode() +{ + // TODO: clean up: this 'new' requires callers to do memory management + return new XMLNode(fDOMDocument->first_node()); +} + +//----------------------------------------------------------------------------- +void XMLDocument::saveToFile(string sFilename) +{ + std::ofstream file(sFilename.c_str()); + + file << *fDOMDocument; +} + +//----------------------------------------------------------------------------- + diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp new file mode 100644 index 0000000..e47c3e7 --- /dev/null +++ b/src/XMLNode.cpp @@ -0,0 +1,499 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#include "astra/XMLNode.h" + +#ifdef _MSC_VER +#include "rapidxml/rapidxml.hpp" +#include "rapidxml/rapidxml_print.hpp" +#else +#include "rapidxml.hpp" +#include "rapidxml_print.hpp" +#endif + +#include <boost/lexical_cast.hpp> + +using namespace rapidxml; +using namespace astra; +using namespace std; + + +//----------------------------------------------------------------------------- +// Utility function to delete a list of nodes +static void deleteNodes(list<XMLNode*>& nodes) +{ + for (list<XMLNode*>::iterator i = nodes.begin(); i != nodes.end(); ++i) + delete (*i); + + nodes.clear(); +} + + +//----------------------------------------------------------------------------- +// default constructor +XMLNode::XMLNode() +{ + +} + +//----------------------------------------------------------------------------- +// private constructor +XMLNode::XMLNode(xml_node<>* node) +{ + fDOMElement = node; +} + +//----------------------------------------------------------------------------- +// destructor +XMLNode::~XMLNode() +{ + +} + +//----------------------------------------------------------------------------- +// set DOM node (private) +void XMLNode::setDOMNode(xml_node<>* n) +{ + fDOMElement = n; +} + +//----------------------------------------------------------------------------- +// print XML Node +void XMLNode::print() +{ + std::cout << fDOMElement; +} + +//----------------------------------------------------------------------------- +// print XML Node +std::string XMLNode::toString() +{ + std::string s; + ::print(std::back_inserter(s), *fDOMElement, 0); + return s; +} + +//----------------------------------------------------------------------------- +// Get single node +XMLNode* XMLNode::getSingleNode(string name) +{ + xml_node<> *node = fDOMElement->first_node(name.c_str()); + + if (node) + return new XMLNode(node); + else + return 0; +} + +//----------------------------------------------------------------------------- +// Get list of nodes +list<XMLNode*> XMLNode::getNodes(string name) +{ + list<XMLNode*> result; + xml_node<> *iter; + for (iter = fDOMElement->first_node(name.c_str()); iter; iter = iter->next_sibling(name.c_str())) { + result.push_back(new XMLNode(iter)); + } + return result; +} + +//----------------------------------------------------------------------------- +// Get list of nodes +list<XMLNode*> XMLNode::getNodes() +{ + list<XMLNode*> result; + xml_node<> *iter; + for (iter = fDOMElement->first_node(); iter; iter = iter->next_sibling()) { + result.push_back(new XMLNode(iter)); + } + return result; +} + +//----------------------------------------------------------------------------- +// Get name of this node +std::string XMLNode::getName() +{ + return fDOMElement->name(); +} + +//----------------------------------------------------------------------------- +// Get node content - STRING +string XMLNode::getContent() +{ + return fDOMElement->value(); +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL +float32 XMLNode::getContentNumerical() +{ + return boost::lexical_cast<float32>(getContent()); +} + +//----------------------------------------------------------------------------- +// Get node content - BOOLEAN +bool XMLNode::getContentBool() +{ + string res = getContent(); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Get node content - STRING LIST +vector<string> XMLNode::getContentArray() +{ + // get listsize + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<string> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + string sValue = (*it)->getAttribute("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = sValue; + } + deleteNodes(nodes); + + // return + return res; +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL LIST +vector<float32> XMLNode::getContentNumericalArray() +{ + // is scalar + if (!hasAttribute("listsize")) { + vector<float32> res(1); + res[0] = getContentNumerical(); + return res; + } + + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<float32> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + float32 fValue = (*it)->getAttributeNumerical("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = fValue; + } + deleteNodes(nodes); + // return + return res; +} + +vector<double> XMLNode::getContentNumericalArrayDouble() +{ + // is scalar + if (!hasAttribute("listsize")) { + vector<double> res(1); + res[0] = getContentNumerical(); + return res; + } + + int iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + vector<double> res(iSize); + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + double fValue = (*it)->getAttributeNumericalDouble("value"); + ASTRA_ASSERT(iIndex < iSize); + res[iIndex] = fValue; + } + deleteNodes(nodes); + // return + return res; +} + +//----------------------------------------------------------------------------- +// Get node content - NUMERICAL LIST 2 +void XMLNode::getContentNumericalArray(float32*& _pfData, int& _iSize) +{ + // is scalar + if (!hasAttribute("listsize")) { + _iSize = 1; + _pfData = new float32[_iSize]; + _pfData[0] = getContentNumerical(); + return; + } + // get listsize + _iSize = boost::lexical_cast<int>(getAttribute("listsize")); + // create result array + _pfData = new float32[_iSize]; + // loop all list item nodes + list<XMLNode*> nodes = getNodes("ListItem"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + int iIndex = (*it)->getAttributeNumerical("index"); + float32 fValue = (*it)->getAttributeNumerical("value"); + ASTRA_ASSERT(iIndex < _iSize); + _pfData[iIndex] = fValue; + } + deleteNodes(nodes); +} + +//----------------------------------------------------------------------------- +// Is attribute? +bool XMLNode::hasAttribute(string _sName) +{ + xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str()); + return (attr != 0); +} + +//----------------------------------------------------------------------------- +// Get attribute - STRING +string XMLNode::getAttribute(string _sName, string _sDefaultValue) +{ + xml_attribute<> *attr = fDOMElement->first_attribute(_sName.c_str()); + + if (!attr) return _sDefaultValue; + + return attr->value(); +} + +//----------------------------------------------------------------------------- +// Get attribute - NUMERICAL +float32 XMLNode::getAttributeNumerical(string _sName, float32 _fDefaultValue) +{ + if (!hasAttribute(_sName)) return _fDefaultValue; + return boost::lexical_cast<float32>(getAttribute(_sName)); +} +double XMLNode::getAttributeNumericalDouble(string _sName, double _fDefaultValue) +{ + if (!hasAttribute(_sName)) return _fDefaultValue; + return boost::lexical_cast<double>(getAttribute(_sName)); +} + +//----------------------------------------------------------------------------- +// Get attribute - BOOLEAN +bool XMLNode::getAttributeBool(string _sName, bool _bDefaultValue) +{ + if (!hasAttribute(_sName)) return _bDefaultValue; + string res = getAttribute(_sName); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Has option? +bool XMLNode::hasOption(string _sKey) +{ + xml_node<> *iter; + for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) { + xml_attribute<> *attr = iter->first_attribute("key"); + if (attr && _sKey == attr->value()) + return true; + } + return false; +} + +//----------------------------------------------------------------------------- +// Get option - STRING +string XMLNode::getOption(string _sKey, string _sDefaultValue) +{ + xml_node<> *iter; + for (iter = fDOMElement->first_node("Option"); iter; iter = iter->next_sibling("Option")) { + xml_attribute<> *attr = iter->first_attribute("key"); + if (attr && _sKey == attr->value()) { + attr = iter->first_attribute("value"); + if (!attr) + return ""; + return attr->value(); + } + } + return _sDefaultValue; +} + +//----------------------------------------------------------------------------- +// Get option - NUMERICAL +float32 XMLNode::getOptionNumerical(string _sKey, float32 _fDefaultValue) +{ + if (!hasOption(_sKey)) return _fDefaultValue; + return boost::lexical_cast<float32>(getOption(_sKey)); +} + +//----------------------------------------------------------------------------- +// Get option - BOOL +bool XMLNode::getOptionBool(string _sKey, bool _bDefaultValue) +{ + bool bHasOption = hasOption(_sKey); + if (!bHasOption) return _bDefaultValue; + string res = getOption(_sKey); + return ((res == "1") || (res == "yes") || (res == "true") || (res == "on")); +} + +//----------------------------------------------------------------------------- +// Get option - NUMERICAL ARRAY +vector<float32> XMLNode::getOptionNumericalArray(string _sKey) +{ + if (!hasOption(_sKey)) return vector<float32>(); + + list<XMLNode*> nodes = getNodes("Option"); + for (list<XMLNode*>::iterator it = nodes.begin(); it != nodes.end(); it++) { + if ((*it)->getAttribute("key") == _sKey) { + vector<float32> vals = (*it)->getContentNumericalArray(); + deleteNodes(nodes); + return vals; + } + } + + deleteNodes(nodes); + return vector<float32>(); +} + +//----------------------------------------------------------------------------- + + + + + + + + + + + + +//----------------------------------------------------------------------------- +// BUILD NODE +//----------------------------------------------------------------------------- + +//----------------------------------------------------------------------------- +// Add child node - EMPTY +XMLNode* XMLNode::addChildNode(string _sNodeName) +{ + xml_document<> *doc = fDOMElement->document(); + char *node_name = doc->allocate_string(_sNodeName.c_str()); + xml_node<> *node = doc->allocate_node(node_element, node_name); + fDOMElement->append_node(node); + + // TODO: clean up: this 'new' requires callers to do memory management + return new XMLNode(node); +} + +//----------------------------------------------------------------------------- +// Add child node - STRING +XMLNode* XMLNode::addChildNode(string _sNodeName, string _sText) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_sText); + return res; +} + +//----------------------------------------------------------------------------- +// Add child node - FLOAT +XMLNode* XMLNode::addChildNode(string _sNodeName, float32 _fValue) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_fValue); + return res; +} + +//----------------------------------------------------------------------------- +// Add child node - LIST +XMLNode* XMLNode::addChildNode(string _sNodeName, float32* _pfList, int _iSize) +{ + XMLNode* res = addChildNode(_sNodeName); + res->setContent(_pfList, _iSize); + return res; +} + +//----------------------------------------------------------------------------- +// Set content - STRING +void XMLNode::setContent(string _sText) +{ + xml_document<> *doc = fDOMElement->document(); + char *text = doc->allocate_string(_sText.c_str()); + fDOMElement->value(text); +} + +//----------------------------------------------------------------------------- +// Set content - FLOAT +void XMLNode::setContent(float32 _fValue) +{ + setContent(boost::lexical_cast<string>(_fValue)); +} + +//----------------------------------------------------------------------------- +// Set content - LIST +void XMLNode::setContent(float32* pfList, int _iSize) +{ + addAttribute("listsize", _iSize); + for (int i = 0; i < _iSize; i++) { + XMLNode* item = addChildNode("ListItem"); + item->addAttribute("index", i); + item->addAttribute("value",pfList[i]); + delete item; + } +} + +//----------------------------------------------------------------------------- +// Add attribute - STRING +void XMLNode::addAttribute(string _sName, string _sText) +{ + xml_document<> *doc = fDOMElement->document(); + char *name = doc->allocate_string(_sName.c_str()); + char *text = doc->allocate_string(_sText.c_str()); + xml_attribute<> *attr = doc->allocate_attribute(name, text); + fDOMElement->append_attribute(attr); +} + +//----------------------------------------------------------------------------- +// Add attribute - FLOAT +void XMLNode::addAttribute(string _sName, float32 _fValue) +{ + addAttribute(_sName, boost::lexical_cast<string>(_fValue)); +} + +//----------------------------------------------------------------------------- +// Add option - STRING +void XMLNode::addOption(string _sName, string _sText) +{ + XMLNode* node = addChildNode("Option"); + node->addAttribute("key", _sName); + node->addAttribute("value", _sText); + delete node; +} + +//----------------------------------------------------------------------------- +// Add option - FLOAT +void XMLNode::addOption(string _sName, float32 _sText) +{ + XMLNode* node = addChildNode("Option"); + node->addAttribute("key", _sName); + node->addAttribute("value", _sText); + delete node; +} +//----------------------------------------------------------------------------- + + diff --git a/src/astra.def b/src/astra.def new file mode 100644 index 0000000..585324c --- /dev/null +++ b/src/astra.def @@ -0,0 +1,6 @@ +; MatlabDLL.def : Declares the module parameters for the DLL. + +LIBRARY "astra" + +EXPORTS + ; Explicit exports can go here diff --git a/src/swrap.cpp b/src/swrap.cpp new file mode 100644 index 0000000..be8238e --- /dev/null +++ b/src/swrap.cpp @@ -0,0 +1,47 @@ +/* +----------------------------------------------------------------------- +Copyright 2012 iMinds-Vision Lab, University of Antwerp + +Contact: astra@ua.ac.be +Website: http://astra.ua.ac.be + + +This file is part of the +All Scale Tomographic Reconstruction Antwerp Toolbox ("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/>. + +----------------------------------------------------------------------- +$Id$ +*/ + +#ifndef _MSC_VER + +#include "astra/swrap.h" +#include <cerrno> + +errno_t fopen_s(FILE** pFile, const char* filename, const char* mode) +{ + if (!pFile) + return EINVAL; + + FILE* x = fopen(filename, mode); + if (!x) + return errno; + + *pFile = x; + return 0; +} + +#endif |