cmtkAffineMultiChannelRegistrationFunctional.txx

Go to the documentation of this file.
00001 /*
00002 //
00003 //  Copyright 1997-2010 Torsten Rohlfing
00004 //
00005 //  Copyright 2004-2010 SRI International
00006 //
00007 //  This file is part of the Computational Morphometry Toolkit.
00008 //
00009 //  http://www.nitrc.org/projects/cmtk/
00010 //
00011 //  The Computational Morphometry Toolkit is free software: you can
00012 //  redistribute it and/or modify it under the terms of the GNU General Public
00013 //  License as published by the Free Software Foundation, either version 3 of
00014 //  the License, or (at your option) any later version.
00015 //
00016 //  The Computational Morphometry Toolkit is distributed in the hope that it
00017 //  will be useful, but WITHOUT ANY WARRANTY; without even the implied
00018 //  warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00019 //  GNU General Public License for more details.
00020 //
00021 //  You should have received a copy of the GNU General Public License along
00022 //  with the Computational Morphometry Toolkit.  If not, see
00023 //  <http://www.gnu.org/licenses/>.
00024 //
00025 //  $Revision: 2398 $
00026 //
00027 //  $LastChangedDate: 2010-10-05 14:54:37 -0700 (Tue, 05 Oct 2010) $
00028 //
00029 //  $LastChangedBy: torstenrohlfing $
00030 //
00031 */
00032 
00033 #include <System/cmtkThreadPool.h>
00034 
00035 namespace
00036 cmtk
00037 {
00038 
00041 
00042 template<class TMultiChannelMetricFunctional>
00043 void
00044 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00045 ::InitTransformation( const bool alignCenters )
00046 {
00047   this->m_Transformation.MakeIdentityXform();
00048   if ( alignCenters ) 
00049     {
00050     if ( this->m_ReferenceChannels.size() == 0 || this->m_FloatingChannels.size() == 0 )
00051       {
00052       StdErr << "ERROR: must set at least one reference and one floating channel image before calling\n"
00053                 << "       AffineMultiChannelRegistrationFunctional::InitTransformation()\n";
00054       exit( 1 );
00055       }
00056 
00057     Vector3D deltaCenter = ( this->m_ReferenceChannels[0]->GetCenterCropRegion() - this->m_FloatingChannels[0]->GetCenterCropRegion() );
00058     this->m_Transformation.SetXlate( deltaCenter.begin() );
00059     }
00060   
00061   Vector3D center = this->m_ReferenceChannels[0]->GetCenterCropRegion();
00062   this->m_Transformation.ChangeCenter( center );
00063 }
00064 
00065 template<class TMultiChannelMetricFunctional>
00066 typename AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>::ReturnType
00067 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00068 ::Evaluate() 
00069 {
00070   this->m_MetricData.Init( this );
00071 
00072   const TransformedVolumeAxes transformedAxes( *this->m_ReferenceChannels[0], &this->m_Transformation );
00073   
00074   const DataGrid::IndexType& dims = this->m_ReferenceDims;
00075   const int dimsX = dims[0], dimsY = dims[1], dimsZ = dims[2];
00076 
00077   this->m_VolumeClipper.SetDeltaX( transformedAxes[0][dimsX-1] - transformedAxes[0][0] );
00078   this->m_VolumeClipper.SetDeltaY( transformedAxes[1][dimsY-1] - transformedAxes[1][0] );
00079   this->m_VolumeClipper.SetDeltaZ( transformedAxes[2][dimsZ-1] - transformedAxes[2][0] );
00080   this->m_VolumeClipper.SetClippingBoundaries( this->m_FloatingCropRegion );
00081     
00082   int startZ, endZ;
00083   if ( this->ClipZ( this->m_VolumeClipper, transformedAxes[2][0], startZ, endZ ) ) 
00084     {
00085     startZ = std::max<int>( startZ, this->m_ReferenceCropRegion.From()[2] );
00086     endZ = std::min<int>( endZ, this->m_ReferenceCropRegion.To()[2] );
00087 
00088     ThreadPool& threadPool = ThreadPool::GetGlobalThreadPool();
00089     const size_t numberOfThreads = threadPool.GetNumberOfThreads();
00090     const size_t numberOfTasks = 4 * numberOfThreads - 3;
00091 
00092     std::vector<typename Self::EvaluateThreadParameters> threadParams( numberOfTasks );
00093     for ( size_t thread = 0; thread < numberOfTasks; ++thread )
00094       {      
00095       threadParams[thread].thisObject = this;
00096       threadParams[thread].m_TransformedAxes = &transformedAxes;
00097       threadParams[thread].m_StartZ = startZ;
00098       threadParams[thread].m_EndZ = endZ;
00099       }
00100     threadPool.Run( Self::EvaluateThreadFunction, threadParams );
00101     }
00102     
00103   return this->GetMetric( this->m_MetricData );
00104 }
00105       
00106 template<class TMultiChannelMetricFunctional>
00107 void
00108 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00109 ::EvaluateThreadFunction( void* args, const size_t taskIdx, const size_t taskCnt, const size_t, const size_t  ) 
00110 {
00111   typename Self::EvaluateThreadParameters* params = static_cast<typename Self::EvaluateThreadParameters*>( args );
00112   
00113   Self* This = params->thisObject;
00114   const Self* constThis = This;
00115   
00116   typename Self::MetricData metricData;
00117   metricData.Init( This );
00118   
00119   const Vector3D *transformedAxesX = (*params->m_TransformedAxes)[0];
00120   const Vector3D *transformedAxesY = (*params->m_TransformedAxes)[1];
00121   const Vector3D *transformedAxesZ = (*params->m_TransformedAxes)[2];
00122 
00123   const DataGrid::IndexType& dims = constThis->m_ReferenceDims;
00124   const int dimsX = dims[0], dimsY = dims[1];
00125 
00126   Vector3D pFloating, rowStart;
00127 
00128   // Loop over all remaining planes
00129   for ( int pZ = params->m_StartZ + taskIdx; pZ < params->m_EndZ; pZ += taskCnt ) 
00130     {
00131     // Offset of current reference voxel
00132     int r = pZ * dimsX * dimsY;
00133     Vector3D planeStart = transformedAxesZ[pZ];
00134     
00135     int startY, endY;
00136     if ( constThis->ClipY( constThis->m_VolumeClipper, planeStart, startY, endY ) ) 
00137       {   
00138       startY = std::max<int>( startY, constThis->m_ReferenceCropRegion.From()[1] );
00139       endY = std::min<int>( endY, constThis->m_ReferenceCropRegion.To()[1] );
00140       r += startY * dimsX;
00141       
00142       // Loop over all remaining rows
00143       for ( int pY = startY; pY<endY; ++pY ) 
00144         {
00145         (rowStart = planeStart) += transformedAxesY[pY];
00146         
00147         int startX, endX;
00148         if ( constThis->ClipX( constThis->m_VolumeClipper, rowStart, startX, endX ) ) 
00149           {
00150           startX = std::max<int>( startX, constThis->m_ReferenceCropRegion.From()[0] );
00151           endX = std::min<int>( endX, constThis->m_ReferenceCropRegion.To()[0] );
00152           
00153           r += startX;
00154           // Loop over all remaining voxels in current row
00155           for ( int pX = startX; pX<endX; ++pX, ++r ) 
00156             {
00157             (pFloating = rowStart) += transformedAxesX[pX];
00158             
00159             // Continue metric computation.
00160             This->ContinueMetric( metricData, r, pFloating );
00161             }
00162           r += (dimsX-endX);
00163           } 
00164         else
00165           {
00166           r += dimsX;
00167           }
00168         }
00169       
00170       r += (dimsY-endY) * dimsX;
00171       } 
00172     else
00173       {
00174       r += dimsY * dimsX;
00175       }
00176     }
00177 
00178 #ifdef CMTK_BUILD_SMP
00179   This->m_MetricDataMutex.Lock();
00180 #endif
00181   This->m_MetricData += metricData;
00182 #ifdef CMTK_BUILD_SMP
00183   This->m_MetricDataMutex.Unlock();
00184 #endif
00185 }
00186 
00187 template<class TMultiChannelMetricFunctional>
00188 bool
00189 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00190 ::ClipZ ( const VolumeClipping& clipper, const Vector3D& origin, int& start, int& end ) const
00191 {
00192   // perform clipping
00193   Types::Coordinate fromFactor, toFactor;
00194   if (! clipper.ClipZ( fromFactor, toFactor, origin ) )
00195     return false;
00196   
00197   // there is an intersection: Look up the corresponding grid indices
00198   start = static_cast<int>( (this->m_ReferenceDims[2]-1)*fromFactor );
00199   end = 1+std::min( (int)(this->m_ReferenceDims[2]-1), (int)(1 + ((this->m_ReferenceDims[2]-1)*toFactor) ) );
00200   
00201   // finally, apply cropping boundaries of the reference volume
00202   start = std::max<int>( start, this->m_ReferenceCropRegion.From()[2] );
00203   end = std::min<int>( end, this->m_ReferenceCropRegion.To()[2] );
00204   
00205   // return true iff index range is non-empty.
00206   return (start < end );
00207 }
00208 
00209 template<class TMultiChannelMetricFunctional>
00210 bool
00211 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00212 ::ClipX ( const VolumeClipping& clipper, const Vector3D& origin, int& start, int& end ) const
00213 {
00214   // perform clipping
00215   Types::Coordinate fromFactor, toFactor;
00216   if ( ! clipper.ClipX( fromFactor, toFactor, origin, 0, 2, false, true ) )
00217     return false;
00218   
00219   fromFactor = std::min<Types::Coordinate>( 1.0, fromFactor );
00220   
00221   // there is an intersection: Look up the corresponding grid indices
00222   start = std::max( 0, (int)((this->m_ReferenceDims[0]-1)*fromFactor)-1 );
00223   while ( ( start*this->m_ReferenceChannels[0]->m_Delta[0] < fromFactor*this->m_ReferenceSize[0]) && ( start < this->m_ReferenceDims[0] ) ) 
00224     ++start;
00225   
00226   if ( (toFactor > 1.0) || (start == this->m_ReferenceDims[0]) ) 
00227     {
00228     end = this->m_ReferenceDims[0];
00229     } 
00230   else
00231     {
00232     end = std::min( this->m_ReferenceDims[0]-2, (int)(1 + (this->m_ReferenceDims[0]-1)*toFactor));
00233     while ( end*this->m_ReferenceChannels[0]->m_Delta[0] > toFactor*this->m_ReferenceSize[0] ) // 'if' not sufficient!  
00234       --end;
00235     ++end; // otherwise end=1+min(...) and ...[0][end-1] above!!
00236     }
00237   
00238   // finally, apply cropping boundaries of the reference volume
00239   start = std::max<int>( start, this->m_ReferenceCropRegion.From()[0] );
00240   end = std::min<int>( end, this->m_ReferenceCropRegion.To()[0] );
00241   
00242   // return true iff index range is non-empty.
00243   return (start < end );
00244 }
00245 
00246 template<class TMultiChannelMetricFunctional>
00247 bool
00248 AffineMultiChannelRegistrationFunctional<TMultiChannelMetricFunctional>
00249 ::ClipY ( const VolumeClipping& clipper, const Vector3D& origin, int& start, int& end ) const
00250 {
00251   // perform clipping
00252   Types::Coordinate fromFactor, toFactor;
00253   if ( !clipper.ClipY( fromFactor, toFactor, origin ) )
00254     return false;
00255   
00256   // there is an intersection: Look up the corresponding grid indices
00257   start = static_cast<int>( (this->m_ReferenceDims[1]-1)*fromFactor );
00258   
00259   if ( toFactor > 1.0 ) 
00260     {
00261     end = this->m_ReferenceDims[1];
00262     } 
00263   else
00264     {
00265     end = 1+std::min( this->m_ReferenceDims[1]-1, (int)(1+(this->m_ReferenceDims[1]-1)*toFactor ) );
00266     }
00267   // finally, apply cropping boundaries of the reference volume
00268   start = std::max<int>( start, this->m_ReferenceCropRegion.From()[1] );
00269   end = std::min<int>( end, this->m_ReferenceCropRegion.To()[1] );
00270   
00271   // return true iff index range is non-empty.
00272   return (start < end );
00273 }
00274 
00275 } // namespace cmtk
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines