/* ----------------------------------------------------------------------- Copyright: 2010-2021, imec Vision Lab, University of Antwerp 2014-2021, CWI, Amsterdam Contact: astra@astra-toolbox.com Website: http://www.astra-toolbox.com/ This file is part of the ASTRA Toolbox. The ASTRA Toolbox is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. The ASTRA Toolbox is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with the ASTRA Toolbox. If not, see . ----------------------------------------------------------------------- */ #include #include #include "astra/AstraObjectManager.h" #include "astra/CudaProjector2D.h" #include "astra/Filters.h" #include "astra/cuda/2d/astra.h" #include "astra/cuda/2d/fbp.h" #include "astra/Logging.h" using namespace std; using namespace astra; string CCudaFilteredBackProjectionAlgorithm::type = "FBP_CUDA"; CCudaFilteredBackProjectionAlgorithm::CCudaFilteredBackProjectionAlgorithm() { m_bIsInitialized = false; CCudaReconstructionAlgorithm2D::_clear(); } CCudaFilteredBackProjectionAlgorithm::~CCudaFilteredBackProjectionAlgorithm() { delete[] m_filterConfig.m_pfCustomFilter; m_filterConfig.m_pfCustomFilter = NULL; } bool CCudaFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) { ASTRA_ASSERT(_cfg.self); ConfigStackCheck CC("CudaFilteredBackProjectionAlgorithm", this, _cfg); // if already initialized, clear first if (m_bIsInitialized) { clear(); } m_bIsInitialized = CCudaReconstructionAlgorithm2D::initialize(_cfg); if (!m_bIsInitialized) return false; m_filterConfig = getFilterConfigForAlgorithm(_cfg, this); // Fan beam short scan mode if (m_pSinogram && dynamic_cast(m_pSinogram->getGeometry())) { m_bShortScan = (int)_cfg.self.getOptionBool("ShortScan", false); CC.markOptionParsed("ShortScan"); } initializeFromProjector(); m_pAlgo = new astraCUDA::FBP(); m_bAlgoInit = false; return check(); } 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_filterConfig.m_eType = _eFilter; m_filterConfig.m_iCustomFilterWidth = _iFilterWidth; m_bShortScan = false; // success m_bIsInitialized = true; m_pAlgo = new astraCUDA::FBP(); m_bAlgoInit = false; if(_pfFilter != NULL) { int iFilterElementCount = 0; if((m_filterConfig.m_eType != FILTER_SINOGRAM) && (m_filterConfig.m_eType != FILTER_RSINOGRAM)) { iFilterElementCount = _iFilterWidth; } else { iFilterElementCount = m_pSinogram->getAngleCount(); } m_filterConfig.m_pfCustomFilter = new float[iFilterElementCount]; memcpy(m_filterConfig.m_pfCustomFilter, _pfFilter, iFilterElementCount * sizeof(float)); } else { m_filterConfig.m_pfCustomFilter = NULL; } m_filterConfig.m_fParameter = _fFilterParameter; return check(); } void CCudaFilteredBackProjectionAlgorithm::initCUDAAlgorithm() { CCudaReconstructionAlgorithm2D::initCUDAAlgorithm(); astraCUDA::FBP* pFBP = dynamic_cast(m_pAlgo); bool ok = pFBP->setFilter(m_filterConfig); if (!ok) { ASTRA_ERROR("CCudaFilteredBackProjectionAlgorithm: Failed to set filter"); ASTRA_ASSERT(ok); } ok &= pFBP->setShortScan(m_bShortScan); if (!ok) { ASTRA_ERROR("CCudaFilteredBackProjectionAlgorithm: Failed to set short-scan mode"); } const CVolumeGeometry2D& volGeom = *m_pReconstruction->getGeometry(); float fPixelArea = volGeom.getPixelArea(); ok &= pFBP->setReconstructionScale(1.0f/fPixelArea); if (!ok) { ASTRA_ERROR("CCudaFilteredBackProjectionAlgorithm: Failed to set reconstruction scale"); } } 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."); ASTRA_CONFIG_CHECK(m_filterConfig.m_eType != FILTER_ERROR, "FBP_CUDA", "Invalid filter name."); if((m_filterConfig.m_eType == FILTER_PROJECTION) || (m_filterConfig.m_eType == FILTER_SINOGRAM) || (m_filterConfig.m_eType == FILTER_RPROJECTION) || (m_filterConfig.m_eType == FILTER_RSINOGRAM)) { ASTRA_CONFIG_CHECK(m_filterConfig.m_pfCustomFilter, "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 >= -1, "FBP_CUDA", "GPUIndex must be a non-negative integer or -1."); // check pixel supersampling ASTRA_CONFIG_CHECK(m_iPixelSuperSampling >= 0, "FBP_CUDA", "PixelSuperSampling must be a non-negative integer."); ASTRA_CONFIG_CHECK(checkCustomFilterSize(m_filterConfig, *m_pSinogram->getGeometry()), "FBP_CUDA", "Filter size mismatch"); // success m_bIsInitialized = true; return true; }