r140: *** empty log message ***
[ctsim.git] / libctsim / backprojectors.cpp
1 /*****************************************************************************
2 ** FILE IDENTIFICATION
3 **
4 **   Name:         backprojectors.cpp         Classes for backprojection
5 **   Programmer:   Kevin Rosenberg
6 **   Date Started: June 2000
7 **
8 **  This is part of the CTSim program
9 **  Copyright (C) 1983-2000 Kevin Rosenberg
10 **
11 **  $Id: backprojectors.cpp,v 1.6 2000/07/09 08:16:17 kevin Exp $
12 **
13 **  This program is free software; you can redistribute it and/or modify
14 **  it under the terms of the GNU General Public License (version 2) as
15 **  published by the Free Software Foundation.
16 **
17 **  This program is distributed in the hope that it will be useful,
18 **  but WITHOUT ANY WARRANTY; without even the implied warranty of
19 **  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20 **  GNU General Public License for more details.
21 **
22 **  You should have received a copy of the GNU General Public License
23 **  along with this program; if not, write to the Free Software
24 **  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25 ******************************************************************************/
26
27 #include "ct.h"
28
29 Backprojector::Backprojector (const Projections& proj, ImageFile& im, const char* const backprojName, const char* const interpName)
30 {
31   m_fail = false;
32   m_pBackprojectImplem = NULL;
33
34   initBackprojector (proj, im, backprojName, interpName);
35 }
36
37 void 
38 Backprojector::BackprojectView (const double* const viewData, const double viewAngle)
39 {
40   if (m_pBackprojectImplem)
41     m_pBackprojectImplem->BackprojectView (viewData, viewAngle);
42 }
43
44 Backprojector::~Backprojector (void)
45 {
46   delete m_pBackprojectImplem;
47 }
48
49 // FUNCTION IDENTIFICATION
50 //     Backproject* projector = selectBackprojector (...)
51 //
52 // PURPOSE
53 //     Selects a backprojector based on BackprojType 
54 //     and initializes the backprojector
55
56 bool
57 Backprojector::initBackprojector (const Projections& proj, ImageFile& im, const char* const backprojName, const char* const interpName)
58 {
59   m_nameBackproject = backprojName;
60   m_nameInterpolation = interpName;
61   m_pBackprojectImplem = NULL;
62   m_idBackproject = convertBackprojectNameToID (backprojName);
63   if (m_idBackproject == BPROJ_INVALID) {
64     m_fail = true;
65     m_failMessage = "Invalid backprojection name ";
66     m_failMessage += backprojName;
67   }
68   m_idInterpolation = convertInterpolationNameToID (interpName);
69   if (m_idInterpolation == INTERP_INVALID) {
70     m_fail = true;
71     m_failMessage = "Invalid interpolation name ";
72     m_failMessage += interpName;
73   }
74
75   if (m_fail || m_idBackproject == BPROJ_INVALID || m_idInterpolation == INTERP_INVALID) {
76     m_fail = true;
77     return false;
78   }
79
80   if (m_idBackproject == BPROJ_TRIG)
81     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectTrig (proj, im, m_idInterpolation));
82   else if (m_idBackproject == BPROJ_TABLE)
83     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectTable (proj, im, m_idInterpolation));
84   else if (m_idBackproject == BPROJ_DIFF)
85     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectDiff (proj, im, m_idInterpolation));
86   else if (m_idBackproject == BPROJ_DIFF2)
87     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectDiff2 (proj, im, m_idInterpolation));
88   else if (m_idBackproject == BPROJ_IDIFF2)
89     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectIntDiff2 (proj, im, m_idInterpolation));
90   else if (m_idBackproject == BPROJ_IDIFF3)
91     m_pBackprojectImplem = static_cast<Backproject*>(new BackprojectIntDiff3 (proj, im, m_idInterpolation));
92   else {
93     m_fail = true;
94     m_failMessage = "Unable to select a backprojection method [Backprojector::initBackprojector]";
95     return false;
96   }
97
98   return true;
99 }
100
101
102 const Backprojector::BackprojectID
103 Backprojector::convertBackprojectNameToID (const char* const backprojName)
104 {
105   BackprojectID backprojID = BPROJ_INVALID;
106
107   if (strcasecmp (backprojName, BPROJ_TRIG_STR) == 0)
108     backprojID = BPROJ_TRIG;
109   else if (strcasecmp (backprojName, BPROJ_TABLE_STR) == 0)
110     backprojID = BPROJ_TABLE;
111   else if (strcasecmp (backprojName, BPROJ_DIFF_STR) == 0)
112     backprojID = BPROJ_DIFF;
113   else if (strcasecmp (backprojName, BPROJ_DIFF2_STR) == 0)
114     backprojID = BPROJ_DIFF2;
115   else if (strcasecmp (backprojName, BPROJ_IDIFF2_STR) == 0)
116     backprojID = BPROJ_IDIFF2;
117   else if (strcasecmp (backprojName, BPROJ_IDIFF3_STR) == 0)
118     backprojID = BPROJ_IDIFF3;
119
120   return (backprojID);
121 }
122
123 const char*
124 Backprojector::convertBackprojectIDToName (const BackprojectID bprojID)
125 {
126   const char *bprojName = "";
127
128   if (bprojID == BPROJ_TRIG)
129     bprojName = BPROJ_TRIG_STR;
130   else if (bprojID == BPROJ_TABLE)
131     bprojName = BPROJ_TABLE_STR;
132   else if (bprojID == BPROJ_DIFF)
133     bprojName = BPROJ_DIFF_STR;
134   else if (bprojID == BPROJ_DIFF2)
135     bprojName = BPROJ_DIFF2_STR;
136   else if (bprojID == BPROJ_IDIFF2)
137     bprojName = BPROJ_IDIFF2_STR;
138   else if (bprojID == BPROJ_IDIFF3)
139     bprojName = BPROJ_IDIFF3_STR;
140
141   return (bprojName);
142 }
143
144
145
146 const Backprojector::InterpolationID
147 Backprojector::convertInterpolationNameToID (const char* const interpName)
148 {
149   InterpolationID interpID = INTERP_INVALID;
150
151   if (strcasecmp (interpName, INTERP_NEAREST_STR) == 0)
152     interpID = INTERP_NEAREST;
153   else if (strcasecmp (interpName, INTERP_LINEAR_STR) == 0)
154     interpID = INTERP_LINEAR;
155   else if (strcasecmp (interpName, INTERP_FREQ_PREINTERPOLATE_STR) == 0)
156     interpID = INTERP_FREQ_PREINTERPOLATE;
157 #if HAVE_BSPLINE_INTERP
158   else if (strcasecmp (interpName, INTERP_BSPLINE_STR) == 0)
159     interpID = INTERP_BSPLINE;
160 #endif
161
162   return (interpID);
163 }
164
165
166 /* NAME
167  *      name_of_interp                  Return name of interpolation method
168  *
169  * SYNOPSIS
170  *      name = name_of_interp (interp_type)
171  *      char *name                      Name of interpolation method
172  *      int interp_type                 Method of interpolation
173  *
174  * NOTES
175  *      Returns NULL if interp_type is invalid
176  */
177
178 const char*
179 Backprojector::convertInterpolationIDToName (const InterpolationID interpID)
180 {
181   if (interpID == INTERP_NEAREST)
182     return (INTERP_NEAREST_STR);
183   else if (interpID == INTERP_LINEAR)
184     return (INTERP_LINEAR_STR);
185   else if (interpID == INTERP_FREQ_PREINTERPOLATE)
186     return (INTERP_FREQ_PREINTERPOLATE_STR);
187 #if HAVE_BSPLINE_INTERP
188   else if (interpID == INTERP_BSPLINE)
189     return (INTERP_BSPLINE_STR);
190 #endif
191   else
192     return ("");
193 }
194
195
196 // CLASS IDENTICATION
197 //   Backproject
198 //
199 // PURPOSE
200 //   Pure virtual base class for all backprojectors.
201
202 Backproject::Backproject (const Projections& proj, ImageFile& im, const Backprojector::InterpolationID interpType)
203   : proj(proj), im(im), interpType(interpType)
204 {
205   detInc = proj.detInc();
206   nDet = proj.nDet();
207   iDetCenter = (nDet - 1) / 2;  // index refering to L=0 projection 
208   rotInc = proj.rotInc();
209
210   v = im.getArray();
211   nx = im.nx();
212   ny = im.ny();
213   im.arrayDataClear();
214
215   xMin = -proj.phmLen() / 2;      // Retangular coords of phantom
216   xMax = xMin + proj.phmLen();
217   yMin = -proj.phmLen() / 2;
218   yMax = yMin + proj.phmLen();
219
220   xInc = (xMax - xMin) / nx;    // size of cells
221   yInc = (yMax - yMin) / ny;
222
223   if (interpType != Backprojector::INTERP_NEAREST && interpType != Backprojector::INTERP_LINEAR)
224     sys_error (ERR_WARNING, "Illegal interpType %d [selectBackprojector]", interpType);
225 }
226
227 Backproject::~Backproject (void)
228 {}
229
230 void
231 Backproject::ScaleImageByRotIncrement (void)
232 {
233   for (int ix = 0; ix < nx; ix++)
234     for (int iy = 0; iy < ny; iy++)
235       v[ix][iy] *= rotInc;
236 }
237
238 void Backproject::errorIndexOutsideDetector (int ix, int iy, double theta, double r, double phi, double L, int iDetPos)
239 {
240     printf ("r=%f, phi=%f\n", r, phi);
241     errorIndexOutsideDetector (ix, iy, theta, L, iDetPos);
242 }
243
244 void Backproject::errorIndexOutsideDetector (int ix, int iy, double theta, double L, int iDetPos)
245 {
246     printf ("ix=%d, iy=%d\n", ix, iy);
247     printf ("theta=%f, L=%f, detInc=%f\n", theta, L, detInc);
248     printf ("proj.ndet=%d, proj.detInc=%.4f, iDetCenter=%d\n", nDet, detInc, iDetCenter);
249     printf ("xMin=%15.8f, xMax=%15.8f, xInc=%15.8f\n", xMin, xMax, xInc);
250     printf ("yMin=%15.8f, yMax=%15.8f, yInc=%15.8f\n", yMin, yMax, yInc);
251     sys_error (ERR_WARNING, "iDetPos index outside bounds: %d [backprojector]", iDetPos);
252 }
253
254
255 // CLASS IDENTICATION
256 //   BackprojectTrig
257 //
258 // PURPOSE
259 //   Uses trigometric functions at each point in image for backprojection.
260
261 void
262 BackprojectTrig::BackprojectView (const double* const filteredProj, const double view_angle)
263 {
264   double theta = HALFPI + view_angle;   // Add PI/2 to get perpendicular angle to detector      
265   int ix, iy;
266   double x, y;                  // Rectang coords of center of pixel 
267
268   for (x = xMin + xInc / 2, ix = 0; ix < nx; x += xInc, ix++)
269     for (y = yMin + yInc / 2, iy = 0; iy < ny; y += yInc, iy++) {
270       double r = sqrt (x * x + y * y);   // distance of cell from center
271       double phi = atan2 (y, x);         // angle of cell from center
272       double L = r * cos (theta - phi);  // position on detector
273
274       if (interpType == Backprojector::INTERP_NEAREST) {
275         int iDetPos = iDetCenter + nearest<int> (L / detInc); // calc'd index in the filter raysum array
276
277         if (iDetPos < 0 || iDetPos >= nDet)     // check for impossible: index outside of raysum pos 
278             errorIndexOutsideDetector (ix, iy, theta, r, phi, L, iDetPos);
279         else
280           v[ix][iy] += rotInc * filteredProj[iDetPos];
281       } else if (interpType == Backprojector::INTERP_LINEAR) {
282           double p = L / detInc;        // position along detector
283           double pFloor = floor (p);
284           int iDetPos = iDetCenter + static_cast<int>(pFloor);
285           double frac = p - pFloor;     // fraction distance from det
286           if (iDetPos < 0 || iDetPos >= nDet - 1)       // check for impossible: index outside of raysum pos 
287             errorIndexOutsideDetector (ix, iy, theta, r, phi, L, iDetPos);
288           else
289             v[ix][iy] += rotInc * ((1-frac) * filteredProj[iDetPos] + frac * filteredProj[iDetPos+1]);
290       }
291     }
292 }  
293
294
295 // CLASS IDENTICATION
296 //   BackprojectTable
297 //
298 // PURPOSE
299 //   Precalculates trigometric function value for each point in image for backprojection.
300
301 BackprojectTable::BackprojectTable (const Projections& proj, ImageFile& im, Backprojector::InterpolationID interpType)
302   : Backproject::Backproject (proj, im, interpType)
303 {
304   arrayR.initSetSize (nx, ny);
305   arrayPhi.initSetSize (nx, ny);
306   r = arrayR.getArray();
307   phi = arrayPhi.getArray();
308
309   double x, y;                  // Rectang coords of center of pixel 
310   int ix, iy;
311   for (x = xMin + xInc / 2, ix = 0; ix < nx; x += xInc, ix++)
312     for (y = yMin + yInc / 2, iy = 0; iy < ny; y += yInc, iy++) {
313       r[ix][iy] = sqrt (x * x + y * y);
314       phi[ix][iy] = atan2 (y, x);
315     }
316 }
317
318 BackprojectTable::~BackprojectTable (void)
319 {
320   ScaleImageByRotIncrement();
321 }
322
323 void
324 BackprojectTable::BackprojectView (const double* const filteredProj, const double view_angle)
325 {
326   double theta = HALFPI + view_angle;  // add half PI to view angle to get perpendicular theta angle
327
328   for (int ix = 0; ix < nx; ix++) {
329     ImageFileColumn pImCol = v[ix];
330
331     for (int iy = 0; iy < ny; iy++) {
332       double L = r[ix][iy] * cos (theta - phi[ix][iy]);
333
334       if (interpType == Backprojector::INTERP_NEAREST) {
335         int iDetPos = iDetCenter + nearest<int>(L / detInc);    // calc index in the filtered raysum vector 
336
337         if (iDetPos < 0 || iDetPos >= nDet)     // check for impossible: index outside of raysum pos 
338           errorIndexOutsideDetector (ix, iy, theta, r[ix][iy], phi[ix][iy], L, iDetPos);
339         else
340           pImCol[iy] += filteredProj[iDetPos];
341       } else if (interpType == Backprojector::INTERP_LINEAR) {
342         double dPos = L / detInc;               // position along detector 
343         double dPosFloor = floor (dPos);
344         int iDetPos = iDetCenter + static_cast<int>(dPosFloor);
345         double frac = dPos - dPosFloor; // fraction distance from det 
346         if (iDetPos < 0 || iDetPos >= nDet - 1)
347             errorIndexOutsideDetector (ix, iy, theta, r[ix][iy], phi[ix][iy], L, iDetPos);
348         else
349           pImCol[iy] += ((1-frac) * filteredProj[iDetPos] + frac * filteredProj[iDetPos+1]);
350       }
351     }   // end for y 
352   }     // end for x 
353 }
354
355
356 // CLASS IDENTICATION
357 //   BackprojectDiff
358 //
359 // PURPOSE
360 //   Backprojects by precalculating the change in L position for each x & y step in the image.
361 //   Iterates in x & y direction by adding difference in L position
362
363 BackprojectDiff::BackprojectDiff (const Projections& proj, ImageFile& im, Backprojector::InterpolationID interpType)
364   :  Backproject::Backproject (proj, im, interpType)
365 {
366   // calculate center of first pixel v[0][0] 
367   double x = xMin + xInc / 2;
368   double y = yMin + yInc / 2;
369   start_r = sqrt (x * x + y * y);
370   start_phi = atan2 (y, x);
371
372   im.arrayDataClear();
373 }
374
375 BackprojectDiff::~BackprojectDiff()
376 {
377   ScaleImageByRotIncrement();
378 }
379
380 void
381 BackprojectDiff::BackprojectView (const double* const filteredProj, const double view_angle)
382 {
383   double theta = - view_angle;  // add half PI to view angle to get perpendicular theta angle
384   double det_dx = xInc * sin (theta);
385   double det_dy = yInc * cos (theta);
386   double lColStart = start_r * cos (theta - start_phi);  // calculate L for first point in image
387         
388   for (int ix = 0; ix < nx; ix++, lColStart += det_dx) {
389     double curDetPos = lColStart;
390     ImageFileColumn pImCol = v[ix];
391   
392     for (int iy = 0; iy < ny; iy++, curDetPos += det_dy) {
393 #ifdef DEBUG
394       printf ("[%2d,%2d]:  %8.5lf  ", ix, iy, curDetPos);
395 #endif
396       if (interpType == Backprojector::INTERP_NEAREST) {
397         int iDetPos = iDetCenter + nearest<int>(curDetPos / detInc);    // calc index in the filtered raysum vector 
398
399         if (iDetPos < 0 || iDetPos >= nDet)     // check for impossible: index outside of raysum pos 
400             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
401         else
402           pImCol[iy] += filteredProj[iDetPos];
403       } else if (interpType == Backprojector::INTERP_LINEAR) {
404         double detPos = curDetPos / detInc;             // position along detector 
405         double detPosFloor = floor (detPos);
406         int iDetPos = iDetCenter + static_cast<int>(detPosFloor);
407         double frac = detPos - detPosFloor;     // fraction distance from det 
408         if (iDetPos < 0 || iDetPos >= nDet - 1)
409             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
410         else
411           pImCol[iy] += ((1-frac) * filteredProj[iDetPos] + frac * filteredProj[iDetPos+1]);
412       }
413     }   // end for y 
414   }     // end for x 
415 }
416
417
418 // CLASS IDENTICATION
419 //   BackprojectDiff2
420 //
421 // PURPOSE
422 //   Optimized version of BackprojectDiff
423
424 void
425 BackprojectDiff2::BackprojectView (const double* const filteredProj, const double view_angle)
426 {
427   double theta = - view_angle;  // add half PI to view angle to get perpendicular theta angle
428
429   // Distance betw. detectors for an angle given in units of detectors 
430   double det_dx = xInc * sin (theta) / detInc;
431   double det_dy = yInc * cos (theta) / detInc;
432
433   // calculate detPosition for first point in image (ix=0, iy=0) 
434   double detPosColStart = start_r * cos (theta - start_phi) / detInc;
435         
436 #ifdef DEBUG
437   printf ("start_r=%8.5f, start_phi=%8.5f, rotInc=%8.5f\n", start_r, start_phi, rotInc);
438 #endif
439   for (int ix = 0; ix < nx; ix++, detPosColStart += det_dx) {
440     double curDetPos = detPosColStart;
441     ImageFileColumn pImCol = v[ix];
442
443     for (int iy = 0; iy < ny; iy++, curDetPos += det_dy) {
444 #ifdef DEBUG
445       printf ("[%2d,%2d]: %8.5f %8.5f\n", ix, iy, curDetPos, filteredProj[iDetCenter + nearest<int>(L))]);
446 #endif
447       if (interpType == Backprojector::INTERP_NEAREST) {
448         int iDetPos = iDetCenter + nearest<int> (curDetPos);    // calc index in the filtered raysum vector 
449         
450         if (iDetPos < 0 || iDetPos >= nDet)     // check for impossible: index outside of raysum pos 
451             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
452         else
453           *pImCol++ += filteredProj[iDetPos];
454       } else if (interpType == Backprojector::INTERP_LINEAR) {
455         double detPosFloor = floor (curDetPos);
456         int iDetPos = iDetCenter + static_cast<int>(detPosFloor);
457         double frac = curDetPos - detPosFloor;  // fraction distance from det 
458         if (iDetPos < 0 || iDetPos >= nDet - 1)
459             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
460         else
461           *pImCol++ += ((1-frac) * filteredProj[iDetPos] + frac * filteredProj[iDetPos+1]);
462       }
463     }   // end for y
464   }     // end for x
465 }
466
467 // CLASS IDENTICATION
468 //   BackprojectIntDiff2
469 //
470 // PURPOSE
471 //   Integer version of BackprojectDiff2
472
473 void
474 BackprojectIntDiff2::BackprojectView (const double* const filteredProj, const double view_angle)
475 {
476   double theta = - view_angle;  // add half PI to view angle to get perpendicular theta angle
477
478   static const kint32 scale = 1 << 16;
479   static const double dScale = scale;
480   static const kint32 halfScale = scale / 2;
481
482   const kint32 det_dx = nearest<kint32> (xInc * sin (theta) / detInc * scale);
483   const kint32 det_dy = nearest<kint32> (yInc * cos (theta) / detInc * scale);
484
485   // calculate L for first point in image (0, 0) 
486   kint32 detPosColStart = nearest<kint32> (start_r * cos (theta - start_phi) / detInc * scale);
487         
488   for (int ix = 0; ix < nx; ix++, detPosColStart += det_dx) {
489     kint32 curDetPos = detPosColStart;
490     ImageFileColumn pImCol = v[ix];
491
492     for (int iy = 0; iy < ny; iy++, curDetPos += det_dy) {
493       if (interpType == Backprojector::INTERP_NEAREST) {
494         int detPosNearest = (curDetPos >= 0 ? ((curDetPos + halfScale) / scale) : ((curDetPos - halfScale) / scale));
495         int iDetPos = iDetCenter + detPosNearest;       // calc index in the filtered raysum vector 
496
497         if (iDetPos < 0 || iDetPos >= nDet)  // check for impossible: index outside of raysum pos 
498             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
499         else
500           *pImCol++ += filteredProj[iDetPos];
501       } else if (interpType == Backprojector::INTERP_LINEAR) {
502         kint32 detPosFloor = curDetPos / scale;
503         kint32 detPosRemainder = curDetPos % scale;
504         if (detPosRemainder < 0) {
505           detPosFloor--;
506           detPosRemainder += scale;
507         }
508         int iDetPos = iDetCenter + detPosFloor;
509         double frac = detPosRemainder / dScale;
510         if (iDetPos < 0 || iDetPos >= nDet - 1)
511             errorIndexOutsideDetector (ix, iy, theta, curDetPos, iDetPos);
512         else
513           *pImCol++ += ((1.-frac) * filteredProj[iDetPos] + frac * filteredProj[iDetPos+1]);
514       }
515     }   // end for y
516   }     // end for x
517 }
518
519 // CLASS IDENTICATION
520 //   BackprojectIntDiff3
521 //
522 // PURPOSE
523 //   Highly optimized version of BackprojectIntDiff2
524
525 void
526 BackprojectIntDiff3::BackprojectView (const double* const filteredProj, const double view_angle)
527 {
528   double theta = - view_angle;  // add half PI to view angle to get perpendicular theta angle
529   static const int scaleShift = 16;
530   static const kint32 scale = (1 << scaleShift);
531   static const kint32 scaleBitmask = scale - 1;
532   static const double dScale = scale;
533   static const kint32 halfScale = scale / 2;
534   static const double dInvScale = 1. / scale;
535
536   const kint32 det_dx = nearest<kint32> (xInc * sin (theta) / detInc * scale);
537   const kint32 det_dy = nearest<kint32> (yInc * cos (theta) / detInc * scale);
538
539   // calculate L for first point in image (0, 0) 
540   kint32 detPosColStart = nearest<kint32> ((start_r * cos (theta - start_phi) / detInc + iDetCenter) * scale);
541         
542   for (int ix = 0; ix < nx; ix++, detPosColStart += det_dx) {
543     kint32 curDetPos = detPosColStart;
544     ImageFileColumn pImCol = v[ix];
545
546     if (interpType == Backprojector::INTERP_NEAREST) {
547       for (int iy = 0; iy < ny; iy++, curDetPos += det_dy) {
548         int iDetPos = (curDetPos + halfScale) >> 16;
549         assert(iDetPos >= 0 && iDetPos < nDet);
550         *pImCol++ += filteredProj[iDetPos];
551       } // end for iy
552     } else if (interpType == Backprojector::INTERP_LINEAR) {
553       for (int iy = 0; iy < ny; iy++, curDetPos += det_dy) {
554         kint32 iDetPos = curDetPos >> scaleShift;
555         kint32 detRemainder = curDetPos & scaleBitmask;
556 #if 0
557         double frac = detRemainder * (1. / 65536.);
558         assert(iDetPos >= 0 && iDetPos < nDet - 1);
559         *pImCol++ += ((1.-frac) * filteredProj[iDetPos]) + (frac * filteredProj[iDetPos+1]);
560 #else
561         assert(iDetPos >= 0 && iDetPos < nDet - 1);
562         const double* const detPointer = &filteredProj[iDetPos];
563         *pImCol++ += (((scale-detRemainder) * *detPointer) + (detRemainder * *(detPointer+1))) * dInvScale;
564 #endif
565       } // end for iy
566     } //end linear
567   } // end for ix
568 }