![]() |
CASToR
1.0
Tomographic Reconstruction (PET/SPECT)
|
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 // =====================================================================