1 #ifndef _ITKINTERPOLATEIMAGEFUNCTIONWITHLUT_
2 #define _ITKINTERPOLATEIMAGEFUNCTIONWITHLUT_
4 /* =========================================================================
6 @file itkBSplineInterpolateImageFunctionWithLUT.txx
7 @author David Sarrut <david.sarrut@creatis.insa-lyon.fr>
10 * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image).
11 All rights reserved. See Doc/License.txt or
12 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
13 * L�on B�rard cancer center, 28 rue La�nnec, 69373 Lyon cedex 08, France
14 * http://www.creatis.insa-lyon.fr/rio
16 This software is distributed WITHOUT ANY WARRANTY; without even the
17 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
18 PURPOSE. See the above copyright notices for more information.
20 ========================================================================= */
21 #include "itkCastImageFilter.h"
23 //====================================================================
24 template <class TImageType, class TCoordRep, class TCoefficientType>
25 BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
26 BSplineInterpolateImageFunctionWithLUT():Superclass() {
28 for(int i=0; i<TImageType::ImageDimension; i++) mOutputSpacing[i] = -1;
29 SetLUTSamplingFactor(10);
31 mWeightsAreUpToDate = false;
32 // Following need to be pointer beacause values are updated into
34 mIntrinsecError = new double;
35 mNumberOfError = new long;
36 mIntrinsecErrorMax = new double;
39 //====================================================================
41 //====================================================================
42 template <class TImageType, class TCoordRep, class TCoefficientType>
43 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
44 SetLUTSamplingFactor(int s) {
45 for(int i=0; i<TImageType::ImageDimension; i++) mSamplingFactors[i] = s;
46 mWeightsAreUpToDate = false;
49 //====================================================================
51 //====================================================================
52 template <class TImageType, class TCoordRep, class TCoefficientType>
53 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
54 SetOutputSpacing(const SpacingType & s) {
55 for(int i=0; i<TImageType::ImageDimension; i++)
56 mOutputSpacing[i] = s[i];
57 mWeightsAreUpToDate = false;
59 //====================================================================
61 //====================================================================
62 template <class TImageType, class TCoordRep, class TCoefficientType>
63 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
64 SetSplineOrder(unsigned int SplineOrder) {
65 Superclass::SetSplineOrder(SplineOrder);
66 // Compute support and half size
67 static const int d = TImageType::ImageDimension;
68 for(int l=0; l<d; l++) {
69 mSplineOrders[l]= SplineOrder;
70 mSupport[l] = SplineOrder+1;
71 if (mSupport[l] % 2 == 0) { // support is even
72 mHalfSupport[l] = mSupport[l]/2-1;
74 else mHalfSupport[l] = mSupport[l]/2; // support is odd (like cubic spline)
77 for(int l=0; l<d; l++) {
78 mSupportSize *= mSupport[l];
80 mWeightsAreUpToDate = false;
82 //====================================================================
85 //====================================================================
86 template <class TImageType, class TCoordRep, class TCoefficientType>
87 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
88 SetSplineOrders(SizeType SplineOrders) {
89 mSplineOrders=SplineOrders;
91 // Compute support and half size
92 static const int d = TImageType::ImageDimension;
93 for(int l=0; l<d; l++) {
94 mSupport[l] = mSplineOrders[l]+1;
95 if (mSupport[l] % 2 == 0) { // support is even
96 mHalfSupport[l] = mSupport[l]/2-1;
98 else mHalfSupport[l] = mSupport[l]/2; // support is odd (like cubic spline)
101 for(int l=0; l<d; l++) {
102 mSupportSize *= mSupport[l];
104 mWeightsAreUpToDate = false;
106 //====================================================================
108 //====================================================================
109 template <class TImageType, class TCoordRep, class TCoefficientType>
110 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
111 SetInputImage(const TImageType * inputData) {
113 // Call superclass SetInputImage and return if input is null
117 // this->InterpolateImageFunction<TImageType,TCoordRep>::SetInputImage(inputData);
119 //==============================
121 Superclass::SetInputImage(inputData);
124 //==============================
126 // If inputData is not float/double, we do not want to set
127 // mInputIsCoef to true, but the compiler goes here ...
129 if (typeid(typename TImageType::PixelType) != typeid(TCoefficientType)) {
130 std::cerr << "Input should be float or double to be set as 'coefficients' with SetInputImageIsCoefficient(true) and should be the same type than TCoefficientType" << std::endl;
134 itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension);
135 typedef Image<TCoefficientType, ImageDimension> CoefficientImageType;
136 typedef itk::CastImageFilter< TImageType, CoefficientImageType> CastFilterType;
137 typename CastFilterType::Pointer castFilter=CastFilterType::New();
138 castFilter->SetInput(inputData);
139 castFilter->Update();
140 this->m_Coefficients=castFilter->GetOutput();
141 if ( this->m_Coefficients.IsNotNull())
142 this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize();
145 // //JV input should be double or float. To keep it generic: cast to the CoefficientImageType
146 // /** Dimension underlying input image. */
147 // itkStaticConstMacro(ImageDimension, unsigned int, Superclass::ImageDimension);
148 // /** Internal Coefficient typedef support */
149 // DD( ImageDimension);
150 // typedef Image<TCoefficientType,ImageDimension> CoefficientImageType;
151 // typedef itk::CastImageFilter< TImageType, CoefficientImageType> CastFilterType;
152 // typename CastFilterType::Pointer castFilter=CastFilterType::New();
153 // castFilter->SetInput(inputData);
154 // castFilter->Update();
155 // DS this->InterpolateImageFunction<TImageType,TCoordRep>::m_Coefficients = inputData;
157 // //JV cast to the coeff type, don't tell my mother
158 // this->InterpolateImageFunction<TImageType,TCoordRep>::SetInputImage(inputData);
159 // this->m_Coefficients=castFilter->GetOutput();
160 // DS ?????? this->m_Coefficients = inputData;
162 // // //============================== old not generic solution
163 // // this->InterpolateImageFunction<TImageType,TCoordRep>::SetInputImage(inputData);
164 // // DS this->InterpolateImageFunction<TImageType,TCoordRep>::m_Coefficients = inputData;
165 // // this->m_Coefficients = inputData;
166 // // //==============================
167 // if ( this->m_Coefficients.IsNotNull()) {
168 // this->m_DataLength = this->m_Coefficients->GetBufferedRegion().GetSize();
173 if (!inputData) return;
174 // mCoefficientTimer = t;
176 // Compute Memory offset inside coefficients images (for looping over coefficients)
177 static const int d = TImageType::ImageDimension;
178 mInputMemoryOffset[0] = 1;
179 for(int l=1; l<d; l++) {
180 mInputMemoryOffset[l] =
181 mInputMemoryOffset[l-1]*this->m_Coefficients->GetLargestPossibleRegion().GetSize(l-1);
184 // Compute mSupportOffset according to input size
185 mSupportOffset.resize(mSupportSize);
186 mSupportIndex.resize(mSupportSize);
187 for(int l=0; l<d; l++) mSupportIndex[0][l] = 0;
188 for(unsigned int k=0; k<mSupportSize; k++) {
190 mSupportOffset[k] = Index2Offset<TImageType::ImageDimension>(mSupportIndex[k], mInputMemoryOffset);
191 // next coefficient index
192 if (k != mSupportSize-1) {
193 for(int l=0; l<d; l++) mSupportIndex[k+1][l] = mSupportIndex[k][l];
197 mSupportIndex[k+1][l]++;
198 if (mSupportIndex[k+1][l] == (int)mSupport[l]) { //ds supportindex=uint et support=int
199 mSupportIndex[k+1][l] = 0;
208 for(int l=0; l<d; l++) {
209 if (mOutputSpacing[l] == -1) {
210 std::cerr << "Please use SetOutputSpacing before using bslut interpolator" << std::endl;
215 // Compute BSpline weights if not up to date
216 if (!mWeightsAreUpToDate) UpdatePrecomputedWeights();
219 *mIntrinsecErrorMax = *mIntrinsecError = 0.0;
222 //====================================================================
224 //====================================================================
225 template <class TImageType, class TCoordRep, class TCoefficientType>
226 void BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
227 UpdatePrecomputedWeights() {
228 // mLUTTimer.Reset();
229 // mLUTTimer.Start();
230 mWeightsCalculator.SetSplineOrders(mSplineOrders);
231 mWeightsCalculator.SetSamplingFactors(mSamplingFactors);
232 mWeightsCalculator.ComputeTensorProducts();
233 mWeightsAreUpToDate = true;
235 // coef = new TCoefficientType[mSupportSize];
236 // mCorrectedSupportIndex.resize(mSupportSize);
237 // mCorrectedSupportOffset.resize(mSupportSize);
239 // mLUTTimer.Print("LUT \t");
241 //====================================================================
243 //====================================================================
244 template <class TImageType, class TCoordRep, class TCoefficientType>
245 typename BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::IndexType
246 BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
247 GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const {
250 WARNING : sometimes, a floating number x could not really be
251 represented in memory. In this case, the difference between x and
252 floor(x) can be almost 1 (instead of 0). So we take into account
253 such special case, otherwise it could lead to annoying results.
255 // static const TCoefficientType tiny = 1.0e-7;
258 for(int l=0; l<TImageType::ImageDimension; l++) {
259 // bool mChange = false;
261 // Compute t1 = distance to floor
262 TCoefficientType t1 = x[l]- vcl_floor(x[l]);
264 // Compute index in precomputed weights table
265 TCoefficientType t2 = mSamplingFactors[l]*t1;
266 index[l] = (IndexValueType)lrint(t2);
268 // For even order : test if too close to 0.5 (but lower). In this
269 // case : take the next coefficient
270 if (!(mSplineOrders[l] & 1)) {
272 if (mSamplingFactors[l] & 1) {
273 if (index[l] == (int) mSamplingFactors[l]/2+1) EvaluateIndex[l] = EvaluateIndex[l]+1;
275 else if (index[l] == (int) mSamplingFactors[l]/2) EvaluateIndex[l] = EvaluateIndex[l]+1;
279 // Statistics (to be removed)
281 *mIntrinsecError += fabs(index[l]-t2);
283 if (fabs(index[l]-t2)> *mIntrinsecErrorMax) *mIntrinsecErrorMax = fabs(index[l]-t2);
286 // When to close to 1, take the next coefficient for ordd order, but
287 // only change index for odd
288 if (index[l] == (int)mSamplingFactors[l]) {
290 if (mSplineOrders[l] & 1) EvaluateIndex[l] = EvaluateIndex[l]+1;
297 //====================================================================
299 //====================================================================
300 template <class TImageType, class TCoordRep, class TCoefficientType>
301 typename BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::OutputType
302 BSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
303 EvaluateAtContinuousIndex(const ContinuousIndexType & x) const {
305 // For shorter coding
306 static const unsigned int d = TImageType::ImageDimension;
308 // Compute the indexe of the first interpolation coefficient in the
310 IndexType EvaluateIndex;
312 for (unsigned int l=0; l<d; l++) {
313 if (mSplineOrders[l] & 1) { // Use this index calculation for odd splineOrder (like cubic)
314 indx = (long)vcl_floor(x[l]) - mSplineOrders[l] / 2 ; //this->m_SplineOrder / 2;
315 EvaluateIndex[l] = indx;
317 else { // Use this index calculation for even splineOrder
318 if (mSplineOrders[l] == 0) EvaluateIndex[l] = (long)rint(x[l]);
320 indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2;
321 EvaluateIndex[l] = indx;
326 // Compute index of precomputed weights and get pointer to first weights
327 const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, EvaluateIndex);
328 const TCoefficientType * pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex);
331 bool mBoundaryCase = false;
332 for (unsigned int l=0; l<d; l++) {
333 if ((EvaluateIndex[l] < 0) ||
334 (EvaluateIndex[l]+mSupport[l]) >= this->m_Coefficients->GetLargestPossibleRegion().GetSize(l)) {
335 mBoundaryCase = true;
339 // Pointer to support offset
340 const int * psupport;
342 // Special case for boundary (to be changed ....)
343 std::vector<int> mCorrectedSupportOffset;//(mSupportSize);
346 //std::vector<TCoefficientType> coef(mSupportSize);
347 // DD(EvaluateIndex);
348 std::vector<IndexType> mCorrectedSupportIndex;//(mSupportSize);
349 mCorrectedSupportIndex.resize(mSupportSize);
350 mCorrectedSupportOffset.resize(mSupportSize);
351 for(unsigned int i=0; i<mSupportSize; i++) {
352 // DD(mSupportIndex[i]);
353 for (unsigned int l=0; l<d; l++) {
354 long a = mSupportIndex[i][l] + EvaluateIndex[l];
355 long b = this->m_Coefficients->GetLargestPossibleRegion().GetSize(l);
360 mCorrectedSupportIndex[i][l] = -a - d2*(-a/d2) - EvaluateIndex[l];//mSupportIndex[i][l]-a;
364 mCorrectedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];
367 mCorrectedSupportIndex[i][l] = mSupportIndex[i][l]; //a - d2*(a/d2) - EvaluateIndex[l];
371 mCorrectedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];//mSupportIndex[i][l] - (a-(b-1));
374 mCorrectedSupportIndex[i][l] = mSupportIndex[i][l];
379 // DD(mCorrectedSupportIndex[i]);
380 mCorrectedSupportOffset[i] = Index2Offset<TImageType::ImageDimension>(mCorrectedSupportIndex[i], mInputMemoryOffset);
382 // for (unsigned int l=0; l<d; l++) {
383 // EvaluateIndex[l] = EvaluateIndex[l] + mCorrectedSupportIndex[0][l];
385 // DD(EvaluateIndex);
386 psupport = &mCorrectedSupportOffset[0];
389 psupport = &mSupportOffset[0];
392 // Get pointer to first coefficient. Even if in some boundary cases,
393 // EvaluateIndex is out of the coefficient image,
394 const TCoefficientType * pcoef = &(this->m_Coefficients->GetPixel(EvaluateIndex));
396 // Main loop over BSpline support
397 TCoefficientType interpolated = 0.0;
398 for (unsigned int p=0; p<mSupportSize; p++) {
399 interpolated += pcoef[*psupport] * (*pweights);
404 // Return interpolated value
405 return(interpolated);
407 //====================================================================