summaryrefslogtreecommitdiffstats
path: root/include/astra/ParallelBeamStripKernelProjector2D.inl
diff options
context:
space:
mode:
Diffstat (limited to 'include/astra/ParallelBeamStripKernelProjector2D.inl')
-rw-r--r--include/astra/ParallelBeamStripKernelProjector2D.inl467
1 files changed, 230 insertions, 237 deletions
diff --git a/include/astra/ParallelBeamStripKernelProjector2D.inl b/include/astra/ParallelBeamStripKernelProjector2D.inl
index e8e3739..fdfcd90 100644
--- a/include/astra/ParallelBeamStripKernelProjector2D.inl
+++ b/include/astra/ParallelBeamStripKernelProjector2D.inl
@@ -29,7 +29,7 @@ template <typename Policy>
void CParallelBeamStripKernelProjector2D::project(Policy& p)
{
projectBlock_internal(0, m_pProjectionGeometry->getProjectionAngleCount(),
- 0, m_pProjectionGeometry->getDetectorCount(), p);
+ 0, m_pProjectionGeometry->getDetectorCount(), p);
}
template <typename Policy>
@@ -47,251 +47,244 @@ void CParallelBeamStripKernelProjector2D::projectSingleRay(int _iProjection, int
}
//----------------------------------------------------------------------------------------
-// PROJECT BLOCK
+/* PROJECT BLOCK
+
+ Kernel limitations: isotropic pixels (PixelLengthX == PixelLengthY)
+
+ For each angle/detector pair:
+
+ Let DL=(DLx,DLy) denote the left of the detector (point) in volume coordinates, and
+ Let DR=(DRx,DRy) denote the right of the detector (point) in volume coordinates, and
+ let R=(Rx,Ry) denote the direction of the ray (vector).
+
+ For mainly vertical rays (|Rx|<=|Ry|),
+ let E=(Ex,Ey) denote the centre of the most upper left pixel:
+ E = (WindowMinX + PixelLengthX/2, WindowMaxY - PixelLengthY/2),
+ and let F=(Fx,Fy) denote a vector to the next pixel
+ F = (PixelLengthX, 0)
+
+ The intersection of the left edge of the strip (DL+aR) with the centre line of the upper row of pixels (E+bF) is
+ { DLx + a*Rx = Ex + b*Fx
+ { DLy + a*Ry = Ey + b*Fy
+ Solving for (a,b) results in:
+ a = (Ey + b*Fy - DLy)/Ry
+ = (Ey - DLy)/Ry
+ b = (DLx + a*Rx - Ex)/Fx
+ = (DLx + (Ey - DLy)*Rx/Ry - Ex)/Fx
+
+ Define cL as the x-value of the intersection of the left edge of the strip with the upper row in pixel coordinates.
+ cL = b
+
+ cR, the x-value of the intersection of the right edge of the strip with the upper row in pixel coordinates can be found similarly.
+
+ The intersection of the ray (DL+aR) with the left line of the second row of pixels (E'+bF) with
+ E'=(WindowMinX + PixelLengthX/2, WindowMaxY - 3*PixelLengthY/2)
+ expressed in x-value pixel coordinates is
+ cL' = (DLx + (Ey' - DLy)*Rx/Ry - Ex)/Fx.
+ And thus:
+ deltac = cL' - cL = (DLx + (Ey' - DLy)*Rx/Ry - Ex)/Fx - (DLx + (Ey - DLy)*Rx/Ry - Ex)/Fx
+ = [(Ey' - DLy)*Rx/Ry - (Ey - DLy)*Rx/Ry]/Fx
+ = [Ey' - Ey]*(Rx/Ry)/Fx
+ = [Ey' - Ey]*(Rx/Ry)/Fx
+ = -PixelLengthY*(Rx/Ry)/Fx.
+
+ The projection weight for a certain pixel is defined by the area between two points of
+
+ _____ LengthPerRow
+ /| | |\
+ / | | | \
+ __/ | | | \__ 0
+ -T -S 0 S T
+ with S = 1/2 - 1/2*|Rx/Ry|, T = 1/2 + 1/2*|Rx/Ry|, and LengthPerRow = pixelLengthX * sqrt(Rx^2+Ry^2) / |Ry|
+
+ For a certain row, all columns that are 'hit' by this kernel lie in the interval
+ (col_left, col_right) = (floor(cL-1/2+S), floor(cR+3/2-S))
+
+ The offsets for both is
+ (offsetL, offsetR) = (cL - floor(col_left), cR - floor(col_left))
+
+ The projection weight is found by the difference between the integrated values of the kernel
+ offset <= -T Kernel = 0
+ -T < offset <= -S Kernel = PixelArea/2*(T+offset)^2/(T-S)
+ -S < offset <= S Kernel = PixelArea/2 + offset
+ S < offset <= T Kernel = PixelArea - PixelArea/2*(T-offset)^2/(T-S)
+ T <= offset: Kernel = PixelArea
+*/
template <typename Policy>
void CParallelBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, int _iProjTo, int _iDetFrom, int _iDetTo, Policy& p)
{
- ASTRA_ASSERT(m_bIsInitialized);
-
- // Some variables
- float32 theta, t;
- int row, col;
- int iAngle;
- int iDetector;
- float32 res;
- float32 PL, PLimitL, PLimitR;
- float32 xL, xR, XLimitL, XLimitR;
- int x1L,x1R;
- float32 x2L, x2R, updateX;
- int iVolumeIndex, iRayIndex;
-
- float32 sin_theta, cos_theta, inv_sin_theta, inv_cos_theta;
- float32 fabs_sin_theta, fabs_cos_theta, fabs_inv_sin_theta, fabs_inv_cos_theta;
- float32 PW, PH, DW, inv_PW, inv_PH;
- float32 S, T, U, V, inv_4T;
+ // 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
+ const float32 pixelLengthX = m_pVolumeGeometry->getPixelLengthX();
+ const float32 pixelLengthY = m_pVolumeGeometry->getPixelLengthY();
+ const float32 pixelArea = pixelLengthX * pixelLengthY;
+ const float32 inv_pixelLengthX = 1.0f / pixelLengthX;
+ const float32 inv_pixelLengthY = 1.0f / pixelLengthY;
+ const int colCount = m_pVolumeGeometry->getGridColCount();
+ const int rowCount = m_pVolumeGeometry->getGridRowCount();
+ const int detCount = pVecProjectionGeometry->getDetectorCount();
// loop angles
- for (iAngle = _iProjFrom; iAngle < _iProjTo; ++iAngle) {
-
- // get values
- theta = m_pProjectionGeometry->getProjectionAngle(iAngle);
- bool switch_t = false;
- if (theta >= 7*PIdiv4) theta -= 2*PI;
- if (theta >= 3*PIdiv4) {
- theta -= PI;
- switch_t = true;
- }
-
- // Precalculate sin, cos, 1/cos
- sin_theta = sin(theta);
- cos_theta = cos(theta);
- inv_cos_theta = 1.0f / cos_theta;
- inv_sin_theta = 1.0f / sin_theta;
-
- fabs_sin_theta = (sin_theta < 0.0f) ? -sin_theta : sin_theta;
- fabs_cos_theta = (cos_theta < 0.0f) ? -cos_theta : cos_theta;
- fabs_inv_cos_theta = (inv_cos_theta < 0.0f) ? -inv_cos_theta : inv_cos_theta;
- fabs_inv_sin_theta = (inv_sin_theta < 0.0f) ? -inv_sin_theta : inv_sin_theta;
-
- // Other precalculations
- PW = m_pVolumeGeometry->getPixelLengthX();
- PH = m_pVolumeGeometry->getPixelLengthY();
- DW = m_pProjectionGeometry->getDetectorWidth();
- inv_PW = 1.0f / PW;
- inv_PH = 1.0f / PH;
-
- // [-45?,45?] and [135?,225?]
- if (theta < PIdiv4) {
-
- // Precalculate kernel limits
- S = -0.5f * fabs_sin_theta * fabs_inv_cos_theta;
- T = -S;
- U = 1.0f + S;
- V = 1.0f - S;
- inv_4T = 0.25f / T;
-
- updateX = sin_theta * inv_cos_theta;
-
- // loop detectors
- for (iDetector = _iDetFrom; iDetector < _iDetTo; ++iDetector) {
-
- iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
-
- // POLICY: RAY PRIOR
- if (!p.rayPrior(iRayIndex)) continue;
-
- // get t
- t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
- if (switch_t) t = -t;
-
- // calculate left strip extremes (volume coordinates)
- PL = (t - sin_theta * m_pVolumeGeometry->pixelRowToCenterY(0) - DW*0.5f) * inv_cos_theta;
- PLimitL = PL - 0.5f * fabs_sin_theta * fabs_inv_cos_theta * PH;
- PLimitR = PLimitL + DW * inv_cos_theta + PH * fabs_sin_theta * fabs_inv_cos_theta;
-
- // calculate strip extremes (pixel coordinates)
- XLimitL = (PLimitL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
- XLimitR = (PLimitR - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
- xL = (PL - m_pVolumeGeometry->getWindowMinX()) * inv_PW;
- xR = xL + (DW * inv_cos_theta) * inv_PW;
-
- // for each row
- for (row = 0; row < m_pVolumeGeometry->getGridRowCount(); ++row) {
-
- // get strip extremes in column indices
- x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
- x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
-
- // get coords w.r.t leftmost column hit by strip
- x2L = xL - x1L;
- x2R = xR - x1L;
-
- // update strip extremes for the next row
- XLimitL += updateX;
- XLimitR += updateX;
- xL += updateX;
- xR += updateX;
-
- // for each affected col
- for (col = x1L; col <= x1R; ++col) {
-
- if (col < 0 || col >= m_pVolumeGeometry->getGridColCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
- // POLICY: PIXEL PRIOR
- if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // right
- if (x2R >= V) res = 1.0f;
- else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
- else if (x2R >= T) res = x2R;
- else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // left
- if (x2L <= S) {} // - 0.0f
- else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
- else if (x2L <= U) res -= x2L;
- else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // POLICY: ADD
- p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
-
- // POLICY: PIXEL POSTERIOR
- p.pixelPosterior(iVolumeIndex);
-
- x2L -= 1.0f;
- x2R -= 1.0f;
-
- } // end col loop
-
- } // end row loop
-
- // POLICY: RAY POSTERIOR
- p.rayPosterior(iRayIndex);
-
- } // end detector loop
-
- // [45?,135?] and [225?,315?]
- // horizontaly
+ for (int iAngle = _iProjFrom; iAngle < _iProjTo; ++iAngle) {
+
+ // variables
+ float32 DLx, DLy, DRx, DRy, Ex, Ey, S, T, deltac, deltar, offsetL, offsetR, invTminS;
+ float32 res, RxOverRy, RyOverRx, cL, cR, rL, rR;
+ int iVolumeIndex, iRayIndex, iDetector;
+ int row, row_top, row_bottom, col, col_left, col_right;
+
+ const SParProjection * proj = &pVecProjectionGeometry->getProjectionVectors()[iAngle];
+
+ bool vertical = fabs(proj->fRayX) < fabs(proj->fRayY);
+ if (vertical) {
+ RxOverRy = proj->fRayX/proj->fRayY;
+ deltac = -m_pVolumeGeometry->getPixelLengthY() * RxOverRy * inv_pixelLengthX;
+ S = 0.5f - 0.5f*fabs(RxOverRy);
+ T = 0.5f + 0.5f*fabs(RxOverRy);
+ invTminS = 1.0f / (T-S);
} else {
+ RyOverRx = proj->fRayY/proj->fRayX;
+ deltar = -m_pVolumeGeometry->getPixelLengthX() * RyOverRx * inv_pixelLengthY;
+ S = 0.5f - 0.5f*fabs(RyOverRx);
+ T = 0.5f + 0.5f*fabs(RyOverRx);
+ invTminS = 1.0f / (T-S);
+ }
- // Precalculate kernel limits
- S = -0.5f * fabs_cos_theta * fabs_inv_sin_theta;
- T = -S;
- U = 1.0f + S;
- V = 1.0f - S;
- inv_4T = 0.25f / T;
-
- updateX = cos_theta * inv_sin_theta;
-
- // loop detectors
- for (iDetector = _iDetFrom; iDetector < _iDetTo; ++iDetector) {
-
- iRayIndex = iAngle * m_pProjectionGeometry->getDetectorCount() + iDetector;
-
- // POLICY: RAY PRIOR
- if (!p.rayPrior(iRayIndex)) continue;
+ Ex = m_pVolumeGeometry->getWindowMinX() + pixelLengthX*0.5f;
+ Ey = m_pVolumeGeometry->getWindowMaxY() - pixelLengthY*0.5f;
- // get t
- t = m_pProjectionGeometry->indexToDetectorOffset(iDetector);
- if (switch_t) t = -t;
+ // loop detectors
+ for (iDetector = _iDetFrom; iDetector < _iDetTo; ++iDetector) {
- // calculate left strip extremes (volume coordinates)
- PL = (t - cos_theta * m_pVolumeGeometry->pixelColToCenterX(0) + DW*0.5f) * inv_sin_theta;
- PLimitL = PL + 0.5f * fabs_cos_theta * fabs_inv_sin_theta * PW;
- PLimitR = PLimitL - DW * inv_sin_theta - PH * fabs_cos_theta * fabs_inv_sin_theta;
-
- // calculate strip extremes (pixel coordinates)
- XLimitL = (m_pVolumeGeometry->getWindowMaxY() - PLimitL) * inv_PH;
- XLimitR = (m_pVolumeGeometry->getWindowMaxY() - PLimitR) * inv_PH;
- xL = (m_pVolumeGeometry->getWindowMaxY() - PL) * inv_PH;
- xR = xL + (DW * fabs_inv_sin_theta) * inv_PH;
-
- // for each col
- for (col = 0; col < m_pVolumeGeometry->getGridColCount(); ++col) {
-
- // get strip extremes in column indices
- x1L = int((XLimitL > 0.0f) ? XLimitL : XLimitL-1.0f);
- x1R = int((XLimitR > 0.0f) ? XLimitR : XLimitR-1.0f);
-
- // get coords w.r.t leftmost column hit by strip
- x2L = xL - x1L;
- x2R = xR - x1L;
-
- // update strip extremes for the next row
- XLimitL += updateX;
- XLimitR += updateX;
- xL += updateX;
- xR += updateX;
+ iRayIndex = iAngle * detCount + iDetector;
- // for each affected col
- for (row = x1L; row <= x1R; ++row) {
-
- if (row < 0 || row >= m_pVolumeGeometry->getGridRowCount()) { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- iVolumeIndex = m_pVolumeGeometry->pixelRowColToIndex(row, col);
-
- // POLICY: PIXEL PRIOR
- if (!p.pixelPrior(iVolumeIndex)) { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // right
- if (x2R >= V) res = 1.0f;
- else if (x2R > U) res = x2R - (x2R-U)*(x2R-U)*inv_4T;
- else if (x2R >= T) res = x2R;
- else if (x2R > S) res = (x2R-S)*(x2R-S) * inv_4T;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // left
- if (x2L <= S) {} // - 0.0f
- else if (x2L < T) res -= (x2L-S)*(x2L-S) * inv_4T;
- else if (x2L <= U) res -= x2L;
- else if (x2L < V) res -= x2L - (x2L-U)*(x2L-U)*inv_4T;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
-
- // POLICY: ADD
- p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
-
- // POLICY: PIXEL POSTERIOR
- p.pixelPosterior(iVolumeIndex);
-
- x2L -= 1.0f;
- x2R -= 1.0f;
-
- } // end row loop
-
- } // end col loop
-
- // POLICY: RAY POSTERIOR
- p.rayPosterior(iRayIndex);
-
- } // end detector loop
-
-
- } // end theta switch
+ // POLICY: RAY PRIOR
+ if (!p.rayPrior(iRayIndex)) continue;
+
+ DLx = proj->fDetSX + iDetector * proj->fDetUX;
+ DLy = proj->fDetSY + iDetector * proj->fDetUY;
+ DRx = DLx + proj->fDetUX;
+ DRy = DLy + proj->fDetUY;
+
+ // vertically
+ if (vertical) {
+
+ // calculate cL and cR for row 0
+ cL = (DLx + (Ey - DLy)*RxOverRy - Ex) * inv_pixelLengthX;
+ cR = (DRx + (Ey - DRy)*RxOverRy - Ex) * inv_pixelLengthX;
+
+ if (cR < cL) {
+ float32 tmp = cL;
+ cL = cR;
+ cR = tmp;
+ }
+
+ // loop rows
+ for (row = 0; row < rowCount; ++row, cL += deltac, cR += deltac) {
+
+ col_left = int(cL-0.5f+S);
+ col_right = int(cR+1.5-S);
+
+ if (col_left < 0) col_left = 0;
+ if (col_right > colCount-1) col_right = colCount-1;
+
+ float32 tmp = float32(col_left);
+ offsetL = cL - tmp;
+ offsetR = cR - tmp;
+
+ // loop columns
+ for (col = col_left; col <= col_right; ++col, offsetL -= 1.0f, offsetR -= 1.0f) {
+
+ iVolumeIndex = row * colCount + col;
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+
+ // right ray edge
+ if (T <= offsetR) res = 1.0f;
+ else if (S < offsetR) res = 1.0f - 0.5f*(T-offsetR)*(T-offsetR)*invTminS;
+ else if (-S < offsetR) res = 0.5f + offsetR;
+ else if (-T < offsetR) res = 0.5f*(offsetR+T)*(offsetR+T)*invTminS;
+ else res = 0.0f;
+
+ // left ray edge
+ if (T <= offsetL) res -= 1.0f;
+ else if (S < offsetL) res -= 1.0f - 0.5f*(T-offsetL)*(T-offsetL)*invTminS;
+ else if (-S < offsetL) res -= 0.5f + offsetL;
+ else if (-T < offsetL) res -= 0.5f*(offsetL+T)*(offsetL+T)*invTminS;
+
+ p.addWeight(iRayIndex, iVolumeIndex, pixelArea*res);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // horizontally
+ else {
+
+ // calculate rL and rR for row 0
+ rL = -(DLy + (Ex - DLx)*RyOverRx - Ey) * inv_pixelLengthY;
+ rR = -(DRy + (Ex - DRx)*RyOverRx - Ey) * inv_pixelLengthY;
+
+ if (rR < rL) {
+ float32 tmp = rL;
+ rL = rR;
+ rR = tmp;
+ }
+
+ // loop columns
+ for (col = 0; col < colCount; ++col, rL += deltar, rR += deltar) {
+
+ row_top = int(rL-0.5f+S);
+ row_bottom = int(rR+1.5-S);
+
+ if (row_top < 0) row_top = 0;
+ if (row_bottom > rowCount-1) row_bottom = rowCount-1;
+
+ float32 tmp = float32(row_top);
+ offsetL = rL - tmp;
+ offsetR = rR - tmp;
+
+ // loop rows
+ for (row = row_top; row <= row_bottom; ++row, offsetL -= 1.0f, offsetR -= 1.0f) {
+
+ iVolumeIndex = row * colCount + col;
+ // POLICY: PIXEL PRIOR + ADD + POSTERIOR
+ if (p.pixelPrior(iVolumeIndex)) {
+
+ // right ray edge
+ if (T <= offsetR) res = 1.0f;
+ else if (S < offsetR) res = 1.0f - 0.5f*(T-offsetR)*(T-offsetR)*invTminS;
+ else if (-S < offsetR) res = 0.5f + offsetR;
+ else if (-T < offsetR) res = 0.5f*(offsetR+T)*(offsetR+T)*invTminS;
+ else res = 0.0f;
+
+ // left ray edge
+ if (T <= offsetL) res -= 1.0f;
+ else if (S < offsetL) res -= 1.0f - 0.5f*(T-offsetL)*(T-offsetL)*invTminS;
+ else if (-S < offsetL) res -= 0.5f + offsetL;
+ else if (-T < offsetL) res -= 0.5f*(offsetL+T)*(offsetL+T)*invTminS;
+
+ p.addWeight(iRayIndex, iVolumeIndex, pixelArea*res);
+ p.pixelPosterior(iVolumeIndex);
+ }
+ }
+ }
+ }
+
+ // POLICY: RAY POSTERIOR
+ p.rayPosterior(iRayIndex);
+
+ } // end loop detector
+ } // end loop angles
- } // end angle loop
+ if (dynamic_cast<CParallelProjectionGeometry2D*>(m_pProjectionGeometry))
+ delete pVecProjectionGeometry;
}
-
-