summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/astra/FanFlatBeamStripKernelProjector2D.inl54
-rw-r--r--tests/python/test_line2d.py27
2 files changed, 72 insertions, 9 deletions
diff --git a/include/astra/FanFlatBeamStripKernelProjector2D.inl b/include/astra/FanFlatBeamStripKernelProjector2D.inl
index 732c302..889d0a3 100644
--- a/include/astra/FanFlatBeamStripKernelProjector2D.inl
+++ b/include/astra/FanFlatBeamStripKernelProjector2D.inl
@@ -109,6 +109,9 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
// POLICY: RAY PRIOR
if (!p.rayPrior(iRayIndex)) continue;
+ float32 dist_srcDetPixSquared = projgeom->getSourceDetectorDistance() * projgeom->getSourceDetectorDistance() +
+ (iDetector + 0.5f - m_pProjectionGeometry->getDetectorCount()*0.5f) * (iDetector + 0.5f - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW * DW;
+
float32 sin_theta_left, cos_theta_left;
float32 sin_theta_right, cos_theta_right;
@@ -138,10 +141,11 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
float32 inv_cos_theta_left = 1.0f / cos_theta_left;
float32 inv_cos_theta_right = 1.0f / cos_theta_right;
- float32 updateX_left = sin_theta_left * inv_cos_theta_left;
- float32 updateX_right = sin_theta_right * inv_cos_theta_right;
+ float32 updateX_left = sin_theta_left * inv_cos_theta_left; // tan(theta_left)
+ float32 updateX_right = sin_theta_right * inv_cos_theta_right; // tan(theta_right)
// Precalculate kernel limits
+ // BUG: If updateX_left > 1 (which can happen if theta_left >= pi/4 > theta), then T_l > U_l, and the expressions for res are no longer correct
float32 S_l = -0.5f * updateX_left;
if (S_l > 0) {S_l = -S_l;}
float32 T_l = -S_l;
@@ -185,6 +189,13 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
xL += updateX_left;
xR += updateX_right;
+ float32 diffSrcYSquared;
+ if (switch_t)
+ diffSrcYSquared = m_pVolumeGeometry->pixelRowToCenterY(row) + cos_theta * projgeom->getOriginSourceDistance();
+ else
+ diffSrcYSquared = m_pVolumeGeometry->pixelRowToCenterY(row) - cos_theta * projgeom->getOriginSourceDistance();
+ diffSrcYSquared = diffSrcYSquared * diffSrcYSquared;
+
// for each affected col
for (col = x1L; col <= x1R; ++col) {
@@ -199,17 +210,25 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
else if (x2R >= T_r) res = x2R;
else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+ else { x2L -= 1.0f; x2R -= 1.0f; p.pixelPosterior(iVolumeIndex); continue; }
// left
if (x2L <= S_l) {}
else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
else if (x2L <= U_l) res -= x2L;
else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+ else { x2L -= 1.0f; x2R -= 1.0f; p.pixelPosterior(iVolumeIndex); continue; }
+
+ float32 diffSrcX;
+ if (switch_t)
+ diffSrcX = m_pVolumeGeometry->pixelColToCenterX(col) - sin_theta * projgeom->getOriginSourceDistance();
+ else
+ diffSrcX = m_pVolumeGeometry->pixelColToCenterX(col) + sin_theta * projgeom->getOriginSourceDistance();
+
+ float32 scale = sqrt(dist_srcDetPixSquared / (diffSrcYSquared + diffSrcX * diffSrcX));
// POLICY: ADD
- p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res * scale);
// POLICY: PIXEL POSTERIOR
p.pixelPosterior(iVolumeIndex);
@@ -238,6 +257,9 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
// POLICY: RAY PRIOR
if (!p.rayPrior(iRayIndex)) continue;
+ float32 dist_srcDetPixSquared = projgeom->getSourceDetectorDistance() * projgeom->getSourceDetectorDistance() +
+ (iDetector + 0.5f - m_pProjectionGeometry->getDetectorCount()*0.5f) * (iDetector + 0.5f - m_pProjectionGeometry->getDetectorCount()*0.5f) * DW * DW;
+
// get theta_l = alpha_left + theta and theta_r = alpha_right + theta
float32 sin_theta_left, cos_theta_left;
float32 sin_theta_right, cos_theta_right;
@@ -270,6 +292,7 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
float32 updateX_right = cos_theta_right * inv_sin_theta_right;
// Precalculate kernel limits
+ // BUG: If updateX_left > 1 (which can happen if theta_left < pi/4 <= theta), then T_l > U_l, and the expressions for res are no longer correct
float32 S_l = -0.5f * updateX_left;
if (S_l > 0) { S_l = -S_l; }
float32 T_l = -S_l;
@@ -313,6 +336,13 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
xL += updateX_left;
xR += updateX_right;
+ float32 diffSrcXSquared;
+ if (switch_t)
+ diffSrcXSquared = m_pVolumeGeometry->pixelColToCenterX(col) - sin_theta * projgeom->getOriginSourceDistance();
+ else
+ diffSrcXSquared = m_pVolumeGeometry->pixelColToCenterX(col) + sin_theta * projgeom->getOriginSourceDistance();
+ diffSrcXSquared = diffSrcXSquared * diffSrcXSquared;
+
// for each affected row
for (row = x1L; row <= x1R; ++row) {
@@ -328,17 +358,25 @@ void CFanFlatBeamStripKernelProjector2D::projectBlock_internal(int _iProjFrom, i
else if (x2R > U_r) res = x2R - (x2R-U_r)*(x2R-U_r)*inv_4T_r;
else if (x2R >= T_r) res = x2R;
else if (x2R > S_r) res = (x2R-S_r)*(x2R-S_r) * inv_4T_r;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+ else { x2L -= 1.0f; x2R -= 1.0f; p.pixelPosterior(iVolumeIndex); continue; }
// left
if (x2L <= S_l) {}
else if (x2L < T_l) res -= (x2L-S_l)*(x2L-S_l) * inv_4T_l;
else if (x2L <= U_l) res -= x2L;
else if (x2L < V_l) res -= x2L - (x2L-U_l)*(x2L-U_l)*inv_4T_l;
- else { x2L -= 1.0f; x2R -= 1.0f; continue; }
+ else { x2L -= 1.0f; x2R -= 1.0f; p.pixelPosterior(iVolumeIndex); continue; }
+
+ float32 diffSrcY;
+ if (switch_t)
+ diffSrcY = m_pVolumeGeometry->pixelRowToCenterY(row) + cos_theta * projgeom->getOriginSourceDistance();
+ else
+ diffSrcY = m_pVolumeGeometry->pixelRowToCenterY(row) - cos_theta * projgeom->getOriginSourceDistance();
+
+ float32 scale = sqrt(dist_srcDetPixSquared / (diffSrcXSquared + diffSrcY * diffSrcY));
// POLICY: ADD
- p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res);
+ p.addWeight(iRayIndex, iVolumeIndex, PW*PH * res * scale);
// POLICY: PIXEL POSTERIOR
p.pixelPosterior(iVolumeIndex);
diff --git a/tests/python/test_line2d.py b/tests/python/test_line2d.py
index e7bca98..d04ffb8 100644
--- a/tests/python/test_line2d.py
+++ b/tests/python/test_line2d.py
@@ -556,11 +556,36 @@ class Test2DKernel(unittest.TestCase):
if DISPLAY and x > TOL:
display_mismatch(data, sinogram, a)
self.assertFalse(x > TOL)
+ elif proj_type == 'strip' and 'fan' in type:
+ a = np.zeros(np.prod(astra.functions.geom_size(pg)), dtype=np.float32)
+ for i, (center, edge1, edge2) in enumerate(gen_lines(pg)):
+ (src, det) = center
+ det_dist = np.linalg.norm(src-det, ord=2)
+ l = 0.0
+ for j in range(rect_min[0], rect_max[0]):
+ xmin = origin[0] + (-0.5 * shape[0] + j) * pixsize[0]
+ xmax = origin[0] + (-0.5 * shape[0] + j + 1) * pixsize[0]
+ xcen = 0.5 * (xmin + xmax)
+ for k in range(rect_min[1], rect_max[1]):
+ ymin = origin[1] + (+0.5 * shape[1] - k - 1) * pixsize[1]
+ ymax = origin[1] + (+0.5 * shape[1] - k) * pixsize[1]
+ ycen = 0.5 * (ymin + ymax)
+ scale = det_dist / np.linalg.norm( src - np.array((xcen,ycen)), ord=2 )
+ w = intersect_ray_rect(edge1, edge2, xmin, xmax, ymin, ymax)
+ l += w * scale
+ a[i] = l
+ a = a.reshape(astra.functions.geom_size(pg))
+ if not np.all(np.isfinite(a)):
+ raise RuntimeError("Invalid value in reference sinogram")
+ x = np.max(np.abs(sinogram-a))
+ TOL = 8e-3
+ if DISPLAY and x > TOL:
+ display_mismatch(data, sinogram, a)
+ self.assertFalse(x > TOL)
elif proj_type == 'strip':
a = np.zeros(np.prod(astra.functions.geom_size(pg)), dtype=np.float32)
for i, (center, edge1, edge2) in enumerate(gen_lines(pg)):
a[i] = intersect_ray_rect(edge1, edge2, xmin, xmax, ymin, ymax)
-
a = a.reshape(astra.functions.geom_size(pg))
if not np.all(np.isfinite(a)):
raise RuntimeError("Invalid value in reference sinogram")