-
Notifications
You must be signed in to change notification settings - Fork 100
Description
Originally posted by @Dimitra-Kyriakopoulou in #1631 (comment)_
In addition, I would like to express a few thoughts that came to my mind regarding the 90 degree rotation and z-flip issues, which can appear as the current left–right (x) problem:
A) src/IO/InterfilePDFSHeaderSPECT.cxx
num_segments = 1;
num_views = -1;
add_key("number of projections", &num_views);
start_angle = 0;
add_key("start angle", &start_angle);
direction_of_rotation = "cw";
add_key("direction of rotation", &direction_of_rotation);
extent_of_rotation = double_value_not_set;
add_key("extent of rotation", &extent_of_rotation);
Different datasets may use different 0° definitions and CW/CCW sense. That creates a global rotation (often ~90°) which can be misread as “left/right” mismatch.
Hence, right after the add_key(...) calls, we must normalize angles to one convention (0°=+x, CCW, positive increment). If already canonical, it’s a no-op; otherwise it corrects once and removes rotation ambiguity.
B) src/recon_buildblock/ProjMatrixByBinSPECTUB.cxx
vol.Xcmd2 = vol.Ncold2 * vol.szcm; // half-size x (cm)
vol.Ycmd2 = vol.Nrowd2 * vol.szcm; // half-size y (cm)
vol.Zcmd2 = vol.Nslid2 * vol.thcm; // half-size z (cm)
vol.x0 = ((float)0.5 - vol.Ncold2) * vol.szcm; // x of first voxel
vol.y0 = ((float)0.5 - vol.Nrowd2) * vol.szcm; // y of first voxel
vol.z0 = ((float)0.5 - vol.Nslid2) * vol.thcm; // z of first voxel
Some images arrive with opposite z slice order . That appears as a z-mirror during comparison and can confuse left/right assessments.
At image load (or just before the projector binds the VoxelsOnCartesianGrid), we can add a one-time z-order normalization that reorders slices to canonical +z.
C) src/recon_buildblock/SPECTUB_Tools.cxx
const float deg = wmh.prj.ang0 + (float)i * wmh.prj.incr; // angle (deg)
ang[i].cos = cos(deg * dg2rd);
ang[i].sin = sin(deg * dg2rd);
// reduced angle to 0..45°, track quadrant
float angR = fabs(deg);
int quad = (int)floor(angR / 90.f);
angR = fabs(angR - 90.f * quad);
if (angR > 45.f) angR = fabs(90.f - angR);
// detector-line direction and first-bin position
ang[i].incx = wmh.prj.szcm * ang[i].cos; // Δx per bin
ang[i].incy = wmh.prj.szcm * ang[i].sin; // Δy per bin
ang[i].xbin0 = -ang[i].Rrad * ang[i].sin - wmh.prj.lngcmd2 * ang[i].cos;
ang[i].ybin0 = ang[i].Rrad * ang[i].cos - wmh.prj.lngcmd2 * ang[i].sin;
If (A) isn’t normalized, deg carries incompatible angle conventions, making the geometry rotated (which may be perceived as left/right mismatch).
We must ensure deg = ang0 + i*incr is exactly the canonical CCW, 0°=+x delivered by (A):
- If A is in place → no code change usually needed in C.
- If any extra CW/CCW or handedness reinterpretation exists here → remove it so C simply uses the canonical angles.
D) src/recon_buildblock/SPECTUB_Weight3d.cxx
float ux = bin.x - vox.x;
float uy = bin.y - vox.y;
float uz = bin.z - vox.z;
int signx = SIGN(ux);
int signy = SIGN(uy);
int signz = SIGN(uz);
// ... next-plane distances and stepping ...
dx = (next_x - vox.x) / (ux + EPSILON);
dy = (next_y - vox.y) / (uy + EPSILON);
dz = (next_z - vox.z) / (uz + EPSILON);
If z-order is normalized once at (B), D is automatically correct for all cases.
_Origin