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 <algorithm>
00034
00035 #include <Base/cmtkHistogramBase.h>
00036
00037 namespace
00038 cmtk
00039 {
00040
00041 template <class TInterpolator>
00042 void
00043 InverseInterpolationVolumeReconstruction<TInterpolator>
00044 ::Interpolation( const ap::real_1d_array& reconstructedPixelArray )
00045 {
00046 this->m_InterpolatedPassImages.clear();
00047 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00048 {
00049 const UniformVolume* passImage = this->m_OriginalPassImages[pass];
00050 UniformVolume::SmartPtr result( passImage->CloneGrid() );
00051 result->CreateDataArray( TYPE_FLOAT, true );
00052
00053 const DataGrid::IndexType& passImageDims = passImage->GetDims();
00054 const int passImageDimsX = passImageDims[0], passImageDimsY = passImageDims[1], passImageDimsZ = passImageDims[2];
00055
00056 const DataGrid::IndexType& correctedImageDims = this->m_CorrectedImage->GetDims();
00057 const int correctedImageDimsX = correctedImageDims[0], correctedImageDimsY = correctedImageDims[1], correctedImageDimsZ = correctedImageDims[2];
00058
00059 const AffineXform* passXform = dynamic_cast<const AffineXform*>( this->m_TransformationsToPassImages[pass].GetPtr() )->GetInverse();
00060
00061 #pragma omp parallel for
00062 for ( int x = 0; x < passImageDimsX; ++x )
00063 {
00064 UniformVolume::CoordinateVectorType v;
00065 int correctedImageGridPoint[3];
00066 Types::Coordinate from[3], to[3];
00067
00068 for ( int y = 0; y < passImageDimsY; ++y )
00069 {
00070 for ( int z = 0; z < passImageDimsZ; ++z )
00071 {
00072 Types::DataItem interpolatedData = 0;
00073 Types::Coordinate totalWeight = 0;
00074 v = passImage->GetGridLocation( x, y, z );
00075 passXform->ApplyInPlace( v );
00076
00077 if ( this->m_CorrectedImage->FindVoxel( v, correctedImageGridPoint, from, to ) )
00078 {
00079 const int xx = correctedImageGridPoint[0] + 1 - TInterpolator::RegionSizeLeftRight;
00080 const int yy = correctedImageGridPoint[1] + 1 - TInterpolator::RegionSizeLeftRight;
00081 const int zz = correctedImageGridPoint[2] + 1 - TInterpolator::RegionSizeLeftRight;
00082
00083 Types::DataItem data;
00084 Types::Coordinate difference[3];
00085 Types::Coordinate interpolationWeights[3][2 * TInterpolator::RegionSizeLeftRight];
00086 for ( int n = 0; n < 3; ++n )
00087 {
00088 difference[n] = (v[n] - from[n]) / (to[n] - from[n]);
00089 for ( int m = 1-TInterpolator::RegionSizeLeftRight; m <= TInterpolator::RegionSizeLeftRight; ++m )
00090 {
00091 interpolationWeights[n][m+TInterpolator::RegionSizeLeftRight-1] = TInterpolator::GetWeight(m, difference[n]);
00092 }
00093 }
00094
00095 const int iMin = std::max( 0, -xx );
00096 const int iMax = std::min( 2 * TInterpolator::RegionSizeLeftRight, correctedImageDimsX - xx );
00097
00098 const int jMin = std::max( 0, -yy );
00099 const int jMax = std::min( 2 * TInterpolator::RegionSizeLeftRight, correctedImageDimsY - yy );
00100
00101 const int kMin = std::max( 0, -zz );
00102 const int kMax = std::min( 2 * TInterpolator::RegionSizeLeftRight, correctedImageDimsZ - zz );
00103
00104 for ( int k = kMin; k < kMax; ++k )
00105 {
00106 for ( int j = jMin; j < jMax; ++j )
00107 {
00108 const Types::Coordinate weightJK = interpolationWeights[1][j] * interpolationWeights[2][k];
00109 for ( int i = iMin; i < iMax; ++i )
00110 {
00111 const Types::Coordinate weightIJK = interpolationWeights[0][i] * weightJK;
00112 data = reconstructedPixelArray( 1+this->m_CorrectedImage->GetOffsetFromIndex( xx + i, yy + j, zz + k ) );
00113
00114 interpolatedData = interpolatedData + data * weightIJK;
00115 totalWeight += weightIJK;
00116 }
00117 }
00118 }
00119 }
00120
00121 if ( totalWeight == 0 )
00122 result->GetData()->SetPaddingAt( result->GetOffsetFromIndex( x, y, z ) );
00123 else
00124 result->SetDataAt( interpolatedData / totalWeight, x, y, z );
00125 }
00126 }
00127 }
00128 this->m_InterpolatedPassImages.push_back( result );
00129 }
00130 }
00131
00132 template <class TInterpolator>
00133 void
00134 InverseInterpolationVolumeReconstruction<TInterpolator>
00135 ::ComputeErrorGradientImage( ap::real_1d_array& g )
00136 {
00137 const UniformVolume* correctedImage = this->m_CorrectedImage;
00138 const size_t numberOfPixels = correctedImage->GetNumberOfPixels();
00139 for ( size_t i = 1; i <= numberOfPixels; ++i )
00140 g(i) = 0;
00141
00142 const DataGrid::IndexType& correctedImageDims = correctedImage->GetDims();
00143 const int correctedImageDimsX = correctedImageDims[0], correctedImageDimsY = correctedImageDims[1];
00144 const int correctedImageDimsXY = correctedImageDimsX*correctedImageDimsY;
00145
00146 for ( int pass = 0; pass < this->m_NumberOfPasses; ++pass )
00147 {
00148 const UniformVolume* differencePassImage = this->m_DifferencePassImages[pass];
00149 const UniformVolume* interpolatedPassImage = this->m_InterpolatedPassImages[pass];
00150
00151 const AffineXform* transformationToPassImage = dynamic_cast<const AffineXform*>( this->m_TransformationsToPassImages[pass].GetPtr() );
00152 const AffineXform* inverseTransformationToPassImage = transformationToPassImage->GetInverse();
00153 const DataGrid::IndexType& passImageDims = this->m_InterpolatedPassImages[pass]->GetDims();
00154
00155 const Types::Coordinate passImageWeight = this->m_PassWeights[pass];
00156
00157 if ( passImageWeight > 0 )
00158 {
00159 #pragma omp parallel for
00160 for ( size_t offset = 0; offset < numberOfPixels; ++offset )
00161 {
00162 const int correctedImageCurrentGridPoint[3] =
00163 { (offset % correctedImageDimsXY) % correctedImageDimsX, (offset % correctedImageDimsXY) / correctedImageDimsX, (offset / correctedImageDimsXY) };
00164
00165 int passImageDependentRegion[6];
00166 this->GetPassImageDependentPixelRegion( passImageDependentRegion, correctedImage, correctedImageCurrentGridPoint, interpolatedPassImage, transformationToPassImage, passImageDims );
00167
00168 Types::DataItem gradientData = 0;
00169 Types::Coordinate from[3], to[3];
00170 for (int k = passImageDependentRegion[2]; k <= passImageDependentRegion[5]; ++k)
00171 {
00172 for (int j = passImageDependentRegion[1]; j <= passImageDependentRegion[4]; ++j)
00173 {
00174 for (int i = passImageDependentRegion[0]; i <= passImageDependentRegion[3]; ++i)
00175 {
00176 Types::DataItem differenceData;
00177 if ( differencePassImage->GetDataAt( differenceData, i, j, k ) && (differenceData !=0) )
00178 {
00179 Types::DataItem weight = 0;
00180
00181 UniformVolume::CoordinateVectorType v = interpolatedPassImage->GetGridLocation( i, j, k );
00182 inverseTransformationToPassImage->ApplyInPlace( v );
00183
00184 int correctedImageGridPoint[3];
00185 if ( correctedImage->FindVoxel( v, correctedImageGridPoint, from, to ) )
00186 {
00187 const int correctedImageDifference[3] =
00188 {
00189 correctedImageCurrentGridPoint[0] - correctedImageGridPoint[0],
00190 correctedImageCurrentGridPoint[1] - correctedImageGridPoint[1],
00191 correctedImageCurrentGridPoint[2] - correctedImageGridPoint[2],
00192 };
00193
00194 if ( correctedImageDifference[0] > -TInterpolator::RegionSizeLeftRight && correctedImageDifference[1] > -TInterpolator::RegionSizeLeftRight &&
00195 correctedImageDifference[2] > -TInterpolator::RegionSizeLeftRight && correctedImageDifference[0] <= TInterpolator::RegionSizeLeftRight &&
00196 correctedImageDifference[1] <= TInterpolator::RegionSizeLeftRight && correctedImageDifference[2] <= TInterpolator::RegionSizeLeftRight )
00197 {
00198 weight = passImageWeight;
00199 for ( int n = 0; n < 3; ++n )
00200 {
00201 const Types::Coordinate relative = (v[n] - from[n]) / (to[n] - from[n]);
00202 weight *= TInterpolator::GetWeight( correctedImageDifference[n], relative );
00203 }
00204 }
00205 }
00206
00207 gradientData += weight * differenceData;
00208 }
00209 }
00210 }
00211 }
00212
00213 if ( this->m_FourthOrderError )
00214 g(offset+1) += 4 * (gradientData*gradientData*gradientData) / numberOfPixels;
00215 else
00216 g(offset+1) += 2 * gradientData / numberOfPixels;
00217 }
00218 }
00219 }
00220 }
00221
00222 template<class TInterpolator>
00223 void
00224 InverseInterpolationVolumeReconstruction<TInterpolator>
00225 ::GetPassImageDependentPixelRegion
00226 ( int* region, const UniformVolume* correctedImage, const int* currentCorrectedGridPoint,
00227 const UniformVolume* passImage, const AffineXform* transformationToPassImage, const DataGrid::IndexType& passImageDims )
00228 {
00229
00230 int corners[2][3];
00231 for ( int dim = 0; dim < 3; ++dim )
00232 {
00233 corners[0][dim] = std::max( currentCorrectedGridPoint[dim] - TInterpolator::RegionSizeLeftRight, 0 );
00234 corners[1][dim] = std::min( currentCorrectedGridPoint[dim] + TInterpolator::RegionSizeLeftRight, correctedImage->GetDims()[dim]-1 );
00235 }
00236
00237 UniformVolume::CoordinateVectorType corners3D[8];
00238 int neighborIdx = 0;
00239 for ( int a = 0; a < 2 ; ++a )
00240 {
00241 for ( int b = 0; b < 2 ; ++b )
00242 {
00243 for ( int c = 0; c < 2; ++c, ++neighborIdx )
00244 {
00245 corners3D[neighborIdx] = correctedImage->GetGridLocation( corners[a][0], corners[b][1], corners[c][2] );
00246 transformationToPassImage->ApplyInPlace( corners3D[neighborIdx] );
00247 }
00248 }
00249 }
00250
00251
00252 Vector3D bboxMin = corners3D[0];
00253 Vector3D bboxMax = corners3D[0];
00254 for ( int m = 1; m < 8; ++m )
00255 {
00256 for ( int o = 0; o < 3; ++o )
00257 {
00258 if ( corners3D[m][o] < bboxMin[o] )
00259 {
00260 bboxMin[o] = corners3D[m][o];
00261 }
00262 else
00263 if ( corners3D[m][o] > bboxMax[o] )
00264 {
00265 bboxMax[o] = corners3D[m][o];
00266 }
00267 }
00268 }
00269
00270
00271 passImage->GetVoxelIndexNoBounds( bboxMin, region+0 );
00272 passImage->GetVoxelIndexNoBounds( bboxMax, region+3 );
00273
00274
00275 for ( int dim = 0; dim < 3; ++dim )
00276 {
00277 region[dim] = std::max( region[dim], 0 );
00278
00279 region[dim+3] = std::min( region[dim+3]+1, passImageDims[dim]-1 );
00280 }
00281 }
00282
00283 template<class TInterpolator>
00284 void
00285 InverseInterpolationVolumeReconstruction<TInterpolator>
00286 ::FunctionAndGradient
00287 ::Evaluate( const ap::real_1d_array& x, ap::real_value_type& f, ap::real_1d_array& g )
00288 {
00289 this->m_Function->Interpolation( x );
00290 this->m_Function->ComputeApproximationError();
00291 this->m_Function->ComputeErrorGradientImage( g );
00292 const ap::real_value_type msd = f = this->m_Function->GetMeanSquaredError();
00293
00294 ap::real_value_type lnorm = 0;
00295 if ( this->m_Function->m_ConstraintWeightLNorm > 0 )
00296 {
00297 f += this->m_Function->m_ConstraintWeightLNorm * (lnorm = this->m_Function->ComputeCorrectedImageLaplacianNorm( x ));
00298 this->m_Function->AddLaplacianGradientImage( g, x, this->m_Function->m_ConstraintWeightLNorm );
00299 }
00300
00301 if ( this->m_Function->GetMaximumError() <= this->m_Function->m_LowestMaxError )
00302 {
00303 this->m_Function->m_LowestMaxError = this->m_Function->GetMaximumError();
00304 const int numberOfPixels = this->m_Function->m_CorrectedImage->GetNumberOfPixels();
00305 for ( int i = 1; i <= numberOfPixels; ++i )
00306 this->m_Function->m_CorrectedImage->SetDataAt( x(i), i-1 );
00307 this->m_Function->m_LowestMaxErrorImage = UniformVolume::SmartPtr( this->m_Function->m_CorrectedImage->Clone( true ) );
00308 }
00309
00310 std::cerr << "f " << f << " MSD " << msd
00311 << " MAX " << this->m_Function->GetMaximumError()
00312 << " KLD " << this->m_Function->GetOriginalToCorrectedImageKLD( x )
00313 << " LNORM " << lnorm << std::endl;
00314 }
00315
00316 }