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