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; | 
