1 /*========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18 #ifndef __itkRayCastInterpolateImageFunctionWithOrigin_txx
19 #define __itkRayCastInterpolateImageFunctionWithOrigin_txx
20 #include "itkRayCastInterpolateImageFunctionWithOrigin.h"
22 #include "vnl/vnl_math.h"
23 #include "clitkCommon.h"
25 // Put the helper class in an anonymous namespace so that it is not
26 // exposed to the user
30 /** \class Helper class to maintain state when casting a ray.
31 * This helper class keeps the RayCastInterpolateImageFunctionWithOrigin thread safe.
33 template <class TInputImage, class TCoordRep = float>
37 /** Constants for the image dimensions */
38 itkStaticConstMacro(InputImageDimension, unsigned int,
39 TInputImage::ImageDimension);
42 * Type of the Transform Base class
43 * The fixed image should be a 3D image
45 typedef itk::Transform<TCoordRep,3,3> TransformType;
47 typedef typename TransformType::Pointer TransformPointer;
48 typedef typename TransformType::InputPointType InputPointType;
49 typedef typename TransformType::OutputPointType OutputPointType;
50 typedef typename TransformType::ParametersType TransformParametersType;
51 typedef typename TransformType::JacobianType TransformJacobianType;
53 typedef typename TInputImage::SizeType SizeType;
54 typedef itk::Vector<TCoordRep, 3> DirectionType;
55 typedef itk::Point<TCoordRep, 3> PointType;
57 typedef TInputImage InputImageType;
58 typedef typename InputImageType::PixelType PixelType;
59 typedef typename InputImageType::IndexType IndexType;
64 void SetImage(const InputImageType *input) {
69 * Initialise the ray using the position and direction of a line.
71 * \param RayPosn The position of the ray in 3D (mm).
72 * \param RayDirn The direction of the ray in 3D (mm).
74 * \return True if this is a valid ray.
76 bool SetRay(OutputPointType RayPosn, DirectionType RayDirn);
80 * Integrate the interpolated intensities along the ray and
83 * This routine can be called after instantiating the ray and
84 * calling SetProjectionCoord2D() or Reset(). It may then be called
85 * as many times thereafter for different 2D projection
88 * \param integral The integrated intensities along the ray.
90 * \return True if a valid ray was specified.
92 bool Integrate(double &integral) {
93 return IntegrateAboveThreshold(integral, 0);
98 * Integrate the interpolated intensities above a given threshold,
99 * along the ray and return the result.
101 * This routine can be called after instantiating the ray and
102 * calling SetProjectionCoord2D() or Reset(). It may then be called
103 * as many times thereafter for different 2D projection
106 * \param integral The integrated intensities along the ray.
107 * \param threshold The integration threshold [default value: 0]
109 * \return True if a valid ray was specified.
111 bool IntegrateAboveThreshold(double &integral, double threshold);
114 * Increment each of the intensities of the 4 planar voxels
115 * surrounding the current ray point.
117 * \parameter increment Intensity increment for each of the current 4 voxels
119 void IncrementIntensities(double increment=1);
121 /// Reset the iterator to the start of the ray.
124 /// Return the interpolated intensity of the current ray point.
125 double GetCurrentIntensity(void) const;
127 /// Return the ray point spacing in mm
128 double GetRayPointSpacing(void) const {
129 typename InputImageType::SpacingType spacing=this->m_Image->GetSpacing();
132 return vcl_sqrt(m_VoxelIncrement[0]*spacing[0]*m_VoxelIncrement[0]*spacing[0]
133 + m_VoxelIncrement[1]*spacing[1]*m_VoxelIncrement[1]*spacing[1]
134 + m_VoxelIncrement[2]*spacing[2]*m_VoxelIncrement[2]*spacing[2] );
139 /// Set the initial zero state of the object
142 /// Initialise the object
143 void Initialise(void);
146 /// Calculate the endpoint coordinats of the ray in voxels.
147 void EndPointsInVoxels(void);
150 * Calculate the incremental direction vector in voxels, 'dVoxel',
151 * required to traverse the ray.
153 void CalcDirnVector(void);
156 * Reduce the length of the ray until both start and end
157 * coordinates lie inside the volume.
159 * \return True if a valid ray has been, false otherwise.
161 bool AdjustRayLength(void);
164 * Obtain pointers to the four voxels surrounding the point where the ray
167 void InitialiseVoxelPointers(void);
169 /// Increment the voxel pointers surrounding the current point on the ray.
170 void IncrementVoxelPointers(void);
172 /// Record volume dimensions and resolution
173 void RecordVolumeDimensions(void);
175 /// Define the corners of the volume
176 void DefineCorners(void);
179 * Calculate the planes which define the volume.
181 * Member function to calculate the equations of the planes of 4 of
182 * the sides of the volume, calculate the positions of the 8 corners
183 * of the volume in mm in World, also calculate the values of the
184 * slopes of the lines which go to make up the volume( defined as
185 * lines in cube x,y,z dirn and then each of these lines has a slope
186 * in the world x,y,z dirn [3]) and finally also to return the length
187 * of the sides of the lines in mm.
189 void CalcPlanesAndCorners(void);
192 * Calculate the ray intercepts with the volume.
194 * See where the ray cuts the volume, check that truncation does not occur,
195 * if not, then start ray where it first intercepts the volume and set
196 * x_max to be where it leaves the volume.
198 * \return True if a valid ray has been specified, false otherwise.
200 bool CalcRayIntercepts(void);
203 * The ray is traversed by stepping in the axial direction
204 * that enables the greatest number of planes in the volume to be
208 UNDEFINED_DIRECTION=0, //!< Undefined
209 TRANSVERSE_IN_X, //!< x
210 TRANSVERSE_IN_Y, //!< y
211 TRANSVERSE_IN_Z, //!< z
213 } TraversalDirection;
215 // Cache the image in the structure. Skip the smart pointer for
216 // efficiency. This inner class will go in/out of scope with every
217 // call to Evaluate()
218 const InputImageType *m_Image;
220 /// Flag indicating whether the current ray is valid
224 * The start position of the ray in voxels.
226 * NB. Two of the components of this coordinate (i.e. those lying within
227 * the planes of voxels being traversed) will be shifted by half a
228 * voxel. This enables indices of the neighbouring voxels within the plane
229 * to be determined by simply casting to 'int' and optionally adding 1.
231 double m_RayVoxelStartPosition[3];
234 * The end coordinate of the ray in voxels.
236 * NB. Two of the components of this coordinate (i.e. those lying within
237 * the planes of voxels being traversed) will be shifted by half a
238 * voxel. This enables indices of the neighbouring voxels within the plane
239 * to be determined by simply casting to 'int' and optionally adding 1.
241 double m_RayVoxelEndPosition[3];
245 * The current coordinate on the ray in voxels.
247 * NB. Two of the components of this coordinate (i.e. those lying within
248 * the planes of voxels being traversed) will be shifted by half a
249 * voxel. This enables indices of the neighbouring voxels within the plane
250 * to be determined by simply casting to 'int' and optionally adding 1.
252 double m_Position3Dvox[3];
254 /** The incremental direction vector of the ray in voxels. */
255 double m_VoxelIncrement[3];
257 /// The direction in which the ray is incremented thorough the volume (x, y or z).
258 TraversalDirection m_TraversalDirection;
260 /// The total number of planes of voxels traversed by the ray.
261 int m_TotalRayVoxelPlanes;
263 /// The current number of planes of voxels traversed by the ray.
264 int m_NumVoxelPlanesTraversed;
266 /// Pointers to the current four voxels surrounding the ray's trajectory.
267 const PixelType *m_RayIntersectionVoxels[4];
270 * The voxel coordinate of the bottom-left voxel of the current
271 * four voxels surrounding the ray's trajectory.
273 int m_RayIntersectionVoxelIndex[3];
275 /// The dimension in voxels of the 3D volume in along the x axis
276 int m_NumberOfVoxelsInX;
277 /// The dimension in voxels of the 3D volume in along the y axis
278 int m_NumberOfVoxelsInY;
279 /// The dimension in voxels of the 3D volume in along the z axis
280 int m_NumberOfVoxelsInZ;
282 /// Voxel dimension in x
283 double m_VoxelDimensionInX;
284 /// Voxel dimension in y
285 double m_VoxelDimensionInY;
286 /// Voxel dimension in z
287 double m_VoxelDimensionInZ;
289 /// The coordinate of the point at which the ray enters the volume in mm.
290 double m_RayStartCoordInMM[3];
291 /// The coordinate of the point at which the ray exits the volume in mm.
292 double m_RayEndCoordInMM[3];
296 Planes which define the boundary of the volume in mm
297 (six planes and four parameters: Ax+By+Cz+D). */
298 double m_BoundingPlane[6][4];
299 /// The eight corners of the volume (x,y,z coordinates for each).
300 double m_BoundingCorner[8][3];
302 /// The position of the ray
303 double m_CurrentRayPositionInMM[3];
305 /// The direction of the ray
306 double m_RayDirectionInMM[3];
310 /* -----------------------------------------------------------------------
311 Initialise() - Initialise the object
312 ----------------------------------------------------------------------- */
314 template<class TInputImage, class TCoordRep>
316 RayCastHelper<TInputImage, TCoordRep>
319 // Save the dimensions of the volume and calculate the bounding box
320 this->RecordVolumeDimensions();
322 // Calculate the planes and corners which define the volume.
323 this->DefineCorners();
324 this->CalcPlanesAndCorners();
328 /* -----------------------------------------------------------------------
329 RecordVolumeDimensions() - Record volume dimensions and resolution
330 ----------------------------------------------------------------------- */
332 template<class TInputImage, class TCoordRep>
334 RayCastHelper<TInputImage, TCoordRep>
335 ::RecordVolumeDimensions(void)
337 typename InputImageType::SpacingType spacing=this->m_Image->GetSpacing();
338 SizeType dim=this->m_Image->GetLargestPossibleRegion().GetSize();
340 m_NumberOfVoxelsInX = dim[0];
341 m_NumberOfVoxelsInY = dim[1];
342 m_NumberOfVoxelsInZ = dim[2];
344 m_VoxelDimensionInX = spacing[0];
345 m_VoxelDimensionInY = spacing[1];
346 m_VoxelDimensionInZ = spacing[2];
350 /* -----------------------------------------------------------------------
351 DefineCorners() - Define the corners of the volume
352 ----------------------------------------------------------------------- */
354 template<class TInputImage, class TCoordRep>
356 RayCastHelper<TInputImage, TCoordRep>
357 ::DefineCorners(void)
359 // Define corner positions as if at the origin
361 m_BoundingCorner[0][0] =
362 m_BoundingCorner[1][0] =
363 m_BoundingCorner[2][0] =
364 m_BoundingCorner[3][0] = 0;
366 m_BoundingCorner[4][0] =
367 m_BoundingCorner[5][0] =
368 m_BoundingCorner[6][0] =
369 m_BoundingCorner[7][0] = m_VoxelDimensionInX*m_NumberOfVoxelsInX;
371 m_BoundingCorner[1][1] =
372 m_BoundingCorner[3][1] =
373 m_BoundingCorner[5][1] =
374 m_BoundingCorner[7][1] = m_VoxelDimensionInY*m_NumberOfVoxelsInY;
376 m_BoundingCorner[0][1] =
377 m_BoundingCorner[2][1] =
378 m_BoundingCorner[4][1] =
379 m_BoundingCorner[6][1] = 0;
381 m_BoundingCorner[0][2] =
382 m_BoundingCorner[1][2] =
383 m_BoundingCorner[4][2] =
384 m_BoundingCorner[5][2] =
385 m_VoxelDimensionInZ*m_NumberOfVoxelsInZ;
387 m_BoundingCorner[2][2] =
388 m_BoundingCorner[3][2] =
389 m_BoundingCorner[6][2] =
390 m_BoundingCorner[7][2] = 0;
394 /* -----------------------------------------------------------------------
395 CalcPlanesAndCorners() - Calculate the planes and corners of the volume.
396 ----------------------------------------------------------------------- */
398 template<class TInputImage, class TCoordRep>
400 RayCastHelper<TInputImage, TCoordRep>
401 ::CalcPlanesAndCorners(void)
406 // find the equations of the planes
408 int c1=0, c2=0, c3=0;
410 for (j=0; j<6; j++) {
411 // loop around for planes
413 // which corners to take
447 double line1x, line1y, line1z;
448 double line2x, line2y, line2z;
450 // lines from one corner to another in x,y,z dirns
451 line1x = m_BoundingCorner[c1][0] - m_BoundingCorner[c2][0];
452 line2x = m_BoundingCorner[c1][0] - m_BoundingCorner[c3][0];
454 line1y = m_BoundingCorner[c1][1] - m_BoundingCorner[c2][1];
455 line2y = m_BoundingCorner[c1][1] - m_BoundingCorner[c3][1];
457 line1z = m_BoundingCorner[c1][2] - m_BoundingCorner[c2][2];
458 line2z = m_BoundingCorner[c1][2] - m_BoundingCorner[c3][2];
462 // take cross product
463 A = line1y*line2z - line2y*line1z;
464 B = line2x*line1z - line1x*line2z;
465 C = line1x*line2y - line2x*line1y;
468 D = -( A*m_BoundingCorner[c1][0]
469 + B*m_BoundingCorner[c1][1]
470 + C*m_BoundingCorner[c1][2] );
472 // initialise plane value and normalise
473 m_BoundingPlane[j][0] = A/vcl_sqrt(A*A + B*B + C*C);
474 m_BoundingPlane[j][1] = B/vcl_sqrt(A*A + B*B + C*C);
475 m_BoundingPlane[j][2] = C/vcl_sqrt(A*A + B*B + C*C);
476 m_BoundingPlane[j][3] = D/vcl_sqrt(A*A + B*B + C*C);
478 if ( (A*A + B*B + C*C) == 0 ) {
479 itk::ExceptionObject err(__FILE__, __LINE__);
480 err.SetLocation( ITK_LOCATION );
481 err.SetDescription( "Division by zero (planes) "
482 "- CalcPlanesAndCorners().");
490 /* -----------------------------------------------------------------------
491 CalcRayIntercepts() - Calculate the ray intercepts with the volume.
492 ----------------------------------------------------------------------- */
494 template<class TInputImage, class TCoordRep>
496 RayCastHelper<TInputImage, TCoordRep>
497 ::CalcRayIntercepts()
499 double maxInterDist, interDist;
500 double cornerVect[4][3];
501 for(clitk::uint i=0; i<4; i++)
502 for(clitk::uint j=0; j<3; j++)
503 cornerVect[i][j] = 0.0; // to avoid warning
504 int cross[4][3], noInterFlag[6];
505 int nSidesCrossed, crossFlag, c[4];
506 double ax, ay, az, bx, by, bz;
507 double cubeInter[6][3];
511 int NoSides = 6; // =6 to allow truncation: =4 to remove truncated rays
513 // Calculate intercept of ray with planes
515 double interceptx[6], intercepty[6], interceptz[6];
518 for( j=0; j<NoSides; j++) {
520 denom = ( m_BoundingPlane[j][0]*m_RayDirectionInMM[0]
521 + m_BoundingPlane[j][1]*m_RayDirectionInMM[1]
522 + m_BoundingPlane[j][2]*m_RayDirectionInMM[2]);
524 if( (long)(denom*100) != 0 ) {
525 d[j] = -( m_BoundingPlane[j][3]
526 + m_BoundingPlane[j][0]*m_CurrentRayPositionInMM[0]
527 + m_BoundingPlane[j][1]*m_CurrentRayPositionInMM[1]
528 + m_BoundingPlane[j][2]*m_CurrentRayPositionInMM[2] ) / denom;
530 interceptx[j] = m_CurrentRayPositionInMM[0] + d[j]*m_RayDirectionInMM[0];
531 intercepty[j] = m_CurrentRayPositionInMM[1] + d[j]*m_RayDirectionInMM[1];
532 interceptz[j] = m_CurrentRayPositionInMM[2] + d[j]*m_RayDirectionInMM[2];
534 noInterFlag[j] = 1; //OK
536 noInterFlag[j] = 0; //NOT OK
542 for( j=0; j<NoSides; j++ ) {
544 // Work out which corners to use
580 // Calculate vectors from corner of ct volume to intercept.
581 for( i=0; i<4; i++ ) {
582 if( noInterFlag[j]==1 ) {
583 cornerVect[i][0] = m_BoundingCorner[c[i]][0] - interceptx[j];
584 cornerVect[i][1] = m_BoundingCorner[c[i]][1] - intercepty[j];
585 cornerVect[i][2] = m_BoundingCorner[c[i]][2] - interceptz[j];
586 } else if( noInterFlag[j]==0 ) {
587 cornerVect[i][0] = 0;
588 cornerVect[i][1] = 0;
589 cornerVect[i][2] = 0;
594 // Do cross product with these vectors
595 for( i=0; i<4; i++ ) {
601 ax = cornerVect[i][0];
602 ay = cornerVect[i][1];
603 az = cornerVect[i][2];
604 bx = cornerVect[k][0];
605 by = cornerVect[k][1];
606 bz = cornerVect[k][2];
608 // The int and divide by 100 are to avoid rounding errors. If
609 // these are not included then you get values fluctuating around
610 // zero and so in the subsequent check, all the values are not
611 // above or below zero. NB. If you "INT" by too much here though
612 // you can get problems in the corners of your volume when rays
613 // are allowed to go through more than one plane.
614 cross[i][0] = (int)((ay*bz - az*by)/100);
615 cross[i][1] = (int)((az*bx - ax*bz)/100);
616 cross[i][2] = (int)((ax*by - ay*bx)/100);
619 // See if a sign change occured between all these cross products
620 // if not, then the ray went through this plane
623 for( i=0; i<3; i++ ) {
632 && cross[3][i]>=0) ) {
638 if( crossFlag==3 && noInterFlag[j]==1 ) {
639 cubeInter[nSidesCrossed][0] = interceptx[j];
640 cubeInter[nSidesCrossed][1] = intercepty[j];
641 cubeInter[nSidesCrossed][2] = interceptz[j];
645 } // End of loop over all four planes
647 m_RayStartCoordInMM[0] = cubeInter[0][0];
648 m_RayStartCoordInMM[1] = cubeInter[0][1];
649 m_RayStartCoordInMM[2] = cubeInter[0][2];
651 m_RayEndCoordInMM[0] = cubeInter[1][0];
652 m_RayEndCoordInMM[1] = cubeInter[1][1];
653 m_RayEndCoordInMM[2] = cubeInter[1][2];
655 if( nSidesCrossed >= 5 ) {
656 std::cerr << "WARNING: No. of sides crossed equals: " << nSidesCrossed << std::endl;
659 // If 'nSidesCrossed' is larger than 2, this means that the ray goes through
660 // a corner of the volume and due to rounding errors, the ray is
661 // deemed to go through more than two planes. To obtain the correct
662 // start and end positions we choose the two intercept values which
663 // are furthest from each other.
666 if( nSidesCrossed >= 3 ) {
668 for( j=0; j<nSidesCrossed-1; j++ ) {
669 for( k=j+1; k<nSidesCrossed; k++ ) {
671 for( i=0; i<3; i++ ) {
672 interDist += (cubeInter[j][i] - cubeInter[k][i])*
673 (cubeInter[j][i] - cubeInter[k][i]);
675 if( interDist > maxInterDist ) {
676 maxInterDist = interDist;
678 m_RayStartCoordInMM[0] = cubeInter[j][0];
679 m_RayStartCoordInMM[1] = cubeInter[j][1];
680 m_RayStartCoordInMM[2] = cubeInter[j][2];
682 m_RayEndCoordInMM[0] = cubeInter[k][0];
683 m_RayEndCoordInMM[1] = cubeInter[k][1];
684 m_RayEndCoordInMM[2] = cubeInter[k][2];
691 if (nSidesCrossed == 2 ) {
699 /* -----------------------------------------------------------------------
700 SetRay() - Set the position and direction of the ray
701 ----------------------------------------------------------------------- */
703 template<class TInputImage, class TCoordRep>
705 RayCastHelper<TInputImage, TCoordRep>
706 ::SetRay(OutputPointType RayPosn, DirectionType RayDirn)
709 // Store the position and direction of the ray
710 typename TInputImage::SpacingType spacing=this->m_Image->GetSpacing();
711 SizeType dim=this->m_Image->GetLargestPossibleRegion().GetSize();
713 // we need to translate the _center_ of the volume to the origin
714 m_NumberOfVoxelsInX = dim[0];
715 m_NumberOfVoxelsInY = dim[1];
716 m_NumberOfVoxelsInZ = dim[2];
718 m_VoxelDimensionInX = spacing[0];
719 m_VoxelDimensionInY = spacing[1];
720 m_VoxelDimensionInZ = spacing[2];
722 // (Aviv) Incorporating a fix by Jian Wu
723 // http://public.kitware.com/pipermail/insight-users/2006-March/017265.html
724 m_CurrentRayPositionInMM[0] = RayPosn[0];
725 m_CurrentRayPositionInMM[1] = RayPosn[1];
726 m_CurrentRayPositionInMM[2] = RayPosn[2];
728 m_RayDirectionInMM[0] = RayDirn[0];
729 m_RayDirectionInMM[1] = RayDirn[1];
730 m_RayDirectionInMM[2] = RayDirn[2];
732 // Compute the ray path for this coordinate in mm
734 m_ValidRay = this->CalcRayIntercepts();
741 // Convert the start and end coordinates of the ray to voxels
743 this->EndPointsInVoxels();
745 /* Calculate the ray direction vector in voxels and hence the voxel
746 increment required to traverse the ray, and the number of
747 interpolation points on the ray.
749 This routine also shifts the coordinate frame by half a voxel for
750 two of the directional components (i.e. those lying within the
751 planes of voxels being traversed). */
753 this->CalcDirnVector();
756 /* Reduce the length of the ray until both start and end
757 coordinates lie inside the volume. */
759 m_ValidRay = this->AdjustRayLength();
761 // Reset the iterator to the start of the ray.
769 /* -----------------------------------------------------------------------
770 EndPointsInVoxels() - Convert the endpoints to voxels
771 ----------------------------------------------------------------------- */
773 template<class TInputImage, class TCoordRep>
775 RayCastHelper<TInputImage, TCoordRep>
776 ::EndPointsInVoxels(void)
778 m_RayVoxelStartPosition[0] = m_RayStartCoordInMM[0]/m_VoxelDimensionInX;
779 m_RayVoxelStartPosition[1] = m_RayStartCoordInMM[1]/m_VoxelDimensionInY;
780 m_RayVoxelStartPosition[2] = m_RayStartCoordInMM[2]/m_VoxelDimensionInZ;
782 m_RayVoxelEndPosition[0] = m_RayEndCoordInMM[0]/m_VoxelDimensionInX;
783 m_RayVoxelEndPosition[1] = m_RayEndCoordInMM[1]/m_VoxelDimensionInY;
784 m_RayVoxelEndPosition[2] = m_RayEndCoordInMM[2]/m_VoxelDimensionInZ;
789 /* -----------------------------------------------------------------------
790 CalcDirnVector() - Calculate the incremental direction vector in voxels.
791 ----------------------------------------------------------------------- */
793 template<class TInputImage, class TCoordRep>
795 RayCastHelper<TInputImage, TCoordRep>
796 ::CalcDirnVector(void)
798 double xNum, yNum, zNum;
800 // Calculate the number of voxels in each direction
802 xNum = vcl_fabs(m_RayVoxelStartPosition[0] - m_RayVoxelEndPosition[0]);
803 yNum = vcl_fabs(m_RayVoxelStartPosition[1] - m_RayVoxelEndPosition[1]);
804 zNum = vcl_fabs(m_RayVoxelStartPosition[2] - m_RayVoxelEndPosition[2]);
806 // The direction iterated in is that with the greatest number of voxels
807 // ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
809 // Iterate in X direction
811 if( (xNum >= yNum) && (xNum >= zNum) ) {
812 if( m_RayVoxelStartPosition[0] < m_RayVoxelEndPosition[0] ) {
813 m_VoxelIncrement[0] = 1;
816 = (m_RayVoxelStartPosition[1]
817 - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[0]
818 - m_RayVoxelEndPosition[0]);
821 = (m_RayVoxelStartPosition[2]
822 - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[0]
823 - m_RayVoxelEndPosition[0]);
825 m_VoxelIncrement[0] = -1;
828 = -(m_RayVoxelStartPosition[1]
829 - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[0]
830 - m_RayVoxelEndPosition[0]);
833 = -(m_RayVoxelStartPosition[2]
834 - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[0]
835 - m_RayVoxelEndPosition[0]);
838 // This section is to alter the start position in order to
839 // place the center of the voxels in there correct positions,
840 // rather than placing them at the corner of voxels which is
841 // what happens if this is not carried out. The reason why
842 // x has no -0.5 is because this is the direction we are going
843 // to iterate in and therefore we wish to go from center to
844 // center rather than finding the surrounding voxels.
846 m_RayVoxelStartPosition[1] += ( (int)m_RayVoxelStartPosition[0]
847 - m_RayVoxelStartPosition[0])*m_VoxelIncrement[1]*m_VoxelIncrement[0]
848 + 0.5*m_VoxelIncrement[1] - 0.5;
850 m_RayVoxelStartPosition[2] += ( (int)m_RayVoxelStartPosition[0]
851 - m_RayVoxelStartPosition[0])*m_VoxelIncrement[2]*m_VoxelIncrement[0]
852 + 0.5*m_VoxelIncrement[2] - 0.5;
854 m_RayVoxelStartPosition[0] = (int)m_RayVoxelStartPosition[0] + 0.5*m_VoxelIncrement[0];
856 m_TotalRayVoxelPlanes = (int)xNum;
858 m_TraversalDirection = TRANSVERSE_IN_X;
861 // Iterate in Y direction
863 else if( (yNum >= xNum) && (yNum >= zNum) ) {
865 if( m_RayVoxelStartPosition[1] < m_RayVoxelEndPosition[1] ) {
866 m_VoxelIncrement[1] = 1;
869 = (m_RayVoxelStartPosition[0]
870 - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[1]
871 - m_RayVoxelEndPosition[1]);
874 = (m_RayVoxelStartPosition[2]
875 - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[1]
876 - m_RayVoxelEndPosition[1]);
878 m_VoxelIncrement[1] = -1;
881 = -(m_RayVoxelStartPosition[0]
882 - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[1]
883 - m_RayVoxelEndPosition[1]);
886 = -(m_RayVoxelStartPosition[2]
887 - m_RayVoxelEndPosition[2])/(m_RayVoxelStartPosition[1]
888 - m_RayVoxelEndPosition[1]);
891 m_RayVoxelStartPosition[0] += ( (int)m_RayVoxelStartPosition[1]
892 - m_RayVoxelStartPosition[1])*m_VoxelIncrement[0]*m_VoxelIncrement[1]
893 + 0.5*m_VoxelIncrement[0] - 0.5;
895 m_RayVoxelStartPosition[2] += ( (int)m_RayVoxelStartPosition[1]
896 - m_RayVoxelStartPosition[1])*m_VoxelIncrement[2]*m_VoxelIncrement[1]
897 + 0.5*m_VoxelIncrement[2] - 0.5;
899 m_RayVoxelStartPosition[1] = (int)m_RayVoxelStartPosition[1] + 0.5*m_VoxelIncrement[1];
901 m_TotalRayVoxelPlanes = (int)yNum;
903 m_TraversalDirection = TRANSVERSE_IN_Y;
906 // Iterate in Z direction
910 if( m_RayVoxelStartPosition[2] < m_RayVoxelEndPosition[2] ) {
911 m_VoxelIncrement[2] = 1;
914 = (m_RayVoxelStartPosition[0]
915 - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[2]
916 - m_RayVoxelEndPosition[2]);
919 = (m_RayVoxelStartPosition[1]
920 - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[2]
921 - m_RayVoxelEndPosition[2]);
923 m_VoxelIncrement[2] = -1;
926 = -(m_RayVoxelStartPosition[0]
927 - m_RayVoxelEndPosition[0])/(m_RayVoxelStartPosition[2]
928 - m_RayVoxelEndPosition[2]);
931 = -(m_RayVoxelStartPosition[1]
932 - m_RayVoxelEndPosition[1])/(m_RayVoxelStartPosition[2]
933 - m_RayVoxelEndPosition[2]);
936 m_RayVoxelStartPosition[0] += ( (int)m_RayVoxelStartPosition[2]
937 - m_RayVoxelStartPosition[2])*m_VoxelIncrement[0]*m_VoxelIncrement[2]
938 + 0.5*m_VoxelIncrement[0] - 0.5;
940 m_RayVoxelStartPosition[1] += ( (int)m_RayVoxelStartPosition[2]
941 - m_RayVoxelStartPosition[2])*m_VoxelIncrement[1]*m_VoxelIncrement[2]
942 + 0.5*m_VoxelIncrement[1] - 0.5;
944 m_RayVoxelStartPosition[2] = (int)m_RayVoxelStartPosition[2] + 0.5*m_VoxelIncrement[2];
946 m_TotalRayVoxelPlanes = (int)zNum;
948 m_TraversalDirection = TRANSVERSE_IN_Z;
953 /* -----------------------------------------------------------------------
954 AdjustRayLength() - Ensure that the ray lies within the volume
955 ----------------------------------------------------------------------- */
957 template<class TInputImage, class TCoordRep>
959 RayCastHelper<TInputImage, TCoordRep>
960 ::AdjustRayLength(void)
967 if (m_TraversalDirection == TRANSVERSE_IN_X) {
971 } else if (m_TraversalDirection == TRANSVERSE_IN_Y) {
975 } else if (m_TraversalDirection == TRANSVERSE_IN_Z) {
980 itk::ExceptionObject err(__FILE__, __LINE__);
981 err.SetLocation( ITK_LOCATION );
982 err.SetDescription( "The ray traversal direction is unset "
983 "- AdjustRayLength().");
994 Istart[0] = (int) vcl_floor(m_RayVoxelStartPosition[0]);
995 Istart[1] = (int) vcl_floor(m_RayVoxelStartPosition[1]);
996 Istart[2] = (int) vcl_floor(m_RayVoxelStartPosition[2]);
998 if( (Istart[0] >= 0) && (Istart[0] + Idirn[0] < m_NumberOfVoxelsInX) &&
999 (Istart[1] >= 0) && (Istart[1] + Idirn[1] < m_NumberOfVoxelsInY) &&
1000 (Istart[2] >= 0) && (Istart[2] + Idirn[2] < m_NumberOfVoxelsInZ) ) {
1004 m_RayVoxelStartPosition[0] += m_VoxelIncrement[0];
1005 m_RayVoxelStartPosition[1] += m_VoxelIncrement[1];
1006 m_RayVoxelStartPosition[2] += m_VoxelIncrement[2];
1008 m_TotalRayVoxelPlanes--;
1011 Istart[0] = (int) vcl_floor(m_RayVoxelStartPosition[0]
1012 + m_TotalRayVoxelPlanes*m_VoxelIncrement[0]);
1014 Istart[1] = (int) vcl_floor(m_RayVoxelStartPosition[1]
1015 + m_TotalRayVoxelPlanes*m_VoxelIncrement[1]);
1017 Istart[2] = (int) vcl_floor(m_RayVoxelStartPosition[2]
1018 + m_TotalRayVoxelPlanes*m_VoxelIncrement[2]);
1020 if( (Istart[0] >= 0) && (Istart[0] + Idirn[0] < m_NumberOfVoxelsInX) &&
1021 (Istart[1] >= 0) && (Istart[1] + Idirn[1] < m_NumberOfVoxelsInY) &&
1022 (Istart[2] >= 0) && (Istart[2] + Idirn[2] < m_NumberOfVoxelsInZ) ) {
1026 m_TotalRayVoxelPlanes--;
1029 } while ( (! (startOK && endOK)) && (m_TotalRayVoxelPlanes > 1) );
1032 return (startOK && endOK);
1036 /* -----------------------------------------------------------------------
1037 Reset() - Reset the iterator to the start of the ray.
1038 ----------------------------------------------------------------------- */
1040 template<class TInputImage, class TCoordRep>
1042 RayCastHelper<TInputImage, TCoordRep>
1047 m_NumVoxelPlanesTraversed = -1;
1049 // If this is a valid ray...
1052 for (i=0; i<3; i++) {
1053 m_Position3Dvox[i] = m_RayVoxelStartPosition[i];
1055 this->InitialiseVoxelPointers();
1058 // otherwise set parameters to zero
1061 for (i=0; i<3; i++) {
1062 m_RayVoxelStartPosition[i] = 0.;
1064 for (i=0; i<3; i++) {
1065 m_RayVoxelEndPosition[i] = 0.;
1067 for (i=0; i<3; i++) {
1068 m_VoxelIncrement[i] = 0.;
1070 m_TraversalDirection = UNDEFINED_DIRECTION;
1072 m_TotalRayVoxelPlanes = 0;
1074 for (i=0; i<4; i++) {
1075 m_RayIntersectionVoxels[i] = 0;
1077 for (i=0; i<3; i++) {
1078 m_RayIntersectionVoxelIndex[i] = 0;
1084 /* -----------------------------------------------------------------------
1085 InitialiseVoxelPointers() - Obtain pointers to the first four voxels
1086 ----------------------------------------------------------------------- */
1088 template<class TInputImage, class TCoordRep>
1090 RayCastHelper<TInputImage, TCoordRep>
1091 ::InitialiseVoxelPointers(void)
1097 Ix = (int)(m_RayVoxelStartPosition[0]);
1098 Iy = (int)(m_RayVoxelStartPosition[1]);
1099 Iz = (int)(m_RayVoxelStartPosition[2]);
1101 m_RayIntersectionVoxelIndex[0] = Ix;
1102 m_RayIntersectionVoxelIndex[1] = Iy;
1103 m_RayIntersectionVoxelIndex[2] = Iz;
1105 switch( m_TraversalDirection ) {
1106 case TRANSVERSE_IN_X: {
1108 if( (Ix >= 0) && (Ix < m_NumberOfVoxelsInX) &&
1109 (Iy >= 0) && (Iy + 1 < m_NumberOfVoxelsInY) &&
1110 (Iz >= 0) && (Iz + 1 < m_NumberOfVoxelsInZ)) {
1115 m_RayIntersectionVoxels[0]
1116 = this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index);
1121 m_RayIntersectionVoxels[1]
1122 = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) );
1127 m_RayIntersectionVoxels[2]
1128 = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) );
1133 m_RayIntersectionVoxels[3]
1134 = ( this->m_Image->GetBufferPointer() + this->m_Image->ComputeOffset(index) );
1136 m_RayIntersectionVoxels[0] =
1137 m_RayIntersectionVoxels[1] =
1138 m_RayIntersectionVoxels[2] =
1139 m_RayIntersectionVoxels[3] = NULL;
1144 case TRANSVERSE_IN_Y: {
1146 if( (Ix >= 0) && (Ix + 1 < m_NumberOfVoxelsInX) &&
1147 (Iy >= 0) && (Iy < m_NumberOfVoxelsInY) &&
1148 (Iz >= 0) && (Iz + 1 < m_NumberOfVoxelsInZ)) {
1153 m_RayIntersectionVoxels[0] = ( this->m_Image->GetBufferPointer()
1154 + this->m_Image->ComputeOffset(index) );
1159 m_RayIntersectionVoxels[1] = ( this->m_Image->GetBufferPointer()
1160 + this->m_Image->ComputeOffset(index) );
1165 m_RayIntersectionVoxels[2] = ( this->m_Image->GetBufferPointer()
1166 + this->m_Image->ComputeOffset(index) );
1171 m_RayIntersectionVoxels[3] = ( this->m_Image->GetBufferPointer()
1172 + this->m_Image->ComputeOffset(index) );
1174 m_RayIntersectionVoxels[0]
1175 = m_RayIntersectionVoxels[1]
1176 = m_RayIntersectionVoxels[2]
1177 = m_RayIntersectionVoxels[3] = NULL;
1182 case TRANSVERSE_IN_Z: {
1184 if( (Ix >= 0) && (Ix + 1 < m_NumberOfVoxelsInX) &&
1185 (Iy >= 0) && (Iy + 1 < m_NumberOfVoxelsInY) &&
1186 (Iz >= 0) && (Iz < m_NumberOfVoxelsInZ)) {
1191 m_RayIntersectionVoxels[0] = ( this->m_Image->GetBufferPointer()
1192 + this->m_Image->ComputeOffset(index) );
1197 m_RayIntersectionVoxels[1] = ( this->m_Image->GetBufferPointer()
1198 + this->m_Image->ComputeOffset(index) );
1203 m_RayIntersectionVoxels[2] = ( this->m_Image->GetBufferPointer()
1204 + this->m_Image->ComputeOffset(index) );
1209 m_RayIntersectionVoxels[3] = ( this->m_Image->GetBufferPointer()
1210 + this->m_Image->ComputeOffset(index) );
1213 m_RayIntersectionVoxels[0]
1214 = m_RayIntersectionVoxels[1]
1215 = m_RayIntersectionVoxels[2]
1216 = m_RayIntersectionVoxels[3] = NULL;
1222 itk::ExceptionObject err(__FILE__, __LINE__);
1223 err.SetLocation( ITK_LOCATION );
1224 err.SetDescription( "The ray traversal direction is unset "
1225 "- InitialiseVoxelPointers().");
1232 /* -----------------------------------------------------------------------
1233 IncrementVoxelPointers() - Increment the voxel pointers
1234 ----------------------------------------------------------------------- */
1236 template<class TInputImage, class TCoordRep>
1238 RayCastHelper<TInputImage, TCoordRep>
1239 ::IncrementVoxelPointers(void)
1241 double xBefore = m_Position3Dvox[0];
1242 double yBefore = m_Position3Dvox[1];
1243 double zBefore = m_Position3Dvox[2];
1245 m_Position3Dvox[0] += m_VoxelIncrement[0];
1246 m_Position3Dvox[1] += m_VoxelIncrement[1];
1247 m_Position3Dvox[2] += m_VoxelIncrement[2];
1249 int dx = ((int) m_Position3Dvox[0]) - ((int) xBefore);
1250 int dy = ((int) m_Position3Dvox[1]) - ((int) yBefore);
1251 int dz = ((int) m_Position3Dvox[2]) - ((int) zBefore);
1253 m_RayIntersectionVoxelIndex[0] += dx;
1254 m_RayIntersectionVoxelIndex[1] += dy;
1255 m_RayIntersectionVoxelIndex[2] += dz;
1257 int totalRayVoxelPlanes
1258 = dx + dy*m_NumberOfVoxelsInX + dz*m_NumberOfVoxelsInX*m_NumberOfVoxelsInY;
1260 m_RayIntersectionVoxels[0] += totalRayVoxelPlanes;
1261 m_RayIntersectionVoxels[1] += totalRayVoxelPlanes;
1262 m_RayIntersectionVoxels[2] += totalRayVoxelPlanes;
1263 m_RayIntersectionVoxels[3] += totalRayVoxelPlanes;
1267 /* -----------------------------------------------------------------------
1268 GetCurrentIntensity() - Get the intensity of the current ray point.
1269 ----------------------------------------------------------------------- */
1271 template<class TInputImage, class TCoordRep>
1273 RayCastHelper<TInputImage, TCoordRep>
1274 ::GetCurrentIntensity(void) const
1282 a = (double) (*m_RayIntersectionVoxels[0]);
1283 b = (double) (*m_RayIntersectionVoxels[1] - a);
1284 c = (double) (*m_RayIntersectionVoxels[2] - a);
1285 d = (double) (*m_RayIntersectionVoxels[3] - a - b - c);
1287 switch( m_TraversalDirection ) {
1288 case TRANSVERSE_IN_X: {
1289 y = m_Position3Dvox[1] - vcl_floor(m_Position3Dvox[1]);
1290 z = m_Position3Dvox[2] - vcl_floor(m_Position3Dvox[2]);
1293 case TRANSVERSE_IN_Y: {
1294 y = m_Position3Dvox[0] - vcl_floor(m_Position3Dvox[0]);
1295 z = m_Position3Dvox[2] - vcl_floor(m_Position3Dvox[2]);
1298 case TRANSVERSE_IN_Z: {
1299 y = m_Position3Dvox[0] - vcl_floor(m_Position3Dvox[0]);
1300 z = m_Position3Dvox[1] - vcl_floor(m_Position3Dvox[1]);
1304 itk::ExceptionObject err(__FILE__, __LINE__);
1305 err.SetLocation( ITK_LOCATION );
1306 err.SetDescription( "The ray traversal direction is unset "
1307 "- GetCurrentIntensity().");
1313 return a + b*y + c*z + d*y*z;
1316 /* -----------------------------------------------------------------------
1317 IncrementIntensities() - Increment the intensities of the current ray point
1318 ----------------------------------------------------------------------- */
1320 template<class TInputImage, class TCoordRep>
1322 RayCastHelper<TInputImage, TCoordRep>
1323 ::IncrementIntensities(double increment)
1325 short inc = (short) vcl_floor(increment + 0.5);
1330 *m_RayIntersectionVoxels[0] += inc;
1331 *m_RayIntersectionVoxels[1] += inc;
1332 *m_RayIntersectionVoxels[2] += inc;
1333 *m_RayIntersectionVoxels[3] += inc;
1339 /* -----------------------------------------------------------------------
1340 IntegrateAboveThreshold() - Integrate intensities above a threshold.
1341 ----------------------------------------------------------------------- */
1343 template<class TInputImage, class TCoordRep>
1345 RayCastHelper<TInputImage, TCoordRep>
1346 ::IntegrateAboveThreshold(double &integral, double threshold)
1349 // double posn3D_x, posn3D_y, posn3D_z;
1353 // Check if this is a valid ray
1358 /* Step along the ray as quickly as possible
1359 integrating the interpolated intensities. */
1361 for (m_NumVoxelPlanesTraversed=0;
1362 m_NumVoxelPlanesTraversed<m_TotalRayVoxelPlanes;
1363 m_NumVoxelPlanesTraversed++) {
1364 intensity = this->GetCurrentIntensity();
1366 if (intensity > threshold) {
1367 integral += intensity - threshold;
1369 this->IncrementVoxelPointers();
1372 /* The ray passes through the volume one plane of voxels at a time,
1373 however, if its moving diagonally the ray points will be further
1374 apart so account for this by scaling by the distance moved. */
1376 integral *= this->GetRayPointSpacing();
1381 /* -----------------------------------------------------------------------
1382 ZeroState() - Set the default (zero) state of the object
1383 ----------------------------------------------------------------------- */
1385 template<class TInputImage, class TCoordRep>
1387 RayCastHelper<TInputImage, TCoordRep>
1394 m_NumberOfVoxelsInX = 0;
1395 m_NumberOfVoxelsInY = 0;
1396 m_NumberOfVoxelsInZ = 0;
1398 m_VoxelDimensionInX = 0;
1399 m_VoxelDimensionInY = 0;
1400 m_VoxelDimensionInZ = 0;
1402 for (i=0; i<3; i++) {
1403 m_CurrentRayPositionInMM[i] = 0.;
1405 for (i=0; i<3; i++) {
1406 m_RayDirectionInMM[i] = 0.;
1408 for (i=0; i<3; i++) {
1409 m_RayVoxelStartPosition[i] = 0.;
1411 for (i=0; i<3; i++) {
1412 m_RayVoxelEndPosition[i] = 0.;
1414 for (i=0; i<3; i++) {
1415 m_VoxelIncrement[i] = 0.;
1417 m_TraversalDirection = UNDEFINED_DIRECTION;
1419 m_TotalRayVoxelPlanes = 0;
1420 m_NumVoxelPlanesTraversed = -1;
1422 for (i=0; i<4; i++) {
1423 m_RayIntersectionVoxels[i] = 0;
1425 for (i=0; i<3; i++) {
1426 m_RayIntersectionVoxelIndex[i] = 0;
1429 }; // end of anonymous namespace
1435 /**************************************************************************
1438 * Rest of this code is the actual RayCastInterpolateImageFunctionWithOrigin
1442 **************************************************************************/
1444 /* -----------------------------------------------------------------------
1446 ----------------------------------------------------------------------- */
1448 template<class TInputImage, class TCoordRep>
1449 RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1450 ::RayCastInterpolateImageFunctionWithOrigin()
1454 m_FocalPoint[0] = 0.;
1455 m_FocalPoint[1] = 0.;
1456 m_FocalPoint[2] = 0.;
1460 /* -----------------------------------------------------------------------
1462 ----------------------------------------------------------------------- */
1464 template<class TInputImage, class TCoordRep>
1466 RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1467 ::PrintSelf(std::ostream& os, Indent indent) const
1469 this->Superclass::PrintSelf(os,indent);
1471 os << indent << "Threshold: " << m_Threshold << std::endl;
1472 os << indent << "FocalPoint: " << m_FocalPoint << std::endl;
1473 os << indent << "Transform: " << m_Transform.GetPointer() << std::endl;
1474 os << indent << "Interpolator: " << m_Interpolator.GetPointer() << std::endl;
1478 /* -----------------------------------------------------------------------
1479 Evaluate at image index position
1480 ----------------------------------------------------------------------- */
1482 template<class TInputImage, class TCoordRep>
1483 typename RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1485 RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1486 ::Evaluate( const PointType& point ) const
1488 double integral = 0;
1490 OutputPointType transformedFocalPoint
1491 = m_Transform->TransformPoint( m_FocalPoint );
1493 DirectionType direction = transformedFocalPoint - point;
1495 RayCastHelper<TInputImage, TCoordRep> ray;
1496 ray.SetImage( this->m_Image );
1500 // (Aviv) Added support for images with non-zero origin
1501 // ray.SetRay(point, direction);
1502 ray.SetRay(point - this->m_Image->GetOrigin().GetVectorFromOrigin(), direction);
1503 ray.IntegrateAboveThreshold(integral, m_Threshold);
1505 return ( static_cast<OutputType>( integral ));
1508 template<class TInputImage, class TCoordRep>
1509 typename RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1511 RayCastInterpolateImageFunctionWithOrigin< TInputImage, TCoordRep >
1512 ::EvaluateAtContinuousIndex( const ContinuousIndexType& index ) const
1514 OutputPointType point;
1515 this->m_Image->TransformContinuousIndexToPhysicalPoint(index, point);
1517 return this->Evaluate( point );