diff options
| -rw-r--r-- | include/astra/ParallelBeamBlobKernelProjector2D.h | 7 | ||||
| -rw-r--r-- | include/astra/ParallelBeamBlobKernelProjector2D.inl | 267 | ||||
| -rw-r--r-- | src/ParallelBeamBlobKernelProjector2D.cpp | 92 | 
3 files changed, 163 insertions, 203 deletions
diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.h b/include/astra/ParallelBeamBlobKernelProjector2D.h index ecf71ef..a718f56 100644 --- a/include/astra/ParallelBeamBlobKernelProjector2D.h +++ b/include/astra/ParallelBeamBlobKernelProjector2D.h @@ -215,7 +215,12 @@ protected:  	float32 m_fBlobSampleRate; //< At which interval are the inserted blob values evaluated?  	int m_iBlobSampleCount; //< Number of evaluated blob samples  	float32* m_pfBlobValues; //< Evaluated blob values -	float32* m_pfBlobValuesNeg; //< Evaluated blob values + +	/** Internal policy-based projection of a range of angles and range. + 	 * (_i*From is inclusive, _i*To exclusive) */ +	template <typename Policy> +	void projectBlock_internal(int _iProjFrom, int _iProjTo, +	                           int _iDetFrom, int _iDetTo, Policy& _policy);  }; diff --git a/include/astra/ParallelBeamBlobKernelProjector2D.inl b/include/astra/ParallelBeamBlobKernelProjector2D.inl index 467e066..203eb51 100644 --- a/include/astra/ParallelBeamBlobKernelProjector2D.inl +++ b/include/astra/ParallelBeamBlobKernelProjector2D.inl @@ -27,186 +27,151 @@ $Id$  */ - -//---------------------------------------------------------------------------------------- -// PROJECT ALL   template <typename Policy>  void CParallelBeamBlobKernelProjector2D::project(Policy& p)  { -	for (int iAngle = 0; iAngle < m_pProjectionGeometry->getProjectionAngleCount(); ++iAngle) { -		for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { -			projectSingleRay(iAngle, iDetector, p); -		} -	} +	projectBlock_internal(0, m_pProjectionGeometry->getProjectionAngleCount(), +		                  0, m_pProjectionGeometry->getDetectorCount(), p);  } - -//---------------------------------------------------------------------------------------- -// PROJECT SINGLE PROJECTION  template <typename Policy>  void CParallelBeamBlobKernelProjector2D::projectSingleProjection(int _iProjection, Policy& p)  { -	for (int iDetector = 0; iDetector < m_pProjectionGeometry->getDetectorCount(); ++iDetector) { -		projectSingleRay(_iProjection, iDetector, p); -	} +	projectBlock_internal(_iProjection, _iProjection + 1, +	                      0, m_pProjectionGeometry->getDetectorCount(), p);  } - - -//---------------------------------------------------------------------------------------- -// PROJECT SINGLE RAY  template <typename Policy>  void CParallelBeamBlobKernelProjector2D::projectSingleRay(int _iProjection, int _iDetector, Policy& p)  { -	ASTRA_ASSERT(m_bIsInitialized); - -	int iRayIndex = _iProjection * m_pProjectionGeometry->getDetectorCount() + _iDetector; - -	// POLICY: RAY PRIOR -	if (!p.rayPrior(iRayIndex)) return; - -	// get values -	float32 t = m_pProjectionGeometry->indexToDetectorOffset(_iDetector); -	float32 theta = m_pProjectionGeometry->getProjectionAngle(_iProjection); -	if (theta >= 7*PIdiv4) theta -= 2*PI; - -	bool flip = false; +	projectBlock_internal(_iProjection, _iProjection + 1, +	                      _iDetector, _iDetector + 1, p); +} -	if (theta >= 3*PIdiv4) { -		theta -= PI; -		t = -t; -		flip = true; +//---------------------------------------------------------------------------------------- +// PROJECT BLOCK - vector projection geometry +template <typename Policy> +void CParallelBeamBlobKernelProjector2D::projectBlock_internal(int _iProjFrom, int _iProjTo, int _iDetFrom, int _iDetTo, Policy& p) +{ +	// variables +	float32 detX, detY, x, y, c, r, update_c, update_r, offset, invBlobExtent, inv_pixelLengthX, inv_pixelLengthY, weight, d; +	int iVolumeIndex, iRayIndex, row, col, iAngle, iDetector, colCount, rowCount, detCount; +	int col_left, col_right, row_top, row_bottom, index; +	const SParProjection * proj = 0; + +	// get vector geometry +	const CParallelVecProjectionGeometry2D* pVecProjectionGeometry; +	if (dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry)) { +		pVecProjectionGeometry = dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry)->toVectorGeometry(); +	} else { +		pVecProjectionGeometry = dynamic_cast<CParallelVecProjectionGeometry2D*>(m_pProjectionGeometry);  	} +	// precomputations +	inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); +	inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); +	colCount = m_pVolumeGeometry->getGridColCount(); +	rowCount = m_pVolumeGeometry->getGridRowCount(); +	detCount = pVecProjectionGeometry->getDetectorCount(); + +	// loop angles +	for (iAngle = _iProjFrom; iAngle < _iProjTo; ++iAngle) { + +		proj = &pVecProjectionGeometry->getProjectionVectors()[iAngle]; + +		bool vertical = fabs(proj->fRayX) < fabs(proj->fRayY); +		if (vertical) { +			update_c = -m_pVolumeGeometry->getPixelLengthY() * (proj->fRayX/proj->fRayY) * inv_pixelLengthX; +			float32 normR = sqrt(proj->fRayY*proj->fRayY + proj->fRayX*proj->fRayX); +			invBlobExtent = m_pVolumeGeometry->getPixelLengthY() / abs(m_fBlobSize * normR / proj->fRayY); +		} else { +			update_r = -m_pVolumeGeometry->getPixelLengthX() * (proj->fRayY/proj->fRayX) * inv_pixelLengthY; +			float32 normR = sqrt(proj->fRayY*proj->fRayY + proj->fRayX*proj->fRayX); +			invBlobExtent = m_pVolumeGeometry->getPixelLengthX() / abs(m_fBlobSize * normR / proj->fRayX); +		} -	if (theta <= PIdiv4) { // -pi/4 <= theta <= pi/4 - -		// precalculate sin, cos, 1/cos -		float32 sin_theta = sin(theta); -		float32 cos_theta = cos(theta); -		float32 inv_cos_theta = 1.0f / cos_theta;  - -		// precalculate other stuff -		float32 lengthPerRow = m_pVolumeGeometry->getPixelLengthY() * inv_cos_theta; -		float32 updatePerRow = sin_theta * lengthPerRow; -		float32 inv_pixelLengthX = 1.0f / m_pVolumeGeometry->getPixelLengthX(); -		float32 pixelLengthX_over_blobSize = m_pVolumeGeometry->getPixelLengthX() / m_fBlobSize; -		 -		// some variables -		int row, col, xmin, xmax; -		float32 P, x, d; - -		// calculate P and x for row 0 -		P = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0)) * inv_cos_theta; -		x = (P - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f; - -		// for each row -		for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) { +		// loop detectors +		for (iDetector = _iDetFrom; iDetector < _iDetTo; ++iDetector) { -			// calculate extent -			xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f); -			xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f); -	 -			// add pixels -			for (col = xmin; col <= xmax; col++) { -				if (col >= 0 && col < m_pVolumeGeometry->getGridColCount()) { -					//d = abs(x - col) * pixelLengthX_over_blobSize; -					//index = (int)(d*m_iBlobSampleCount+0.5f); -					//float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerRow; - -					float32 fWeight; -					int index; -					if ((x >= col) ^ flip) { -						d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta; -						index = (int)(d*m_iBlobSampleCount+0.5f); -						fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; -					} else { -						d = abs(x - col) * pixelLengthX_over_blobSize * cos_theta; -						index = (int)(d*m_iBlobSampleCount+0.5f); -						fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)]; -					} +			iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector; -					int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); -					// POLICY: PIXEL PRIOR + ADD + POSTERIOR -					if (p.pixelPrior(iVolumeIndex)) { -						p.addWeight(iRayIndex, iVolumeIndex, fWeight); -						p.pixelPosterior(iVolumeIndex); +			// POLICY: RAY PRIOR +			if (!p.rayPrior(iRayIndex)) continue; +	 +			detX = proj->fDetSX + (iDetector+0.5f) * proj->fDetUX; +			detY = proj->fDetSY + (iDetector+0.5f) * proj->fDetUY; + +			// vertically +			if (vertical) { + +				// calculate x for row 0 +				x = detX + (proj->fRayX/proj->fRayY)*(m_pVolumeGeometry->pixelRowToCenterY(0)-detY); +				c = (x - m_pVolumeGeometry->getWindowMinX()) * inv_pixelLengthX - 0.5f; + +				// for each row +				for (row = 0; row < rowCount; ++row, c += update_c) { + +					col_left = int(c - 0.5f - m_fBlobSize); +					col_right = int(c + 0.5f + m_fBlobSize); + +					if (col_left < 0) col_left = 0;  +					if (col_right > colCount-1) col_right = colCount-1;  + +					// for each column +					for (col = col_left; col <= col_right; ++col) { + +						offset = abs(c - float32(col)) * invBlobExtent; +						index = (int)(offset*m_iBlobSampleCount+0.5f); +						weight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; +				 +						iVolumeIndex = row * colCount + col; +						// POLICY: PIXEL PRIOR + ADD + POSTERIOR +						if (p.pixelPrior(iVolumeIndex)) { +							p.addWeight(iRayIndex, iVolumeIndex, weight); +							p.pixelPosterior(iVolumeIndex); +						}  					}  				}  			} -			// update P and x -			P += updatePerRow; -			x += updatePerRow * inv_pixelLengthX; -		} +			// horizontally +			else { -	} else { // pi/4 < theta < 3pi/4 - -		// precalculate sin cos -		float32 sin_90_theta = sin(PIdiv2-theta); -		float32 cos_90_theta = cos(PIdiv2-theta); -		float32 inv_cos_90_theta = 1.0f / cos_90_theta;  - -		// precalculate other stuff -		float32 lengthPerCol = m_pVolumeGeometry->getPixelLengthX() * inv_cos_90_theta; -		float32 updatePerCol = sin_90_theta * lengthPerCol; -		float32 inv_pixelLengthY = 1.0f / m_pVolumeGeometry->getPixelLengthY(); -		float32 pixelLengthY_over_blobSize = m_pVolumeGeometry->getPixelLengthY() / m_fBlobSize; - -		// some variables -		int row, col, xmin, xmax; -		float32 P,x, d; - -		// calculate P and x for col 0 -		P = (sin_90_theta * m_pVolumeGeometry->pixelColToCenterX(0) - t) * inv_cos_90_theta; -		x = (P - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f; - -		// for each col -		for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) { - -			// calculate extent -			xmin = (int)ceil((P - m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f); -			xmax = (int)floor((P + m_fBlobSize - m_pVolumeGeometry->getWindowMinY()) * inv_pixelLengthY - 0.5f); - -			// add pixels -			for (row = xmin; row <= xmax; row++) { -				if (row >= 0 && row < m_pVolumeGeometry->getGridRowCount()) { -					//d = abs(x - row) * pixelLengthY_over_blobSize; -					//int index = (int)(d*m_iBlobSampleCount+0.5f); -					//float32 fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)] * lengthPerCol; - -					float32 fWeight; -					int index; -					if ((x <= row) ^ flip) { -						d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta; -						index = (int)(d*m_iBlobSampleCount+0.5f); -						fWeight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; -					} else { -						d = abs(x - row) * pixelLengthY_over_blobSize * cos_90_theta; -						index = (int)(d*m_iBlobSampleCount+0.5f); -						fWeight = m_pfBlobValuesNeg[min(index,m_iBlobSampleCount-1)]; -					} +				// calculate y for col 0 +				y = detY + (proj->fRayY/proj->fRayX)*(m_pVolumeGeometry->pixelColToCenterX(0)-detX); +				r = (m_pVolumeGeometry->getWindowMaxY() - y) * inv_pixelLengthY - 0.5f; +				// for each col +				for (col = 0; col < colCount; ++col, r += update_r) { -					int iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col); -					// POLICY: PIXEL PRIOR + ADD + POSTERIOR -					if (p.pixelPrior(iVolumeIndex)) { -						p.addWeight(iRayIndex, iVolumeIndex, fWeight); -						p.pixelPosterior(iVolumeIndex); -					} -				} -			} +					row_top = int(r - 0.5f - m_fBlobSize); +					row_bottom = int(r + 0.5f + m_fBlobSize); -			// update P and x -			P += updatePerCol; -			x += updatePerCol * inv_pixelLengthY; -		} +					if (row_top < 0) row_top = 0;  +					if (row_bottom > rowCount-1) row_bottom = rowCount-1;  -	} - -	// POLICY: RAY POSTERIOR -	p.rayPosterior(iRayIndex); +					// for each column +					for (row = row_top; row <= row_bottom; ++row) { +						offset = abs(r - float32(row)) * invBlobExtent; +						index = (int)(offset*m_iBlobSampleCount+0.5f); +						weight = m_pfBlobValues[min(index,m_iBlobSampleCount-1)]; +				 +						iVolumeIndex = row * colCount + col; +						// POLICY: PIXEL PRIOR + ADD + POSTERIOR +						if (p.pixelPrior(iVolumeIndex)) { +							p.addWeight(iRayIndex, iVolumeIndex, weight); +							p.pixelPosterior(iVolumeIndex); +						} +					} +				} +			} +	 +			// POLICY: RAY POSTERIOR +			p.rayPosterior(iRayIndex); +	 +		} // end loop detector +	} // end loop angles  } diff --git a/src/ParallelBeamBlobKernelProjector2D.cpp b/src/ParallelBeamBlobKernelProjector2D.cpp index 3253f88..d030576 100644 --- a/src/ParallelBeamBlobKernelProjector2D.cpp +++ b/src/ParallelBeamBlobKernelProjector2D.cpp @@ -102,7 +102,7 @@ bool CParallelBeamBlobKernelProjector2D::_check()  	// check base class  	ASTRA_CONFIG_CHECK(CProjector2D::_check(), "ParallelBeamBlobKernelProjector2D", "Error in Projector2D initialization"); -	ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamBlobKernelProjector2D", "Unsupported projection geometry"); +	ASTRA_CONFIG_CHECK(dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry) || dynamic_cast<CParallelVecProjectionGeometry2D*>(m_pProjectionGeometry), "ParallelBeamBlobKernelProjector2D", "Unsupported projection geometry");  	ASTRA_CONFIG_CHECK(m_iBlobSampleCount > 0, "ParallelBeamBlobKernelProjector2D", "m_iBlobSampleCount should be strictly positive.");  	ASTRA_CONFIG_CHECK(m_pfBlobValues, "ParallelBeamBlobKernelProjector2D", "Invalid Volume Geometry Object."); @@ -156,16 +156,6 @@ bool CParallelBeamBlobKernelProjector2D::initialize(const Config& _cfg)  			m_pfBlobValues[i] = values[i];  		} -		// Required: KernelValues -		node2 = node->getSingleNode("KernelValuesNeg"); -		ASTRA_CONFIG_CHECK(node2, "BlobProjector", "No Kernel/KernelValuesNeg tag specified."); -		vector<float32> values2 = node2->getContentNumericalArray(); -		ASTRA_CONFIG_CHECK(values2.size() == (unsigned int)m_iBlobSampleCount, "BlobProjector", "Number of specified values doesn't match SampleCount."); -		m_pfBlobValuesNeg = new float32[m_iBlobSampleCount]; -		for (int i = 0; i < m_iBlobSampleCount; i++) { -			m_pfBlobValuesNeg[i] = values2[i]; -		} -  	}  	// success @@ -228,44 +218,44 @@ void CParallelBeamBlobKernelProjector2D::computeSingleRayWeights(int _iProjectio  // Splat a single point  std::vector<SDetector2D> CParallelBeamBlobKernelProjector2D::projectPoint(int _iRow, int _iCol)  { -	float32 x = m_pVolumeGeometry->pixelColToCenterX(_iCol); -	float32 y = m_pVolumeGeometry->pixelRowToCenterY(_iRow); - -	std::vector<SDetector2D> res; -	// loop projectors and detectors -	for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { - -		// get projection angle -		float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); -		if (theta >= 7*PIdiv4) theta -= 2*PI; -		bool inverse = false; -		if (theta >= 3*PIdiv4) { -			theta -= PI; -			inverse = true; -		} - -		// calculate distance from the center of the voxel to the ray though the origin -		float32 t = x * cos(theta) + y * sin(theta); -		if (inverse) t *= -1.0f; - -		// calculate the offset on the detectorarray (in indices) -		float32 d = m_pProjectionGeometry->detectorOffsetToIndexFloat(t); -		int dmin = (int)ceil(d - m_fBlobSize); -		int dmax = (int)floor(d + m_fBlobSize); - -		// add affected detectors to the list -		for (int i = dmin; i <= dmax; ++i) { -			if (d >= 0 && d < m_pProjectionGeometry->getDetectorCount()) { -				SDetector2D det; -				det.m_iAngleIndex = iProjection; -				det.m_iDetectorIndex = i; -				det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; -				res.push_back(det); -			} -		} -	} - -	// return result vector -	return res; - +	// float32 x = m_pVolumeGeometry->pixelColToCenterX(_iCol); +	// float32 y = m_pVolumeGeometry->pixelRowToCenterY(_iRow); + +	// std::vector<SDetector2D> res; +	// // loop projectors and detectors +	// for (int iProjection = 0; iProjection < m_pProjectionGeometry->getProjectionAngleCount(); ++iProjection) { + +	// 	// get projection angle +	// 	float32 theta = m_pProjectionGeometry->getProjectionAngle(iProjection); +	// 	if (theta >= 7*PIdiv4) theta -= 2*PI; +	// 	bool inverse = false; +	// 	if (theta >= 3*PIdiv4) { +	// 		theta -= PI; +	// 		inverse = true; +	// 	} + +	// 	// calculate distance from the center of the voxel to the ray though the origin +	// 	float32 t = x * cos(theta) + y * sin(theta); +	// 	if (inverse) t *= -1.0f; + +	// 	// calculate the offset on the detectorarray (in indices) +	// 	float32 d = m_pProjectionGeometry->detectorOffsetToIndexFloat(t); +	// 	int dmin = (int)ceil(d - m_fBlobSize); +	// 	int dmax = (int)floor(d + m_fBlobSize); + +	// 	// add affected detectors to the list +	// 	for (int i = dmin; i <= dmax; ++i) { +	// 		if (d >= 0 && d < m_pProjectionGeometry->getDetectorCount()) { +	// 			SDetector2D det; +	// 			det.m_iAngleIndex = iProjection; +	// 			det.m_iDetectorIndex = i; +	// 			det.m_iIndex = iProjection * getProjectionGeometry()->getDetectorCount() + i; +	// 			res.push_back(det); +	// 		} +	// 	} +	// } + +	// // return result vector +	// return res; +	return std::vector<SDetector2D>();  }  | 
