CASToR  1.0
Tomographic Reconstruction (PET/SPECT)
iProjectorJoseph.cc
Go to the documentation of this file.
00001 
00002 /*
00003   Implementation of class iProjectorJoseph
00004 
00005   - separators: done
00006   - doxygen: done
00007   - default initialization: done
00008   - CASTOR_DEBUG: 
00009   - CASTOR_VERBOSE: 
00010 */
00011 
00018 #include "iProjectorJoseph.hh"
00019 #include "sOutputManager.hh"
00020 
00021 // =====================================================================
00022 // ---------------------------------------------------------------------
00023 // ---------------------------------------------------------------------
00024 // =====================================================================
00025 
00026 iProjectorJoseph::iProjectorJoseph() : vProjector()
00027 {
00028   // This projector is not compatible with SPECT attenuation correction because
00029   // the voxels contributing to the line are not strictly ordered with respect to
00030   // their distance to point2 (due to interpolations at each plane crossed)
00031   m_compatibleWithSPECTAttenuationCorrection = false;
00032 }
00033 
00034 // =====================================================================
00035 // ---------------------------------------------------------------------
00036 // ---------------------------------------------------------------------
00037 // =====================================================================
00038 
00039 iProjectorJoseph::~iProjectorJoseph()
00040 {
00041   if ( mp_boundariesX )
00042   {
00043     delete[] mp_boundariesX;
00044     mp_boundariesX = nullptr;
00045   }
00046 
00047   if ( mp_boundariesY )
00048   {
00049     delete[] mp_boundariesY;
00050     mp_boundariesY = nullptr;
00051   }
00052 
00053   if ( mp_boundariesZ )
00054   {
00055     delete[] mp_boundariesZ;
00056     mp_boundariesZ = nullptr;
00057   }
00058 }
00059 
00060 // =====================================================================
00061 // ---------------------------------------------------------------------
00062 // ---------------------------------------------------------------------
00063 // =====================================================================
00064 
00065 int iProjectorJoseph::ReadConfigurationFile(const string& a_configurationFile)
00066 {
00067   // No options for joseph
00068   ;
00069   // Normal end
00070   return 0;
00071 }
00072 
00073 // =====================================================================
00074 // ---------------------------------------------------------------------
00075 // ---------------------------------------------------------------------
00076 // =====================================================================
00077 
00078 int iProjectorJoseph::ReadOptionsList(const string& a_optionsList)
00079 {
00080   // No options for joseph
00081   ;
00082   // Normal end
00083   return 0;
00084 }
00085 
00086 // =====================================================================
00087 // ---------------------------------------------------------------------
00088 // ---------------------------------------------------------------------
00089 // =====================================================================
00090 
00091 void iProjectorJoseph::ShowHelpSpecific()
00092 {
00093   cout << "This projector is a line projector that uses linear interpolation between pixels." << endl;
00094   cout << "It is implemented from the following published paper:" << endl;
00095   cout << "P. M. Joseph, \"An improved algorithm for reprojecting rays through pixel images\", IEEE Trans. Med. Imaging, vol. 1, pp. 192-6, 1982." << endl;
00096 }
00097 
00098 // =====================================================================
00099 // ---------------------------------------------------------------------
00100 // ---------------------------------------------------------------------
00101 // =====================================================================
00102 
00103 int iProjectorJoseph::CheckSpecificParameters()
00104 {
00105   // Nothing to check for this projector
00106   ;
00107   // Normal end
00108   return 0;
00109 }
00110 
00111 // =====================================================================
00112 // ---------------------------------------------------------------------
00113 // ---------------------------------------------------------------------
00114 // =====================================================================
00115 
00116 int iProjectorJoseph::InitializeSpecific()
00117 {
00118   // Verbose
00119   if (m_verbose>=2) Cout("iProjectorJoseph::InitializeSpecific() -> Use Joseph projector" << endl);
00120   // Allocate and compute boundaries
00121   mp_boundariesX = new FLTNB[ mp_nbVox[ 0 ] ];
00122   for( int i = 0; i < mp_nbVox[ 0 ]; ++i ) mp_boundariesX[ i ] = -mp_halfFOV[ 0 ] + i * mp_sizeVox[ 0 ];
00123   mp_boundariesY = new FLTNB[ mp_nbVox[ 1 ] ];
00124   for( int i = 0; i < mp_nbVox[ 1 ]; ++i ) mp_boundariesY[ i ] = -mp_halfFOV[ 1 ] + i * mp_sizeVox[ 1 ];
00125   mp_boundariesZ = new FLTNB[ mp_nbVox[ 2 ] ];
00126   for( int i = 0; i < mp_nbVox[ 2 ]; ++i ) mp_boundariesZ[ i ] = -mp_halfFOV[ 2 ] + i * mp_sizeVox[ 2 ];
00127   // Normal end
00128   return 0;
00129 }
00130 
00131 // =====================================================================
00132 // ---------------------------------------------------------------------
00133 // ---------------------------------------------------------------------
00134 // =====================================================================
00135 
00136 INTNB iProjectorJoseph::EstimateMaxNumberOfVoxelsPerLine()
00137 {
00138   // Find the maximum number of voxels along a given dimension
00139   INTNB max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxX();
00140   if (mp_ImageDimensionsAndQuantification->GetNbVoxY()>max_nb_voxels_in_dimension) max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxY();
00141   if (mp_ImageDimensionsAndQuantification->GetNbVoxZ()>max_nb_voxels_in_dimension) max_nb_voxels_in_dimension = mp_ImageDimensionsAndQuantification->GetNbVoxZ();
00142   // We should have at most 4 voxels in a given plane, so multiply by 4
00143   max_nb_voxels_in_dimension *= 4;
00144   // Return the value
00145   return max_nb_voxels_in_dimension;
00146 }
00147 
00148 // =====================================================================
00149 // ---------------------------------------------------------------------
00150 // ---------------------------------------------------------------------
00151 // =====================================================================
00152 
00153 int iProjectorJoseph::ProjectWithoutTOF(int a_direction, oProjectionLine* ap_ProjectionLine )
00154 {
00155   #ifdef CASTOR_DEBUG
00156   if (!m_initialized)
00157   {
00158     Cerr("***** iProjectorJoseph::ProjectWithoutTOF() -> Called while not initialized !" << endl);
00159     Exit(EXIT_DEBUG);
00160   }
00161   #endif
00162 
00163   #ifdef CASTOR_VERBOSE
00164   if (m_verbose>=10)
00165   {
00166     string direction = "";
00167     if (a_direction==FORWARD) direction = "forward";
00168     else direction = "backward";
00169     Cout("iProjectorJoseph::Project without TOF -> Project line '" << ap_ProjectionLine << "' in " << direction << " direction" << endl);
00170   }
00171   #endif
00172 
00173   // Simpler way now, hopefully it works
00174   FLTNB* event1 = ap_ProjectionLine->GetPosition1();
00175   FLTNB* event2 = ap_ProjectionLine->GetPosition2();
00176 
00177   // **************************************
00178   // STEP 1: LOR length calculation
00179   // **************************************
00180 
00181   // Distance between point event1 and event2
00182   FLTNB const dX21( event2[ 0 ] - event1[ 0 ] );
00183   FLTNB const dY21( event2[ 1 ] - event1[ 1 ] );
00184   FLTNB const dZ21( event2[ 2 ] - event1[ 2 ] );
00185 
00186   // Square of distance
00187   FLTNB const dX21_2( dX21 * dX21 );
00188   FLTNB const dY21_2( dY21 * dY21 );
00189   FLTNB const dZ21_2( dZ21 * dZ21 );
00190 
00191   // Size of the voxels
00192   FLTNB const szImg_X( mp_sizeVox[ 0 ] );
00193   FLTNB const szImg_Y( mp_sizeVox[ 1 ] );
00194   FLTNB const szImg_Z( mp_sizeVox[ 2 ] );
00195 
00196   // Get the number of the planes
00197   INTNB const nPlane_X( mp_nbVox[ 0 ] );
00198   INTNB const nPlane_Y( mp_nbVox[ 1 ] );
00199   INTNB const nPlane_Z( mp_nbVox[ 2 ] );
00200   INTNB const nPlane_XY( nPlane_X * nPlane_Y );
00201 
00202   // Coordinates of the first and last planes
00203   FLTNB const xPlane_0 = -mp_halfFOV[ 0 ];
00204   FLTNB const yPlane_0 = -mp_halfFOV[ 1 ];
00205   FLTNB const zPlane_0 = -mp_halfFOV[ 2 ];
00206   FLTNB const xPlane_N = mp_halfFOV[ 0 ];
00207   FLTNB const yPlane_N = mp_halfFOV[ 1 ];
00208   FLTNB const zPlane_N = mp_halfFOV[ 2 ];
00209 
00210   // Parameters for the index
00211   INTNB index_x( 0 );
00212   INTNB index_y( 0 );
00213   INTNB index_z( 0 );
00214 
00215   // Parameter for the intersection point in each axis
00216   // X
00217   FLTNB intersection_x( event1[ 0 ] < xPlane_0 ?
00218     xPlane_0 + szImg_X / ((FLTNB)2.0) : xPlane_N - szImg_X / ((FLTNB)2.0) );
00219 
00220   // Y
00221   FLTNB intersection_y( event1[ 1 ] < yPlane_0 ?
00222     yPlane_0 + szImg_Y / ((FLTNB)2.0) : yPlane_N - szImg_Y / ((FLTNB)2.0) );
00223 
00224   // Z
00225   FLTNB intersection_z( event1[ 2 ] < zPlane_0 ?
00226     zPlane_0 + szImg_Z / ((FLTNB)2.0) : zPlane_N - szImg_Z / ((FLTNB)2.0) );
00227 
00228   // Min. Max. coordinate for histo.
00229   FLTNB const xPlane_0_min = xPlane_0 + szImg_X / ((FLTNB)2.0);
00230   FLTNB const yPlane_0_min = yPlane_0 + szImg_Y / ((FLTNB)2.0);
00231   FLTNB const zPlane_0_min = zPlane_0 + szImg_Z / ((FLTNB)2.0);
00232 
00233   // Min. Max security. Do not take the last slice
00234   FLTNB const xPlane_0_min_safety = xPlane_0 + ( szImg_X / ((FLTNB)2.0) ) + szImg_X;
00235   FLTNB const yPlane_0_min_safety = yPlane_0 + ( szImg_Y / ((FLTNB)2.0) ) + szImg_Y;
00236   FLTNB const zPlane_0_min_safety = zPlane_0 + ( szImg_Z / ((FLTNB)2.0) ) + szImg_Z;
00237   FLTNB const xPlane_N_max_safety = xPlane_N - ( szImg_X / ((FLTNB)2.0) ) - szImg_X;
00238   FLTNB const yPlane_N_max_safety = yPlane_N - ( szImg_Y / ((FLTNB)2.0) ) - szImg_Y;
00239   FLTNB const zPlane_N_max_safety = zPlane_N - ( szImg_Z / ((FLTNB)2.0) ) - szImg_Z;
00240 
00241   // Incrementation of the plane
00242   FLTNB const increment[] = {
00243     event1[ 0 ] < xPlane_0 ? szImg_X : -szImg_X,
00244     event1[ 1 ] < yPlane_0 ? szImg_Y : -szImg_Y,
00245     event1[ 2 ] < zPlane_0 ? szImg_Z : -szImg_Z
00246   };
00247 
00248   INTNB const increment_index[] = {
00249     event1[ 0 ] < xPlane_0 ? 1 : -1,
00250     event1[ 1 ] < yPlane_0 ? 1 : -1,
00251     event1[ 2 ] < zPlane_0 ? 1 : -1
00252   };
00253 
00254   INTNB const first_index[] = {
00255     event1[ 0 ] < xPlane_0 ? 0 : nPlane_X - 1,
00256     event1[ 1 ] < yPlane_0 ? 0 : nPlane_Y - 1,
00257     event1[ 2 ] < zPlane_0 ? 0 : nPlane_Z - 1
00258   };
00259 
00260   // Values of interpolation
00261   FLTNB x1( 0.0 ); FLTNB x2( 0.0 );
00262   FLTNB y1( 0.0 ); FLTNB y2( 0.0 );
00263   FLTNB z1( 0.0 ); FLTNB z2( 0.0 );
00264 
00265   // Find the principal direction
00266   // X direction
00267   if( ::fabs( dX21 ) >= ::fabs( dY21 ) && ::fabs( dX21 ) >= ::fabs( dZ21 ) )
00268   {
00269     // Compute the weight to normalize the line
00270     FLTNB const factor( ::fabs( dX21 ) / ::sqrt( dX21_2 + dY21_2 + dZ21_2 ) );
00271     FLTNB const weight( szImg_X / factor );
00272 
00273     // Take the increment X
00274     FLTNB const incrementX = increment[ 0 ];
00275 
00276     // Compute first intersection in Y and Z
00277     FLTNB const p1X_IntersectionX1 = ( intersection_x - event1[ 0 ] );
00278     intersection_y = ( p1X_IntersectionX1 * dY21 / dX21 ) + event1[ 1 ];
00279     intersection_z = ( p1X_IntersectionX1 * dZ21 / dX21 ) + event1[ 2 ];
00280 
00281     // Compute the increment (next intersection minus current intersection)
00282     FLTNB const incrementY =
00283       ( ( intersection_x + incrementX - event1[ 0 ] ) * dY21 / dX21 )
00284       + event1[ 1 ] - intersection_y;
00285     FLTNB const incrementZ =
00286       ( ( intersection_x + incrementX - event1[ 0 ] ) * dZ21 / dX21 )
00287       + event1[ 2 ] - intersection_z;
00288 
00289     // Take first index for x
00290     index_x = first_index[ 0 ];
00291 
00292     // Loop over the Y-Z planes
00293     for( INTNB i = 0; i < nPlane_X; ++i )
00294     {
00295       // Check if intersection outside of the image space
00296       if( intersection_y < yPlane_0_min_safety
00297         || intersection_y >= yPlane_N_max_safety
00298         || intersection_z < zPlane_0_min_safety
00299         || intersection_z >= zPlane_N_max_safety )
00300       {
00301         index_x += increment_index[ 0 ];
00302         intersection_y += incrementY;
00303         intersection_z += incrementZ;
00304         continue;
00305       }
00306 
00307       // Find the index in the image
00308       index_y = (INTNB)( ( intersection_y - yPlane_0_min ) / szImg_Y );
00309       index_z = (INTNB)( ( intersection_z - zPlane_0_min ) / szImg_Z );
00310 
00311       // Compute distance between intersection point and Y and Z boundaries
00312       y2 = ::fabs( mp_boundariesY[ index_y ] + szImg_Y * ((FLTNB)0.5) - intersection_y )
00313         / szImg_Y;
00314       y1 = ((FLTNB)1.0) - y2;
00315       z2 = ::fabs( mp_boundariesZ[ index_z ] + szImg_Z * ((FLTNB)0.5) - intersection_z )
00316         / szImg_Z;
00317       z1 = ((FLTNB)1.0) - z2;
00318 
00319       INTNB index_final = index_x + index_y * nPlane_X + index_z * nPlane_XY;
00320       ap_ProjectionLine->AddVoxel(a_direction, index_final, ( y1 * z1 ) * weight);
00321       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_X, ( y2 * z1 ) * weight);
00322       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_XY, ( y1 * z2 ) * weight);
00323       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_X + nPlane_XY, ( y2 * z2 ) * weight);
00324 
00325       // Increment
00326       index_x += increment_index[ 0 ];
00327       intersection_y += incrementY;
00328       intersection_z += incrementZ;
00329     }
00330   } // Y direction
00331   else if( ::fabs( dY21 ) > ::fabs( dX21 ) && ::fabs( dY21 ) >= ::fabs( dZ21 ) )
00332   {
00333     // Compute the weight to normalize the line
00334     FLTNB const factor( ::fabs( dY21 ) / ::sqrt( dX21_2 + dY21_2 + dZ21_2 ) );
00335     FLTNB const weight( szImg_Y / factor );
00336 
00337     // Take the increment Y
00338     FLTNB const incrementY = increment[ 1 ];
00339 
00340     // Compute first intersection in X and Z
00341     FLTNB const p1Y_IntersectionY1 = ( intersection_y - event1[ 1 ] );
00342     intersection_x = ( p1Y_IntersectionY1 * dX21 / dY21 ) + event1[ 0 ];
00343     intersection_z = ( p1Y_IntersectionY1 * dZ21 / dY21 ) + event1[ 2 ];
00344 
00345     // Compute the increment (next intersection minus current intersection)
00346     FLTNB const incrementX =
00347       ( ( intersection_y + incrementY - event1[ 1 ] ) * dX21 / dY21 )
00348       + event1[ 0 ] - intersection_x;
00349     FLTNB const incrementZ =
00350       ( ( intersection_y + incrementY - event1[ 1 ] ) * dZ21 / dY21 )
00351       + event1[ 2 ] - intersection_z;
00352 
00353     // Take first index for y
00354     index_y = first_index[ 1 ];
00355 
00356     // Loop over the X-Z planes
00357     for( INTNB i = 0; i < nPlane_Y; ++i )
00358     {
00359       // Check if intersection outside of the image space
00360       if( intersection_x < xPlane_0_min_safety
00361         || intersection_x >= xPlane_N_max_safety
00362         || intersection_z < zPlane_0_min_safety
00363         || intersection_z >= zPlane_N_max_safety )
00364       {
00365         index_y += increment_index[ 1 ];
00366         intersection_x += incrementX;
00367         intersection_z += incrementZ;
00368         continue;
00369       }
00370 
00371       // Find the index in the image
00372       index_x = (INTNB)( ( intersection_x - xPlane_0_min ) / szImg_X );
00373       index_z = (INTNB)( ( intersection_z - zPlane_0_min ) / szImg_Z );
00374 
00375       // Compute distance between intersection point and Y and Z boundaries
00376       x2 = ::fabs( mp_boundariesX[ index_x ] + szImg_X * ((FLTNB)0.5) - intersection_x )
00377         / szImg_X;
00378       x1 = ((FLTNB)1.0) - x2;
00379       z2 = ::fabs( mp_boundariesZ[ index_z ] + szImg_Z * ((FLTNB)0.5) - intersection_z )
00380         / szImg_Z;
00381       z1 = ((FLTNB)1.0) - z2;
00382 
00383       uint32_t index_final = index_x + index_y * nPlane_X + index_z * nPlane_XY;
00384       ap_ProjectionLine->AddVoxel(a_direction, index_final, ( x1 * z1 ) * weight);
00385       ap_ProjectionLine->AddVoxel(a_direction, index_final + 1, ( x2 * z1 ) * weight);
00386       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_XY, ( x1 * z2 ) * weight);
00387       ap_ProjectionLine->AddVoxel(a_direction, index_final + 1 +  nPlane_XY, ( x2 * z2 ) * weight);
00388 
00389       // Increment
00390       index_y += increment_index[ 1 ];
00391       intersection_x += incrementX;
00392       intersection_z += incrementZ;
00393     }
00394   }
00395   else // Z direction
00396   {
00397     // Compute the weight to normalize the line
00398     FLTNB const factor( ::fabs( dZ21 ) / ::sqrt( dX21_2 + dY21_2 + dZ21_2 ) );
00399     FLTNB const weight( szImg_Z / factor );
00400 
00401     // Take the increment Z
00402     FLTNB const incrementZ = increment[ 2 ];
00403 
00404     // Compute first intersection in X and Y
00405     FLTNB const p1Z_IntersectionZ1 = ( intersection_z - event1[ 2 ] );
00406     intersection_y = ( p1Z_IntersectionZ1 * dY21 / dZ21 ) + event1[ 1 ];
00407     intersection_x = ( p1Z_IntersectionZ1 * dX21 / dZ21 ) + event1[ 0 ];
00408 
00409     // Compute the increment (next intersection minus current intersection)
00410     FLTNB const incrementY =
00411       ( ( intersection_z + incrementZ - event1[ 2 ] ) * dY21 / dZ21 )
00412       + event1[ 1 ] - intersection_y;
00413     FLTNB const incrementX =
00414       ( ( intersection_z + incrementZ - event1[ 2 ] ) * dX21 / dZ21 )
00415       + event1[ 0 ] - intersection_x;
00416 
00417     // Take first index for z
00418     index_z = first_index[ 2 ];
00419 
00420     // Loop over the Y-Z planes
00421     for( INTNB i = 0; i < nPlane_Z; ++i )
00422     {
00423       // Check if intersection outside of the image space
00424       if( intersection_y < yPlane_0_min_safety
00425         || intersection_y >= yPlane_N_max_safety
00426         || intersection_x < xPlane_0_min_safety
00427         || intersection_x >= xPlane_N_max_safety )
00428       {
00429         index_z += increment_index[ 2 ];
00430         intersection_y += incrementY;
00431         intersection_x += incrementX;
00432         continue;
00433       }
00434 
00435       // Find the index in the image
00436       index_y = (INTNB)( ( intersection_y - yPlane_0_min ) / szImg_Y );
00437       index_x = (INTNB)( ( intersection_x - xPlane_0_min ) / szImg_X );
00438 
00439       // Compute distance between intersection point and Y and Z boundaries
00440       y2 = ::fabs( mp_boundariesY[ index_y ] + szImg_Y * ((FLTNB)0.5) - intersection_y )
00441         / szImg_Y;
00442       y1 = ((FLTNB)1.0) - y2;
00443       x2 = ::fabs( mp_boundariesX[ index_x ] + szImg_X * ((FLTNB)0.5) - intersection_x )
00444         / szImg_X;
00445       x1 = ((FLTNB)1.0) - x2;
00446 
00447       uint32_t index_final = index_x + index_y * nPlane_X + index_z * nPlane_XY;
00448       ap_ProjectionLine->AddVoxel(a_direction, index_final, ( x1 * y1 ) * weight);
00449       ap_ProjectionLine->AddVoxel(a_direction, index_final + 1, ( x2 * y1 ) * weight);
00450       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_X, ( x1 * y2 ) * weight);
00451       ap_ProjectionLine->AddVoxel(a_direction, index_final + nPlane_X + 1, ( x2 * y2 ) * weight);
00452 
00453       // Increment
00454       index_z += increment_index[ 2 ];
00455       intersection_y += incrementY;
00456       intersection_x += incrementX;
00457     }
00458   }
00459   return 0;
00460 }
00461 
00462 // =====================================================================
00463 // ---------------------------------------------------------------------
00464 // ---------------------------------------------------------------------
00465 // =====================================================================
00466 
00467 int iProjectorJoseph::ProjectWithTOFPos(int a_Projector, oProjectionLine* ap_ProjectionLine)
00468 {
00469   Cerr("***** iProjectorJoseph::ProjectWithTOFPos() -> Not yet implemented !" << endl);
00470   return 1;
00471 }
00472 
00473 // =====================================================================
00474 // ---------------------------------------------------------------------
00475 // ---------------------------------------------------------------------
00476 // =====================================================================
00477 
00478 int iProjectorJoseph::ProjectWithTOFBin(int a_Projector, oProjectionLine* ap_ProjectionLine)
00479 {
00480   Cerr("***** iProjectorJoseph::ProjectWithTOFBin() -> Not yet implemented !" << endl);
00481   return 1;
00482 }
00483 
00484 // =====================================================================
00485 // ---------------------------------------------------------------------
00486 // ---------------------------------------------------------------------
00487 // =====================================================================
 All Classes Files Functions Variables Typedefs Defines