/* ----------------------------------------------------------------------- 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 "astra/Float32Data2D.h" #include #include #include #ifdef _MSC_VER #include #else #include #endif namespace astra { CFloat32CustomMemory::~CFloat32CustomMemory() { } //---------------------------------------------------------------------------------------- // 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); } //---------------------------------------------------------------------------------------- // Create an instance of the CFloat32Data2D class with pre-allocated memory. CFloat32Data2D::CFloat32Data2D(int _iWidth, int _iHeight, CFloat32CustomMemory *_pCustomMemory) { m_bInitialized = false; _initialize(_iWidth, _iHeight, _pCustomMemory); } //---------------------------------------------------------------------------------------- // 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 { if (m_pCustomMemory) { // Can't re-allocate custom data ASTRA_ASSERT(false); return *(CFloat32Data2D*)0; } // 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; m_pCustomMemory = 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; m_pCustomMemory = 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; m_pCustomMemory = 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; } //---------------------------------------------------------------------------------------- // Initializes an instance of the CFloat32Data2D class with pre-allocated memory bool CFloat32Data2D::_initialize(int _iWidth, int _iHeight, CFloat32CustomMemory* _pCustomMemory) { // basic checks ASTRA_ASSERT(_iWidth > 0); ASTRA_ASSERT(_iHeight > 0); ASTRA_ASSERT(_pCustomMemory != NULL); if (m_bInitialized) { _unInit(); } // calculate size m_iWidth = _iWidth; m_iHeight = _iHeight; m_iSize = (size_t)m_iWidth * m_iHeight; // initialize the data pointers m_pCustomMemory = _pCustomMemory; m_pfData = 0; m_ppfData2D = 0; _allocateData(); // 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((size_t)m_iSize == (size_t)m_iWidth * m_iHeight); ASTRA_ASSERT(m_pfData == NULL); ASTRA_ASSERT(m_ppfData2D == NULL); if (!m_pCustomMemory) { // 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 } else { m_pfData = m_pCustomMemory->m_fPtr; } // 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; if (!m_pCustomMemory) { // free memory for data block #ifdef _MSC_VER _aligned_free(m_pfData); #else free(m_pfData); #endif } else { delete m_pCustomMemory; m_pCustomMemory = 0; } } //---------------------------------------------------------------------------------------- // 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_pCustomMemory = 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); } std::string CFloat32Data2D::description() const { std::stringstream res; res << m_iWidth << "x" << m_iHeight; if (getType() == CFloat32Data2D::PROJECTION) res << " sinogram data \t"; if (getType() == CFloat32Data2D::VOLUME) res << " volume data \t"; return res.str(); } } // end namespace astra