diff options
40 files changed, 346 insertions, 152 deletions
diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..4a179f1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,45 @@ +language: python + +python: + - "2.7" + - "3.5" + +os: + - linux + +sudo: false + +addons: + apt: + packages: + - libboost-all-dev + - nvidia-common + - nvidia-current + - nvidia-cuda-toolkit + - nvidia-cuda-dev +env: + - CUDA=yes + - CUDA=no + +before_install: + - if [[ "$TRAVIS_PYTHON_VERSION" == "2.7" ]]; then + wget https://repo.continuum.io/miniconda/Miniconda-latest-Linux-x86_64.sh -O miniconda.sh; + else + wget https://repo.continuum.io/miniconda/Miniconda3-latest-Linux-x86_64.sh -O miniconda.sh; + fi + - bash miniconda.sh -b -p $HOME/miniconda + - export PATH="$HOME/miniconda/bin:$PATH" + - conda config --set always_yes yes --set changeps1 no + - conda update conda + +install: + - conda install python=$TRAVIS_PYTHON_VERSION six numpy scipy cython + - conda info -a + - cd build/linux + - ./autogen.sh + - if [ $CUDA == yes ]; then ./configure --prefix=$HOME/astra --with-python --with-cuda; else ./configure --prefix=$HOME/astra --with-python --without-cuda; fi + - make -j 4 + - make install + +script: + - LD_LIBRARY_PATH=$HOME/astra/lib/:$LD_LIBRARY_PATH PYTHONPATH=$HOME/astra/python/:$PYTHONPATH python -c "import astra" diff --git a/build/linux/Makefile.in b/build/linux/Makefile.in index 9535b4c..a199bf6 100644 --- a/build/linux/Makefile.in +++ b/build/linux/Makefile.in @@ -150,6 +150,7 @@ BASE_OBJECTS=\ src/ParallelProjectionGeometry3D.lo \ src/ParallelVecProjectionGeometry3D.lo \ src/PlatformDepSystemCode.lo \ + src/PluginAlgorithm.lo \ src/ProjectionGeometry2D.lo \ src/ProjectionGeometry3D.lo \ src/Projector2D.lo \ @@ -255,7 +256,6 @@ MATLAB_MEX=\ matlab/mex/astra_mex_direct_c.$(MEXSUFFIX) ifeq ($(python),yes) -ALL_OBJECTS+=src/PluginAlgorithm.lo MATLAB_MEX+=matlab/mex/astra_mex_plugin_c.$(MEXSUFFIX) endif @@ -315,8 +315,10 @@ ifeq ($(cuda),yes) ifeq ($(gen_static_libs),yes) @$(NVCC) $(NVCCFLAGS) -c $(<) -o $*.o >/dev/null 2>&1 endif - @# Generate a .d file, with target name $*.lo - @$(NVCC) $(NVCCFLAGS) -M $(<) -MT $(*F).lo -odir $(*D) -o $(*D)/$(DEPDIR)/$(*F).d + @# Generate a .d file, and change the target name in it from .o to .lo + @$(NVCC) $(NVCCFLAGS) -M $(<) -odir $(*D) -o $(*D)/$(DEPDIR)/$(*F).d2 + @sed '1s/\.o :/.lo :/' < $(*D)/$(DEPDIR)/$(*F).d2 > $(*D)/$(DEPDIR)/$(*F).d + @rm -f $(*D)/$(DEPDIR)/$(*F).d2 @# Generate empty targets for all dependencies listed in the .d file. @# This mimics gcc's -MP option. @for x in `cat $(*D)/$(DEPDIR)/$(*F).d`; do if test a$$x != a: -a a$$x != a\\; then echo -e "\n$$x:\n" >> $(*D)/$(DEPDIR)/$(*F).d; fi; done diff --git a/cuda/2d/sart.cu b/cuda/2d/sart.cu index e5cb5bb..c8608a3 100644 --- a/cuda/2d/sart.cu +++ b/cuda/2d/sart.cu @@ -71,6 +71,8 @@ SART::SART() : ReconAlgo() projectionCount = 0; iteration = 0; customOrder = false; + + fRelaxation = 1.0f; } @@ -98,6 +100,7 @@ void SART::reset() projectionCount = 0; iteration = 0; customOrder = false; + fRelaxation = 1.0f; ReconAlgo::reset(); } @@ -200,10 +203,10 @@ bool SART::iterate(unsigned int iterations) // BP, mask, and add back // TODO: Try putting the masking directly in the BP zeroVolumeData(D_tmpData, tmpPitch, dims); - callBP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle, 1.0f); + callBP_SART(D_tmpData, tmpPitch, D_projData, projPitch, angle, fRelaxation); processVol<opAddMul>(D_volumeData, D_maskData, D_tmpData, volumePitch, dims); } else { - callBP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle, 1.0f); + callBP_SART(D_volumeData, volumePitch, D_projData, projPitch, angle, fRelaxation); } if (useMinConstraint) diff --git a/cuda/2d/sart.h b/cuda/2d/sart.h index 7dcd641..eff9ecf 100644 --- a/cuda/2d/sart.h +++ b/cuda/2d/sart.h @@ -50,6 +50,8 @@ public: virtual float computeDiffNorm(); + void setRelaxation(float r) { fRelaxation = r; } + protected: void reset(); bool precomputeWeights(); @@ -78,6 +80,8 @@ protected: // Geometry-specific precomputed data float* D_lineWeight; unsigned int linePitch; + + float fRelaxation; }; } diff --git a/cuda/2d/sirt.cu b/cuda/2d/sirt.cu index 162ee77..4baaccb 100644 --- a/cuda/2d/sirt.cu +++ b/cuda/2d/sirt.cu @@ -50,6 +50,8 @@ SIRT::SIRT() : ReconAlgo() D_minMaskData = 0; D_maxMaskData = 0; + fRelaxation = 1.0f; + freeMinMaxMasks = false; } @@ -83,6 +85,8 @@ void SIRT::reset() useVolumeMask = false; useSinogramMask = false; + fRelaxation = 1.0f; + ReconAlgo::reset(); } @@ -139,6 +143,9 @@ bool SIRT::precomputeWeights() processVol<opMul>(D_pixelWeight, D_maskData, pixelPitch, dims); } + // Also fold the relaxation factor into pixel weights + processVol<opMul>(D_pixelWeight, fRelaxation, pixelPitch, dims); + return true; } @@ -253,6 +260,7 @@ bool SIRT::iterate(unsigned int iterations) callBP(D_tmpData, tmpPitch, D_projData, projPitch, 1.0f); + // pixel weights also contain the volume mask and relaxation factor processVol<opAddMul>(D_volumeData, D_pixelWeight, D_tmpData, volumePitch, dims); if (useMinConstraint) diff --git a/cuda/2d/sirt.h b/cuda/2d/sirt.h index 21094a1..bc913f4 100644 --- a/cuda/2d/sirt.h +++ b/cuda/2d/sirt.h @@ -53,6 +53,8 @@ public: bool uploadMinMaxMasks(const float* minMaskData, const float* maxMaskData, unsigned int pitch); + void setRelaxation(float r) { fRelaxation = r; } + virtual bool iterate(unsigned int iterations); virtual float computeDiffNorm(); @@ -81,6 +83,8 @@ protected: unsigned int minMaskPitch; float* D_maxMaskData; unsigned int maxMaskPitch; + + float fRelaxation; }; bool doSIRT(float* D_volumeData, unsigned int volumePitch, diff --git a/cuda/3d/astra3d.cu b/cuda/3d/astra3d.cu index 8328229..5670873 100644 --- a/cuda/3d/astra3d.cu +++ b/cuda/3d/astra3d.cu @@ -267,6 +267,7 @@ public: float fOriginDetectorDistance; float fSourceZ; float fDetSize; + float fRelaxation; SConeProjection* projs; SPar3DProjection* parprojs; @@ -311,6 +312,8 @@ AstraSIRT3d::AstraSIRT3d() pData->parprojs = 0; pData->fOutputScale = 1.0f; + pData->fRelaxation = 1.0f; + pData->initialized = false; pData->setStartReconstruction = false; @@ -389,6 +392,14 @@ bool AstraSIRT3d::enableSuperSampling(unsigned int iVoxelSuperSampling, return true; } +void AstraSIRT3d::setRelaxation(float r) +{ + if (pData->initialized) + return; + + pData->fRelaxation = r; +} + bool AstraSIRT3d::enableVolumeMask() { if (pData->initialized) @@ -448,6 +459,8 @@ bool AstraSIRT3d::init() if (!ok) return false; + pData->sirt.setRelaxation(pData->fRelaxation); + pData->D_volumeData = allocateVolumeData(pData->dims); ok = pData->D_volumeData.ptr; if (!ok) diff --git a/cuda/3d/astra3d.h b/cuda/3d/astra3d.h index 2782994..2137587 100644 --- a/cuda/3d/astra3d.h +++ b/cuda/3d/astra3d.h @@ -68,6 +68,8 @@ public: bool enableSuperSampling(unsigned int iVoxelSuperSampling, unsigned int iDetectorSuperSampling); + void setRelaxation(float r); + // Enable volume/sinogram masks // // This may optionally be called before init(). diff --git a/cuda/3d/sirt3d.cu b/cuda/3d/sirt3d.cu index 484521e..713944b 100644 --- a/cuda/3d/sirt3d.cu +++ b/cuda/3d/sirt3d.cu @@ -59,6 +59,8 @@ SIRT::SIRT() : ReconAlgo3D() useMinConstraint = false; useMaxConstraint = false; + + fRelaxation = 1.0f; } @@ -89,6 +91,8 @@ void SIRT::reset() useVolumeMask = false; useSinogramMask = false; + fRelaxation = 1.0f; + ReconAlgo3D::reset(); } @@ -196,6 +200,8 @@ bool SIRT::precomputeWeights() // scale pixel weights with mask to zero out masked pixels processVol3D<opMul>(D_pixelWeight, D_maskData, dims); } + processVol3D<opMul>(D_pixelWeight, fRelaxation, dims); + return true; } @@ -307,7 +313,7 @@ bool SIRT::iterate(unsigned int iterations) } #endif - + // pixel weights also contain the volume mask and relaxation factor processVol3D<opAddMul>(D_volumeData, D_tmpData, D_pixelWeight, dims); if (useMinConstraint) diff --git a/cuda/3d/sirt3d.h b/cuda/3d/sirt3d.h index bb3864a..5e93deb 100644 --- a/cuda/3d/sirt3d.h +++ b/cuda/3d/sirt3d.h @@ -48,6 +48,9 @@ public: // init should be called after setting all geometry bool init(); + // Set relaxation factor. This may be called after init and before iterate. + void setRelaxation(float r) { fRelaxation = r; } + // setVolumeMask should be called after init and before iterate, // but only if enableVolumeMask was called before init. // It may be called again after iterate. @@ -91,6 +94,8 @@ protected: float fMinConstraint; float fMaxConstraint; + float fRelaxation; + cudaPitchedPtr D_maskData; cudaPitchedPtr D_smaskData; diff --git a/include/astra/ArtAlgorithm.h b/include/astra/ArtAlgorithm.h index d232b95..1ad9f3f 100644 --- a/include/astra/ArtAlgorithm.h +++ b/include/astra/ArtAlgorithm.h @@ -59,7 +59,7 @@ namespace astra { * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} - * \astra_xml_item_option{Lamda, float, 1, The relaxation factor.} + * \astra_xml_item_option{Relaxation, float, 1, The relaxation factor.} * \astra_xml_item_option{RayOrder, string, "sequential", the order in which the rays are updated. 'sequential' or 'custom'} * \astra_xml_item_option{RayOrderList, n by 2 vector of float, not used, if RayOrder='custom': use this ray order. Each row consist of a projection id and detector id.} * @@ -73,7 +73,7 @@ namespace astra { * cfg.option.UseMinConstraint = 'yes';\n * cfg.option.UseMaxConstraint = 'yes';\n * cfg.option.MaxConstraintValue = 1024;\n - * cfg.option.Lamda = 0.7;\n + * cfg.option.Relaxation = 0.7;\n * cfg.option.RayOrder = 'custom';\n * cfg.option.RayOrderList = [0\,0; 0\,2; 1\,0];\n * alg_id = astra_mex_algorithm('create'\, cfg);\n diff --git a/include/astra/CudaReconstructionAlgorithm2D.h b/include/astra/CudaReconstructionAlgorithm2D.h index dc93a1a..bb5f2a7 100644 --- a/include/astra/CudaReconstructionAlgorithm2D.h +++ b/include/astra/CudaReconstructionAlgorithm2D.h @@ -141,6 +141,9 @@ protected: */ bool setupGeometry(); + /** Initialize CUDA algorithm. For internal use only. + */ + virtual void initCUDAAlgorithm(); /** The internally used CUDA algorithm object */ diff --git a/include/astra/CudaSartAlgorithm.h b/include/astra/CudaSartAlgorithm.h index c22dc4f..e5e18f0 100644 --- a/include/astra/CudaSartAlgorithm.h +++ b/include/astra/CudaSartAlgorithm.h @@ -46,6 +46,7 @@ namespace astra { * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * \astra_xml_item_option{Relaxation, float, 1, The relaxation factor.} * * \par MATLAB example * \astra_code{ @@ -53,6 +54,7 @@ namespace astra { * cfg.ProjectionDataId = sino_id;\n * cfg.ReconstructionDataId = recon_id;\n * cfg.option.ReconstructionMaskId = mask_id;\n + * cfg.option.Relaxation = 1.0;\n * alg_id = astra_mex_algorithm('create'\, cfg);\n * astra_mex_algorithm('iterate'\, alg_id\, 10);\n * astra_mex_algorithm('delete'\, alg_id);\n @@ -97,6 +99,14 @@ public: * @return description string */ virtual std::string description() const; + +protected: + + /** Relaxation factor + */ + float m_fLambda; + + virtual void initCUDAAlgorithm(); }; // inline functions diff --git a/include/astra/CudaSirtAlgorithm.h b/include/astra/CudaSirtAlgorithm.h index 929ac30..3cd8acc 100644 --- a/include/astra/CudaSirtAlgorithm.h +++ b/include/astra/CudaSirtAlgorithm.h @@ -53,6 +53,7 @@ namespace astra { * \astra_xml_item{ProjectionDataId, integer, Identifier of a projection data object as it is stored in the DataManager.} * \astra_xml_item{ReconstructionDataId, integer, Identifier of a volume data object as it is stored in the DataManager.} * \astra_xml_item_option{ReconstructionMaskId, integer, not used, Identifier of a volume data object that acts as a reconstruction mask. 0 = reconstruct on this pixel. 1 = don't reconstruct on this pixel.} + * \astra_xml_item_option{Relaxation, float, 1, Relaxation parameter.} * * \par MATLAB example * \astra_code{ @@ -62,6 +63,7 @@ namespace astra { * cfg.ProjectionDataId = sino_id;\n * cfg.ReconstructionDataId = recon_id;\n * cfg.option.ReconstructionMaskId = mask_id;\n + * cfg.option.Relaxation = 1.0;\n * alg_id = astra_mex_algorithm('create'\, cfg);\n * astra_mex_algorithm('iterate'\, alg_id\, 10);\n * astra_mex_algorithm('delete'\, alg_id);\n @@ -93,8 +95,6 @@ public: */ virtual bool initialize(const Config& _cfg); - virtual void run(int _iNrIterations); - /** Initialize class. * * @param _pProjector Projector Object. (Optional) @@ -114,6 +114,12 @@ public: protected: CFloat32VolumeData2D* m_pMinMask; CFloat32VolumeData2D* m_pMaxMask; + + /** Relaxation factor + */ + float m_fLambda; + + virtual void initCUDAAlgorithm(); }; // inline functions diff --git a/include/astra/CudaSirtAlgorithm3D.h b/include/astra/CudaSirtAlgorithm3D.h index 379720e..60191cd 100644 --- a/include/astra/CudaSirtAlgorithm3D.h +++ b/include/astra/CudaSirtAlgorithm3D.h @@ -50,7 +50,7 @@ class AstraSIRT3d; * * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by: * \f[ - * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} + * v_j^{(k+1)} = v_j^{(k)} + \lambda \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} * \f] * * \par XML Configuration @@ -175,6 +175,7 @@ protected: bool m_bAstraSIRTInit; int m_iDetectorSuperSampling; int m_iVoxelSuperSampling; + float m_fLambda; void initializeFromProjector(); }; diff --git a/include/astra/DataProjectorPolicies.h b/include/astra/DataProjectorPolicies.h index c258f5c..acfb36f 100644 --- a/include/astra/DataProjectorPolicies.h +++ b/include/astra/DataProjectorPolicies.h @@ -319,10 +319,12 @@ class SIRTBPPolicy { CFloat32ProjectionData2D* m_pTotalRayLength; CFloat32VolumeData2D* m_pTotalPixelWeight; + float m_fRelaxation; + public: FORCEINLINE SIRTBPPolicy(); - FORCEINLINE SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pTotalPixelWeight, CFloat32ProjectionData2D* _pTotalRayLength); + FORCEINLINE SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pTotalPixelWeight, CFloat32ProjectionData2D* _pTotalRayLength, float _fRelaxation); FORCEINLINE ~SIRTBPPolicy(); FORCEINLINE bool rayPrior(int _iRayIndex); diff --git a/include/astra/DataProjectorPolicies.inl b/include/astra/DataProjectorPolicies.inl index 0c0eddd..f300761 100644 --- a/include/astra/DataProjectorPolicies.inl +++ b/include/astra/DataProjectorPolicies.inl @@ -712,12 +712,14 @@ SIRTBPPolicy::SIRTBPPolicy() SIRTBPPolicy::SIRTBPPolicy(CFloat32VolumeData2D* _pReconstruction, CFloat32ProjectionData2D* _pSinogram, CFloat32VolumeData2D* _pTotalPixelWeight, - CFloat32ProjectionData2D* _pTotalRayLength) + CFloat32ProjectionData2D* _pTotalRayLength, + float _fRelaxation) { m_pReconstruction = _pReconstruction; m_pSinogram = _pSinogram; m_pTotalPixelWeight = _pTotalPixelWeight; m_pTotalRayLength = _pTotalRayLength; + m_fRelaxation = _fRelaxation; } //---------------------------------------------------------------------------------------- SIRTBPPolicy::~SIRTBPPolicy() @@ -739,7 +741,7 @@ void SIRTBPPolicy::addWeight(int _iRayIndex, int _iVolumeIndex, float32 _fWeight { float32 fGammaBeta = m_pTotalPixelWeight->getData()[_iVolumeIndex] * m_pTotalRayLength->getData()[_iRayIndex]; if ((fGammaBeta > 0.001f) || (fGammaBeta < -0.001f)) { - m_pReconstruction->getData()[_iVolumeIndex] += _fWeight * m_pSinogram->getData()[_iRayIndex] / fGammaBeta; + m_pReconstruction->getData()[_iVolumeIndex] += _fWeight * m_fRelaxation * m_pSinogram->getData()[_iRayIndex] / fGammaBeta; } } //---------------------------------------------------------------------------------------- diff --git a/include/astra/SartAlgorithm.h b/include/astra/SartAlgorithm.h index eb4c61e..cdae029 100644 --- a/include/astra/SartAlgorithm.h +++ b/include/astra/SartAlgorithm.h @@ -49,7 +49,7 @@ namespace astra { * * The update step of pixel \f$v_j\f$ for projection \f$phi\f$ and iteration \f$k\f$ is given by: * \f[ - * v_j^{(k+1)} = v_j^{(k)} + \frac{\sum_{p_i \in P_\phi} \left( \lambda \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}} {\sum_{r=1}^{N}w_{ir} } \right)} {\sum_{p_i \in P_\phi}w_{ij}} + * v_j^{(k+1)} = v_j^{(k)} + \lambda \frac{\sum_{p_i \in P_\phi} \left( \frac{p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}} {\sum_{r=1}^{N}w_{ir} } \right)} {\sum_{p_i \in P_\phi}w_{ij}} * \f] * * \par XML Configuration @@ -64,6 +64,7 @@ namespace astra { * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} * \astra_xml_item_option{ProjectionOrder, string, "sequential", the order in which the projections are updated. 'sequential', 'random' or 'custom'} * \astra_xml_item_option{ProjectionOrderList, vector of float, not used, if ProjectionOrder='custom': use this order.} + * \astra_xml_item_option{Relaxation, float, 1, The relaxation parameter.} * * \par MATLAB example * \astra_code{ @@ -76,7 +77,8 @@ namespace astra { * cfg.option.UseMaxConstraint = 'yes';\n * cfg.option.MaxConstraintValue = 1024;\n * cfg.option.ProjectionOrder = 'custom';\n -* cfg.option.ProjectionOrderList = randperm(100);\n + * cfg.option.ProjectionOrderList = randperm(100);\n + * cfg.option.Relaxation = 1.0;\n * alg_id = astra_mex_algorithm('create'\, cfg);\n * astra_mex_algorithm('iterate'\, alg_id\, 10);\n * astra_mex_algorithm('delete'\, alg_id);\n @@ -215,6 +217,8 @@ protected: //< Current index in the projection order array. int m_iCurrentProjection; + //< Relaxation parameter + float m_fLambda; }; // inline functions diff --git a/include/astra/SirtAlgorithm.h b/include/astra/SirtAlgorithm.h index 05b3fa9..8044d09 100644 --- a/include/astra/SirtAlgorithm.h +++ b/include/astra/SirtAlgorithm.h @@ -49,7 +49,7 @@ namespace astra { * * The update step of pixel \f$v_j\f$ for iteration \f$k\f$ is given by: * \f[ - * v_j^{(k+1)} = v_j^{(k)} + \alpha \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} + * v_j^{(k+1)} = v_j^{(k)} + \lambda \sum_{i=1}^{M} \left( \frac{w_{ij}\left( p_i - \sum_{r=1}^{N} w_{ir}v_r^{(k)}\right)}{\sum_{k=1}^{N} w_{ik}} \right) \frac{1}{\sum_{l=1}^{M}w_{lj}} * \f] * * \par XML Configuration @@ -62,6 +62,7 @@ namespace astra { * \astra_xml_item_option{MinConstraintValue, float, 0, Minimum constraint value.} * \astra_xml_item_option{UseMaxConstraint, bool, false, Use maximum value constraint.} * \astra_xml_item_option{MaxConstraintValue, float, 255, Maximum constraint value.} + * \astra_xml_item_option{Relaxation, float, 1, The relaxation factor.} * * \par XML Example * \astra_code{ @@ -74,6 +75,7 @@ namespace astra { * <Option key="UseMinConstraint" value="yes"/>\n * <Option key="UseMaxConstraint" value="yes"/>\n * <Option key="MaxConstraintValue" value="1024"/>\n + * <Option key="Relaxation" value="1"/>\n * </Algorithm> * } * @@ -88,6 +90,7 @@ namespace astra { * cfg.option.UseMinConstraint = 'yes';\n * cfg.option.UseMaxConstraint = 'yes';\n * cfg.option.MaxConstraintValue = 1024;\n + * cfg.option.Relaxation = 1.0;\n * alg_id = astra_mex_algorithm('create'\, cfg);\n * astra_mex_algorithm('iterate'\, alg_id\, 10);\n * astra_mex_algorithm('delete'\, alg_id);\n @@ -136,6 +139,10 @@ protected: */ int m_iIterationCount; + /** Relaxation parameter + */ + float m_fLambda; + public: // type of the algorithm, needed to register with CAlgorithmFactory diff --git a/include/astra/Utilities.h b/include/astra/Utilities.h index 3ae0e6c..8d7c44d 100644 --- a/include/astra/Utilities.h +++ b/include/astra/Utilities.h @@ -50,40 +50,40 @@ public: //< Parse string as int. //< Throw exception on failure. -int stringToInt(const std::string& s); +_AstraExport int stringToInt(const std::string& s); //< Parse string as float. //< Throw exception on failure. -float stringToFloat(const std::string& s); +_AstraExport float stringToFloat(const std::string& s); //< Parse string as double. //< Throw exception on failure. -double stringToDouble(const std::string& s); +_AstraExport double stringToDouble(const std::string& s); template<typename T> -T stringTo(const std::string& s); +_AstraExport T stringTo(const std::string& s); //< Parse comma/semicolon-separated string as float vector. //< Throw exception on failure. -std::vector<float> stringToFloatVector(const std::string& s); +_AstraExport std::vector<float> stringToFloatVector(const std::string& s); //< Parse comma/semicolon-separated string as double vector. //< Throw exception on failure. -std::vector<double> stringToDoubleVector(const std::string& s); +_AstraExport std::vector<double> stringToDoubleVector(const std::string& s); template<typename T> -std::vector<T> stringToVector(const std::string& s); +_AstraExport std::vector<T> stringToVector(const std::string& s); //< Generate string from float. -std::string floatToString(float f); +_AstraExport std::string floatToString(float f); //< Generate string from double. -std::string doubleToString(double f); +_AstraExport std::string doubleToString(double f); template<typename T> -std::string toString(T f); +_AstraExport std::string toString(T f); } diff --git a/matlab/tools/opTomo.m b/matlab/tools/opTomo.m index 71dfb1e..04b3634 100644 --- a/matlab/tools/opTomo.m +++ b/matlab/tools/opTomo.m @@ -44,11 +44,9 @@ classdef opTomo < opSpot vol_id fp_alg_id bp_alg_id + proj_id % ASTRA IDs handle astra_handle - % geometries - proj_geom; - vol_geom; end % properties properties ( SetAccess = private, GetAccess = public ) @@ -139,6 +137,17 @@ classdef opTomo < opSpot error(['Only type ' 39 'cuda' 39 ' is supported ' ... 'for 3D geometries.']) end + + % setup projector + cfg = astra_struct('cuda3d'); + cfg.ProjectionGeometry = proj_geom; + cfg.VolumeGeometry = vol_geom; + cfg.option.GPUindex = gpu_index; + + % create projector + op.proj_id = astra_mex_projector3d('create', cfg); + % create handle to ASTRA object, for cleaning up + op.astra_handle = opTomo_helper_handle(op.proj_id); % create a function handle op.funHandle = @opTomo_intrnl3D; @@ -148,8 +157,6 @@ classdef opTomo < opSpot % pass object properties op.proj_size = proj_size; op.vol_size = vol_size; - op.proj_geom = proj_geom; - op.vol_geom = vol_geom; op.cflag = false; op.sweepflag = false; @@ -169,10 +176,12 @@ classdef opTomo < opSpot if issparse(x) x = full(x); end - - % convert input to single - if isa(x, 'single') == false + + if isa(x, 'double') + isdouble = true; x = single(x); + else + isdouble = false; end % the multiplication @@ -180,6 +189,10 @@ classdef opTomo < opSpot % make sure output is column vector y = y(:); + + if isdouble + y = double(y); + end end % multiply @@ -194,7 +207,7 @@ classdef opTomo < opSpot function y = opTomo_intrnl2D(op,x,mode) if mode == 1 - % X is passed as a vector, reshape it into an image. + % x is passed as a vector, reshape it into an image. x = reshape(x, op.vol_size); % Matlab data copied to ASTRA data @@ -206,7 +219,7 @@ classdef opTomo < opSpot % retrieve Matlab array y = astra_mex_data2d('get_single', op.sino_id); else - % X is passed as a vector, reshape it into a sinogram. + % x is passed as a vector, reshape it into a sinogram. x = reshape(x, op.proj_size); % Matlab data copied to ASTRA data @@ -218,6 +231,7 @@ classdef opTomo < opSpot % retrieve Matlab array y = astra_mex_data2d('get_single', op.vol_id); end + end % opTomo_intrnl2D @@ -225,55 +239,16 @@ classdef opTomo < opSpot function y = opTomo_intrnl3D(op,x,mode) if mode == 1 - % X is passed as a vector, reshape it into an image + % x is passed as a vector, reshape it into an image x = reshape(x, op.vol_size); - % initialize output - y = zeros(op.proj_size, 'single'); - - % link matlab array to ASTRA - vol_id = astra_mex_data3d_c('link', '-vol', op.vol_geom, x, 0); - sino_id = astra_mex_data3d_c('link', '-sino', op.proj_geom, y, 1); - - % initialize fp algorithm - cfg = astra_struct('FP3D_CUDA'); - cfg.ProjectionDataId = sino_id; - cfg.VolumeDataId = vol_id; - - alg_id = astra_mex_algorithm('create', cfg); - % forward projection - astra_mex_algorithm('iterate', alg_id); - - % cleanup - astra_mex_data3d('delete', vol_id); - astra_mex_data3d('delete', sino_id); - astra_mex_algorithm('delete', alg_id); + y = astra_mex_direct('FP3D', op.proj_id, x); else - % X is passed as a vector, reshape it into projection data + % x is passed as a vector, reshape it into projection data x = reshape(x, op.proj_size); - - % initialize output - y = zeros(op.vol_size,'single'); - - % link matlab array to ASTRA - vol_id = astra_mex_data3d_c('link', '-vol', op.vol_geom, y, 1); - sino_id = astra_mex_data3d_c('link', '-sino', op.proj_geom, x, 0); - % initialize bp algorithm - cfg = astra_struct('BP3D_CUDA'); - cfg.ProjectionDataId = sino_id; - cfg.ReconstructionDataId = vol_id; - - alg_id = astra_mex_algorithm('create', cfg); - - % backprojection - astra_mex_algorithm('iterate', alg_id); - - % cleanup - astra_mex_data3d('delete', vol_id); - astra_mex_data3d('delete', sino_id); - astra_mex_algorithm('delete', alg_id); + y = astra_mex_direct('BP3D', op.proj_id, x); end end % opTomo_intrnl3D diff --git a/python/astra/data3d.py b/python/astra/data3d.py index e5ef6b0..f143659 100644 --- a/python/astra/data3d.py +++ b/python/astra/data3d.py @@ -89,7 +89,7 @@ def get_single(i): :returns: :class:`numpy.ndarray` -- The object data. """ - return g.get_single(i) + return d.get_single(i) def store(i,data): """Fill existing 3D object with data. diff --git a/python/astra/functions.py b/python/astra/functions.py index e38b5bc..3f4aa82 100644 --- a/python/astra/functions.py +++ b/python/astra/functions.py @@ -115,7 +115,7 @@ def add_noise_to_sino(sinogram_in, I0, seed=None): sinogram_out = -max_sinogramRaw * np.log(sinogramCT_D) if not isinstance(sinogram_in, np.ndarray): - at.data2d.store(sinogram_in, sinogram_out) + data2d.store(sinogram_in, sinogram_out) if not seed==None: np.random.set_state(curstate) diff --git a/python/astra/optomo.py b/python/astra/optomo.py index 4a64150..dd10713 100644 --- a/python/astra/optomo.py +++ b/python/astra/optomo.py @@ -160,7 +160,7 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): return self._matvec(v) return scipy.sparse.linalg.LinearOperator.__mul__(self, v) - def reconstruct(self, method, s, iterations=1, extraOptions = {}): + def reconstruct(self, method, s, iterations=1, extraOptions = None): """Reconstruct an object. :param method: Method to use for reconstruction. @@ -172,6 +172,8 @@ class OpTomo(scipy.sparse.linalg.LinearOperator): :param extraOptions: Extra options to use during reconstruction (i.e. for cfg['option']). :type extraOptions: :class:`dict` """ + if extraOptions is None: + extraOptions={} s = self.__checkArray(s, self.sshape) sid = self.data_mod.link('-sino',self.pg,s) v = np.zeros(self.vshape,dtype=np.float32) diff --git a/python/astra/utils.pyx b/python/astra/utils.pyx index 52c2a8d..34d1902 100644 --- a/python/astra/utils.pyx +++ b/python/astra/utils.pyx @@ -32,7 +32,7 @@ import six if six.PY3: import builtins else: - import __builtin__ + import __builtin__ as builtins from libcpp.string cimport string from libcpp.vector cimport vector from libcpp.list cimport list @@ -95,14 +95,14 @@ cdef void readDict(XMLNode root, _dc): dc = convert_item(_dc) for item in dc: val = dc[item] - if isinstance(val, __builtins__.list) or isinstance(val, tuple): + if isinstance(val, builtins.list) or isinstance(val, tuple): val = np.array(val,dtype=np.float64) if isinstance(val, np.ndarray): if val.size == 0: break listbase = root.addChildNode(item) contig_data = np.ascontiguousarray(val,dtype=np.float64) - data = <double*>np.PyArray_DATA(contig_data) + data = <double*>np.PyArray_DATA(contig_data) if val.ndim == 2: listbase.setContent(data, val.shape[1], val.shape[0], False) elif val.ndim == 1: @@ -119,6 +119,8 @@ cdef void readDict(XMLNode root, _dc): if item == six.b('type'): root.addAttribute(< string > six.b('type'), <string> wrap_to_bytes(val)) else: + if isinstance(val, builtins.bool): + val = int(val) itm = root.addChildNode(item, wrap_to_bytes(val)) cdef void readOptions(XMLNode node, dc): @@ -131,7 +133,7 @@ cdef void readOptions(XMLNode node, dc): val = dc[item] if node.hasOption(item): raise Exception('Duplicate Option: %s' % item) - if isinstance(val, __builtins__.list) or isinstance(val, tuple): + if isinstance(val, builtins.list) or isinstance(val, tuple): val = np.array(val,dtype=np.float64) if isinstance(val, np.ndarray): if val.size == 0: @@ -147,6 +149,8 @@ cdef void readOptions(XMLNode node, dc): else: raise Exception("Only 1 or 2 dimensions are allowed") else: + if isinstance(val, builtins.bool): + val = int(val) node.addOption(item, wrap_to_bytes(val)) cdef configToDict(Config *cfg): diff --git a/python/conda/build.sh b/python/conda/build.sh index 814ea7e..13ae3f8 100644 --- a/python/conda/build.sh +++ b/python/conda/build.sh @@ -5,12 +5,4 @@ if [ $MAKEOPTS == '<UNDEFINED>' ] then MAKEOPTS="" fi -make $MAKEOPTS install-libraries -make $MAKEOPTS python-root-install -LIBPATH=lib -if [ $ARCH == 64 ] - then - LIBPATH+=64 -fi -cp -P $CUDA_ROOT/$LIBPATH/libcudart.so.* $PREFIX/lib -cp -P $CUDA_ROOT/$LIBPATH/libcufft.so.* $PREFIX/lib +make $MAKEOPTS python-root-install
\ No newline at end of file diff --git a/python/conda/libastra/build.sh b/python/conda/libastra/build.sh new file mode 100644 index 0000000..e1d9700 --- /dev/null +++ b/python/conda/libastra/build.sh @@ -0,0 +1,15 @@ +cd build/linux +./autogen.sh +./configure --with-cuda=$CUDA_ROOT --prefix=$PREFIX +if [ $MAKEOPTS == '<UNDEFINED>' ] + then + MAKEOPTS="" +fi +make $MAKEOPTS install-libraries +LIBPATH=lib +if [ $ARCH == 64 ] + then + LIBPATH+=64 +fi +cp -P $CUDA_ROOT/$LIBPATH/libcudart.so.* $PREFIX/lib +cp -P $CUDA_ROOT/$LIBPATH/libcufft.so.* $PREFIX/lib diff --git a/python/conda/libastra/meta.yaml b/python/conda/libastra/meta.yaml new file mode 100644 index 0000000..73fa0d7 --- /dev/null +++ b/python/conda/libastra/meta.yaml @@ -0,0 +1,22 @@ +package: + name: libastra + version: '1.8b' + +source: + git_url: https://github.com/astra-toolbox/astra-toolbox.git + #git_tag: v1.7.1 # Change to 1.8 after release + +build: + number: 0 + script_env: + - CUDA_ROOT + - MAKEOPTS + +about: + home: http://www.astra-toolbox.com + license: GPLv3 + summary: 'The ASTRA Toolbox is a Python toolbox of high-performance GPU primitives for 2D and 3D tomography.' + +# See +# http://docs.continuum.io/conda/build.html for +# more information about meta.yaml diff --git a/python/conda/meta.yaml b/python/conda/meta.yaml index 7e4679b..e6a7f52 100644 --- a/python/conda/meta.yaml +++ b/python/conda/meta.yaml @@ -1,10 +1,10 @@ package: name: astra-toolbox - version: '1.7.1' + version: '1.8b' source: git_url: https://github.com/astra-toolbox/astra-toolbox.git - git_tag: v1.7.1 + #git_tag: v1.7.1 # Change to 1.8 after release build: number: 0 @@ -29,10 +29,11 @@ requirements: - numpy - scipy - six + - libastra ==1.8b about: - home: http://sourceforge.net/p/astra-toolbox/wiki/Home/ + home: http://www.astra-toolbox.com license: GPLv3 summary: 'The ASTRA Toolbox is a Python toolbox of high-performance GPU primitives for 2D and 3D tomography.' diff --git a/src/ArtAlgorithm.cpp b/src/ArtAlgorithm.cpp index b59bd93..526c263 100644 --- a/src/ArtAlgorithm.cpp +++ b/src/ArtAlgorithm.cpp @@ -156,8 +156,12 @@ bool CArtAlgorithm::initialize(const Config& _cfg) return false; } + // "Lambda" is replaced by the more descriptive "Relaxation" m_fLambda = _cfg.self.getOptionNumerical("Lambda", 1.0f); - CC.markOptionParsed("Lambda"); + m_fLambda = _cfg.self.getOptionNumerical("Relaxation", m_fLambda); + if (!_cfg.self.hasOption("Relaxation")) + CC.markOptionParsed("Lambda"); + CC.markOptionParsed("Relaxation"); // success m_bIsInitialized = _check(); @@ -232,7 +236,7 @@ map<string,boost::any> CArtAlgorithm::getInformation() { map<string, boost::any> res; res["RayOrder"] = getInformation("RayOrder"); - res["Lambda"] = getInformation("Lambda"); + res["Relaxation"] = getInformation("Relaxation"); return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); }; @@ -240,7 +244,7 @@ map<string,boost::any> CArtAlgorithm::getInformation() // Information - Specific boost::any CArtAlgorithm::getInformation(std::string _sIdentifier) { - if (_sIdentifier == "Lambda") { return m_fLambda; } + if (_sIdentifier == "Relaxation") { return m_fLambda; } if (_sIdentifier == "RayOrder") { vector<float32> res; for (int i = 0; i < m_iRayCount; i++) { diff --git a/src/CudaDataOperationAlgorithm.cpp b/src/CudaDataOperationAlgorithm.cpp index 15886a4..82b676b 100644 --- a/src/CudaDataOperationAlgorithm.cpp +++ b/src/CudaDataOperationAlgorithm.cpp @@ -76,7 +76,7 @@ bool CCudaDataOperationAlgorithm::initialize(const Config& _cfg) 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++){ + for (vector<string>::iterator it = data.begin(); it != data.end(); ++it){ int id = StringUtil::stringToInt(*it); m_pData.push_back(dynamic_cast<CFloat32Data2D*>(CData2DManager::getSingleton().get(id))); } diff --git a/src/CudaReconstructionAlgorithm2D.cpp b/src/CudaReconstructionAlgorithm2D.cpp index 5a1910c..2798434 100644 --- a/src/CudaReconstructionAlgorithm2D.cpp +++ b/src/CudaReconstructionAlgorithm2D.cpp @@ -329,6 +329,20 @@ bool CCudaReconstructionAlgorithm2D::setupGeometry() } //---------------------------------------------------------------------------------------- + +void CCudaReconstructionAlgorithm2D::initCUDAAlgorithm() +{ + bool ok; + + ok = setupGeometry(); + ASTRA_ASSERT(ok); + + ok = m_pAlgo->allocateBuffers(); + ASTRA_ASSERT(ok); +} + + +//---------------------------------------------------------------------------------------- // Iterate void CCudaReconstructionAlgorithm2D::run(int _iNrIterations) { @@ -339,13 +353,7 @@ void CCudaReconstructionAlgorithm2D::run(int _iNrIterations) const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); if (!m_bAlgoInit) { - - ok = setupGeometry(); - ASTRA_ASSERT(ok); - - ok = m_pAlgo->allocateBuffers(); - ASTRA_ASSERT(ok); - + initCUDAAlgorithm(); m_bAlgoInit = true; } diff --git a/src/CudaSartAlgorithm.cpp b/src/CudaSartAlgorithm.cpp index d202847..bf97224 100644 --- a/src/CudaSartAlgorithm.cpp +++ b/src/CudaSartAlgorithm.cpp @@ -107,7 +107,8 @@ bool CCudaSartAlgorithm::initialize(const Config& _cfg) CC.markOptionParsed("ProjectionOrderList"); } - + m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f); + CC.markOptionParsed("Relaxation"); return true; } @@ -123,12 +124,26 @@ bool CCudaSartAlgorithm::initialize(CProjector2D* _pProjector, if (!m_bIsInitialized) return false; + m_fLambda = 1.0f; + m_pAlgo = new astraCUDA::SART(); m_bAlgoInit = false; return true; } +//---------------------------------------------------------------------------------------- + +void CCudaSartAlgorithm::initCUDAAlgorithm() +{ + CCudaReconstructionAlgorithm2D::initCUDAAlgorithm(); + + astraCUDA::SART* pSart = dynamic_cast<astraCUDA::SART*>(m_pAlgo); + + pSart->setRelaxation(m_fLambda); +} + + } // namespace astra diff --git a/src/CudaSirtAlgorithm.cpp b/src/CudaSirtAlgorithm.cpp index 33e381a..c8dc677 100644 --- a/src/CudaSirtAlgorithm.cpp +++ b/src/CudaSirtAlgorithm.cpp @@ -50,6 +50,8 @@ CCudaSirtAlgorithm::CCudaSirtAlgorithm() m_pMinMask = 0; m_pMaxMask = 0; + + m_fLambda = 1.0f; } //---------------------------------------------------------------------------------------- @@ -86,6 +88,8 @@ bool CCudaSirtAlgorithm::initialize(const Config& _cfg) } CC.markOptionParsed("MaxMaskId"); + m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f); + CC.markOptionParsed("Relaxation"); m_pAlgo = new astraCUDA::SIRT(); m_bAlgoInit = false; @@ -108,41 +112,30 @@ bool CCudaSirtAlgorithm::initialize(CProjector2D* _pProjector, m_pAlgo = new astraCUDA::SIRT(); m_bAlgoInit = false; + m_fLambda = 1.0f; return true; } //---------------------------------------------------------------------------------------- -// Iterate -void CCudaSirtAlgorithm::run(int _iNrIterations) + +void CCudaSirtAlgorithm::initCUDAAlgorithm() { - // check initialized - ASTRA_ASSERT(m_bIsInitialized); + CCudaReconstructionAlgorithm2D::initCUDAAlgorithm(); - if (!m_bAlgoInit) { - // We only override the initialisation step to copy the min/max masks + astraCUDA::SIRT* pSirt = dynamic_cast<astraCUDA::SIRT*>(m_pAlgo); - bool ok = setupGeometry(); + if (m_pMinMask || m_pMaxMask) { + const CVolumeGeometry2D& volgeom = *m_pReconstruction->getGeometry(); + const float *pfMinMaskData = 0; + const float *pfMaxMaskData = 0; + if (m_pMinMask) pfMinMaskData = m_pMinMask->getDataConst(); + if (m_pMaxMask) pfMaxMaskData = m_pMaxMask->getDataConst(); + bool ok = pSirt->uploadMinMaxMasks(pfMinMaskData, pfMaxMaskData, volgeom.getGridColCount()); 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); + pSirt->setRelaxation(m_fLambda); } diff --git a/src/CudaSirtAlgorithm3D.cpp b/src/CudaSirtAlgorithm3D.cpp index 605c470..c819f8e 100644 --- a/src/CudaSirtAlgorithm3D.cpp +++ b/src/CudaSirtAlgorithm3D.cpp @@ -56,6 +56,7 @@ CCudaSirtAlgorithm3D::CCudaSirtAlgorithm3D() m_iGPUIndex = -1; m_iVoxelSuperSampling = 1; m_iDetectorSuperSampling = 1; + m_fLambda = 1.0f; } //---------------------------------------------------------------------------------------- @@ -128,6 +129,8 @@ bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg) return false; } + m_fLambda = _cfg.self.getOptionNumerical("Relaxation"); + initializeFromProjector(); // Deprecated options @@ -135,6 +138,7 @@ bool CCudaSirtAlgorithm3D::initialize(const Config& _cfg) m_iDetectorSuperSampling = (int)_cfg.self.getOptionNumerical("DetectorSuperSampling", m_iDetectorSuperSampling); m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUindex", m_iGPUIndex); m_iGPUIndex = (int)_cfg.self.getOptionNumerical("GPUIndex", m_iGPUIndex); + CC.markOptionParsed("VoxelSuperSampling"); CC.markOptionParsed("DetectorSuperSampling"); CC.markOptionParsed("GPUIndex"); @@ -164,6 +168,8 @@ bool CCudaSirtAlgorithm3D::initialize(CProjector3D* _pProjector, clear(); } + m_fLambda = 1.0f; + // required classes m_pProjector = _pProjector; m_pSinogram = _pSinogram; @@ -224,6 +230,8 @@ void CCudaSirtAlgorithm3D::run(int _iNrIterations) ASTRA_ASSERT(ok); + m_pSirt->setRelaxation(m_fLambda); + m_bAstraSIRTInit = true; } diff --git a/src/FilteredBackProjectionAlgorithm.cpp b/src/FilteredBackProjectionAlgorithm.cpp index c195578..ccbfec6 100644 --- a/src/FilteredBackProjectionAlgorithm.cpp +++ b/src/FilteredBackProjectionAlgorithm.cpp @@ -117,12 +117,10 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) int angleCount = projectionIndex.size(); int detectorCount = m_pProjector->getProjectionGeometry()->getDetectorCount(); + // TODO: There is no need to allocate this. Better just + // create the CFloat32ProjectionData2D object directly, and use its + // memory. 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(); @@ -130,6 +128,8 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) for (int i = 0; i < angleCount; i ++) { if (projectionIndex[i] > m_pProjector->getProjectionGeometry()->getProjectionAngleCount() -1 ) { + delete[] sinogramData2D; + delete[] projectionAngles; ASTRA_ERROR("Invalid Projection Index"); return false; } else { @@ -139,7 +139,6 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) { 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] ); } @@ -148,6 +147,9 @@ bool CFilteredBackProjectionAlgorithm::initialize(const Config& _cfg) CParallelProjectionGeometry2D * pg = new CParallelProjectionGeometry2D(angleCount, detectorCount,detectorWidth,projectionAngles); m_pProjector = new CParallelBeamLineKernelProjector2D(pg,m_pReconstruction->getGeometry()); m_pSinogram = new CFloat32ProjectionData2D(pg, sinogramData2D); + + delete[] sinogramData2D; + delete[] projectionAngles; } // TODO: check that the angles are linearly spaced between 0 and pi diff --git a/src/Float32VolumeData3DMemory.cpp b/src/Float32VolumeData3DMemory.cpp index af45cb9..14adb1a 100644 --- a/src/Float32VolumeData3DMemory.cpp +++ b/src/Float32VolumeData3DMemory.cpp @@ -136,7 +136,6 @@ CFloat32VolumeData2D * CFloat32VolumeData3DMemory::fetchSliceZ(int _iSliceIndex) CFloat32VolumeData2D* res = new CFloat32VolumeData2D(&volGeom); // copy data - int iSliceCount = m_pGeometry->getGridSliceCount(); float * pfTargetData = res->getData(); for(int iRowIndex = 0; iRowIndex < iRowCount; iRowIndex++) { diff --git a/src/SartAlgorithm.cpp b/src/SartAlgorithm.cpp index 9346160..8df3342 100644 --- a/src/SartAlgorithm.cpp +++ b/src/SartAlgorithm.cpp @@ -151,6 +151,9 @@ bool CSartAlgorithm::initialize(const Config& _cfg) CC.markOptionParsed("ProjectionOrderList"); } + m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f); + CC.markOptionParsed("Relaxation"); + // create data objects m_pTotalRayLength = new CFloat32ProjectionData2D(m_pProjector->getProjectionGeometry()); m_pTotalPixelWeight = new CFloat32VolumeData2D(m_pProjector->getVolumeGeometry()); @@ -246,6 +249,7 @@ map<string,boost::any> CSartAlgorithm::getInformation() { map<string, boost::any> res; res["ProjectionOrder"] = getInformation("ProjectionOrder"); + res["Relaxation"] = getInformation("Relaxation"); return mergeMap<string,boost::any>(CReconstructionAlgorithm2D::getInformation(), res); }; @@ -253,6 +257,8 @@ map<string,boost::any> CSartAlgorithm::getInformation() // Information - Specific boost::any CSartAlgorithm::getInformation(std::string _sIdentifier) { + if (_sIdentifier == "Relaxation") + return m_fLambda; if (_sIdentifier == "ProjectionOrder") { vector<float32> res; for (int i = 0; i < m_iProjectionCount; i++) { @@ -272,9 +278,8 @@ void CSartAlgorithm::run(int _iNrIterations) m_bShouldAbort = false; - int iIteration = 0; - // data projectors + CDataProjectorInterface* pFirstForwardProjector; CDataProjectorInterface* pForwardProjector; CDataProjectorInterface* pBackProjector; @@ -286,13 +291,13 @@ void CSartAlgorithm::run(int _iNrIterations) m_pProjector, SinogramMaskPolicy(m_pSinogramMask), // sinogram mask ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask - SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength), // SIRT backprojection + SIRTBPPolicy(m_pReconstruction, m_pDiffSinogram, m_pTotalPixelWeight, m_pTotalRayLength, m_fLambda), // 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( + pFirstForwardProjector = dispatchDataProjector( m_pProjector, SinogramMaskPolicy(m_pSinogramMask), // sinogram mask ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask @@ -303,16 +308,30 @@ void CSartAlgorithm::run(int _iNrIterations) m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off ); + // forward projection data projector + pForwardProjector = dispatchDataProjector( + m_pProjector, + SinogramMaskPolicy(m_pSinogramMask), // sinogram mask + ReconstructionMaskPolicy(m_pReconstructionMask), // reconstruction mask + CombinePolicy<DiffFPPolicy, TotalPixelWeightPolicy>( // 2 basic operations + DiffFPPolicy(m_pReconstruction, m_pDiffSinogram, m_pSinogram), // forward projection with difference calculation + TotalPixelWeightPolicy(m_pTotalPixelWeight)), // calculate the total pixel weights + m_bUseSinogramMask, m_bUseReconstructionMask, true // options on/off + ); + // iteration loop - for (; iIteration < _iNrIterations && !m_bShouldAbort; ++iIteration) { + for (int iIteration = 0; 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); + if (iIteration < m_iProjectionCount) + pFirstForwardProjector->projectSingleProjection(iProjection); + else + pForwardProjector->projectSingleProjection(iProjection); // backprojection pBackProjector->projectSingleProjection(iProjection); // update iteration count @@ -325,6 +344,7 @@ void CSartAlgorithm::run(int _iNrIterations) } + ASTRA_DELETE(pFirstForwardProjector); ASTRA_DELETE(pForwardProjector); ASTRA_DELETE(pBackProjector); diff --git a/src/SirtAlgorithm.cpp b/src/SirtAlgorithm.cpp index d9f3a65..ff25648 100644 --- a/src/SirtAlgorithm.cpp +++ b/src/SirtAlgorithm.cpp @@ -76,6 +76,7 @@ void CSirtAlgorithm::_clear() m_pDiffSinogram = NULL; m_pTmpVolume = NULL; + m_fLambda = 1.0f; m_iIterationCount = 0; } @@ -91,6 +92,7 @@ void CSirtAlgorithm::clear() ASTRA_DELETE(m_pDiffSinogram); ASTRA_DELETE(m_pTmpVolume); + m_fLambda = 1.0f; m_iIterationCount = 0; } @@ -128,6 +130,9 @@ bool CSirtAlgorithm::initialize(const Config& _cfg) return false; } + m_fLambda = _cfg.self.getOptionNumerical("Relaxation", 1.0f); + CC.markOptionParsed("Relaxation"); + // init data objects and data projectors _init(); @@ -152,6 +157,8 @@ bool CSirtAlgorithm::initialize(CProjector2D* _pProjector, m_pSinogram = _pSinogram; m_pReconstruction = _pReconstruction; + m_fLambda = 1.0f; + // init data objects and data projectors _init(); @@ -248,7 +255,7 @@ void CSirtAlgorithm::run(int _iNrIterations) x = 1.0f / x; else x = 0.0f; - pfT[i] = x; + pfT[i] = m_fLambda * x; } pfT = m_pTotalRayLength->getData(); for (int i = 0; i < m_pTotalRayLength->getSize(); ++i) { @@ -296,7 +303,7 @@ void CSirtAlgorithm::run(int _iNrIterations) m_pTmpVolume->setData(0.0f); pBackProjector->project(); - // divide by pixel weights + // multiply with relaxation factor divided by pixel weights (*m_pTmpVolume) *= (*m_pTotalPixelWeight); (*m_pReconstruction) += (*m_pTmpVolume); diff --git a/src/XMLNode.cpp b/src/XMLNode.cpp index 40a9b22..cf268c2 100644 --- a/src/XMLNode.cpp +++ b/src/XMLNode.cpp @@ -158,7 +158,7 @@ vector<string> XMLNode::getContentArray() const 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++) { + 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); @@ -290,7 +290,7 @@ vector<float32> XMLNode::getOptionNumericalArray(string _sKey) const if (!hasOption(_sKey)) return vector<float32>(); list<XMLNode> nodes = getNodes("Option"); - for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); it++) { + for (list<XMLNode>::iterator it = nodes.begin(); it != nodes.end(); ++it) { if (it->getAttribute("key") == _sKey) { vector<float32> vals = it->getContentNumericalArray(); return vals; |