00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
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
00129 for ( int pZ = params->m_StartZ + taskIdx; pZ < params->m_EndZ; pZ += taskCnt )
00130 {
00131
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
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
00155 for ( int pX = startX; pX<endX; ++pX, ++r )
00156 {
00157 (pFloating = rowStart) += transformedAxesX[pX];
00158
00159
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
00193 Types::Coordinate fromFactor, toFactor;
00194 if (! clipper.ClipZ( fromFactor, toFactor, origin ) )
00195 return false;
00196
00197
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
00202 start = std::max<int>( start, this->m_ReferenceCropRegion.From()[2] );
00203 end = std::min<int>( end, this->m_ReferenceCropRegion.To()[2] );
00204
00205
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
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
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] )
00234 --end;
00235 ++end;
00236 }
00237
00238
00239 start = std::max<int>( start, this->m_ReferenceCropRegion.From()[0] );
00240 end = std::min<int>( end, this->m_ReferenceCropRegion.To()[0] );
00241
00242
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
00252 Types::Coordinate fromFactor, toFactor;
00253 if ( !clipper.ClipY( fromFactor, toFactor, origin ) )
00254 return false;
00255
00256
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
00268 start = std::max<int>( start, this->m_ReferenceCropRegion.From()[1] );
00269 end = std::min<int>( end, this->m_ReferenceCropRegion.To()[1] );
00270
00271
00272 return (start < end );
00273 }
00274
00275 }