1 /*=========================================================================
2 Program: vv http://www.creatis.insa-lyon.fr/rio/vv
5 - University of LYON http://www.universite-lyon.fr/
6 - Léon Bérard cancer center http://www.centreleonberard.fr
7 - CREATIS CNRS laboratory http://www.creatis.insa-lyon.fr
9 This software is distributed WITHOUT ANY WARRANTY; without even
10 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
11 PURPOSE. See the copyright notices for more information.
13 It is distributed under dual licence
15 - BSD See included LICENSE.txt file
16 - CeCILL-B http://www.cecill.info/licences/Licence_CeCILL-B_V1-en.html
17 ===========================================================================**/
18 #ifndef _CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX
19 #define _CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX
20 /* =========================================================================
22 @file itkBSplineInterpolateImageFunctionWithLUT.txx
23 @author jefvdmb@gmail.com
26 * CREATIS (Centre de Recherche et d'Applications en Traitement de l'Image).
27 All rights reserved. See Doc/License.txt or
28 http://www.creatis.insa-lyon.fr/Public/Gdcm/License.html for details.
29 * Léon Bérard cancer center, 28 rue Laënnec, 69373 Lyon cedex 08, France
30 * http://www.creatis.insa-lyon.fr/rio
32 This software is distributed WITHOUT ANY WARRANTY; without even the
33 implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
34 PURPOSE. See the above copyright notices for more information.
36 ========================================================================= */
39 //====================================================================
40 template <class TImageType, class TCoordRep, class TCoefficientType>
41 VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
42 VectorBSplineInterpolateImageFunctionWithLUT():Superclass()
45 SetLUTSamplingFactor(20);
47 mWeightsAreUpToDate = false;
50 //====================================================================
52 //====================================================================
53 template <class TImageType, class TCoordRep, class TCoefficientType>
54 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
55 SetLUTSamplingFactor(const int& s)
57 for(int i=0; i<TImageType::ImageDimension; i++) mSamplingFactors[i] = s;
58 mWeightsAreUpToDate = false;
61 //====================================================================
63 //====================================================================
64 template <class TImageType, class TCoordRep, class TCoefficientType>
65 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
66 SetLUTSamplingFactors(const SizeType& s)
68 for(int i=0; i<TImageType::ImageDimension; i++) mSamplingFactors[i] = s[i];
69 mWeightsAreUpToDate = false;
72 //====================================================================
74 //====================================================================
75 template <class TImageType, class TCoordRep, class TCoefficientType>
76 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
77 SetSplineOrder(const unsigned int& SplineOrder)
79 Superclass::SetSplineOrder(SplineOrder);
80 // Compute support and half size
81 static const int d = TImageType::ImageDimension;
82 for(int l=0; l<d; l++) {
83 mSplineOrders[l]= SplineOrder;
84 mSupport[l] = SplineOrder+1;
85 if (mSupport[l] % 2 == 0) { // support is even
86 mHalfSupport[l] = mSupport[l]/2-1;
87 } else mHalfSupport[l] = mSupport[l]/2; // support is odd (like cubic spline)
90 for(int l=0; l<d; l++) {
91 mSupportSize *= mSupport[l];
93 mWeightsAreUpToDate = false;
95 //====================================================================
98 //====================================================================
99 template <class TImageType, class TCoordRep, class TCoefficientType>
100 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
101 SetSplineOrders(const SizeType& SplineOrders)
103 mSplineOrders=SplineOrders;
105 // Compute support and half size
106 static const int d = TImageType::ImageDimension;
107 for(int l=0; l<d; l++) {
108 mSupport[l] = mSplineOrders[l]+1;
109 if (mSupport[l] % 2 == 0) { // support is even
110 mHalfSupport[l] = mSupport[l]/2-1;
111 } else mHalfSupport[l] = mSupport[l]/2; // support is odd (like cubic spline)
114 for(int l=0; l<d; l++) {
115 mSupportSize *= mSupport[l];
117 mWeightsAreUpToDate = false;
119 //====================================================================
121 //====================================================================
122 template <class TImageType, class TCoordRep, class TCoefficientType>
123 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
124 SetInputImage(const TImageType * inputData)
126 // JV Call superclass (decomposition filter is executeed each time!)
127 // JV Should call clitkVectorBSplineDecompositionFilterWithOBD to allow different order by dimension
128 Superclass::SetInputImage(inputData);
130 // Update the weightproperties
131 if (!inputData) return;
132 UpdateWeightsProperties();
136 //====================================================================
137 template <class TImageType, class TCoordRep, class TCoefficientType>
138 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
139 UpdateWeightsProperties()
142 // Compute Memory offset inside coefficients images (for looping over coefficients)
143 static const unsigned int d = TImageType::ImageDimension;
144 mInputMemoryOffset[0] = 1;
145 for(unsigned int l=1; l<d; l++) {
146 mInputMemoryOffset[l] =
147 mInputMemoryOffset[l-1]*this->m_Coefficients->GetLargestPossibleRegion().GetSize(l-1);
150 // Compute mSupportOffset according to input size
151 mSupportOffset.resize(mSupportSize);
152 mSupportIndex.resize(mSupportSize);
153 for(unsigned int l=0; l<d; l++) mSupportIndex[0][l] = 0;
154 for(unsigned int k=0; k<mSupportSize; k++) {
156 mSupportOffset[k] = itk::Index2Offset<TImageType::ImageDimension>(mSupportIndex[k], mInputMemoryOffset);
157 // next coefficient index
158 if (k != mSupportSize-1) {
159 for(unsigned int l=0; l<d; l++) mSupportIndex[k+1][l] = mSupportIndex[k][l];
163 mSupportIndex[k+1][l]++;
164 if (static_cast<unsigned int>(mSupportIndex[k+1][l]) == mSupport[l]) {
165 mSupportIndex[k+1][l] = 0;
173 // Compute BSpline weights if not up to date
174 if (!mWeightsAreUpToDate)
175 UpdatePrecomputedWeights();
177 //====================================================================
179 //====================================================================
180 template <class TImageType, class TCoordRep, class TCoefficientType>
181 void VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
182 UpdatePrecomputedWeights()
184 mWeightsCalculator.SetSplineOrders(mSplineOrders);
185 mWeightsCalculator.SetSamplingFactors(mSamplingFactors);
186 mWeightsCalculator.ComputeTensorProducts();
187 mWeightsAreUpToDate = true;
189 //====================================================================
191 //====================================================================
192 template <class TImageType, class TCoordRep, class TCoefficientType>
193 typename VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::IndexType
194 VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
195 GetSampleIndexOfPixelPosition(const ContinuousIndexType & x, IndexType & EvaluateIndex) const
199 WARNING : sometimes, a floating number x could not really be
200 represented in memory. In this case, the difference between x and
201 floor(x) can be almost 1 (instead of 0). So we take into account
202 such special case, otherwise it could lead to annoying results.
204 // static const TCoefficientType tiny = 1.0e-7;
207 for(int l=0; l<TImageType::ImageDimension; l++) {
208 // Compute t1 = distance to floor
209 TCoefficientType t1 = x[l]- vcl_floor(x[l]);
211 // Compute index in precomputed weights table
212 TCoefficientType t2 = mSamplingFactors[l]*t1;
213 index[l] = (IndexValueType)itk::Math::Floor<IndexValueType,TCoefficientType>(t2);
215 // For even order : test if too close to 0.5 (but lower). In this
216 // case : take the next coefficient
217 if (!(mSplineOrders[l] & 1)) {
219 if (mSamplingFactors[l] & 1) {
220 if (index[l] == (int) mSamplingFactors[l]/2+1) EvaluateIndex[l] = EvaluateIndex[l]+1;
223 else if (index[l] == (int) mSamplingFactors[l]/2) EvaluateIndex[l] = EvaluateIndex[l]+1;
227 // When to close to 1, take the next coefficient for odd order, but
228 // only change index for odd
229 if (index[l] == (int)mSamplingFactors[l]) {
231 if (mSplineOrders[l] & 1) EvaluateIndex[l] = EvaluateIndex[l]+1;
240 //====================================================================
242 //====================================================================
243 template <class TImageType, class TCoordRep, class TCoefficientType>
244 typename VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::OutputType
245 VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
246 EvaluateAtContinuousIndex(const ContinuousIndexType & x) const
248 // JV Compute BSpline weights if not up to date! Problem const: pass image as last
249 // if (!mWeightsAreUpToDate) UpdatePrecomputedWeights();
250 // For shorter coding
251 static const unsigned int d = TImageType::ImageDimension;
253 // Compute the index of the first interpolation coefficient in the coefficient image
254 IndexType evaluateIndex;
256 for (unsigned int l=0; l<d; l++) {
257 if (mSplineOrders[l] & 1) { // Use this index calculation for odd splineOrder (like cubic)
258 indx = (long)vcl_floor(x[l]) - mSplineOrders[l] / 2 ; //this->m_SplineOrder / 2;
259 evaluateIndex[l] = indx;
260 } else { // Use this index calculation for even splineOrder
261 if (mSplineOrders[l] == 0) evaluateIndex[l] = itk::Math::Round<long, typename ContinuousIndexType::ValueType>(x[l]);
263 indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2;
264 evaluateIndex[l] = indx;
269 // Compute index of precomputed weights and get pointer to first weights
270 const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, evaluateIndex);
271 const TCoefficientType * pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex);
274 bool boundaryCase = false;
275 for (unsigned int l=0; l<d; l++) {
276 if ((evaluateIndex[l] < 0) ||
277 (evaluateIndex[l]+mSupport[l]) >= this->m_Coefficients->GetLargestPossibleRegion().GetSize(l)) {
282 // Pointer to support offset
283 const int * psupport;
285 // Special case for boundary (to be changed ....)
286 std::vector<int> correctedSupportOffset;
288 std::vector<IndexType> correctedSupportIndex;//(mSupportSize);
289 correctedSupportIndex.resize(mSupportSize);
290 correctedSupportOffset.resize(mSupportSize);
291 for(unsigned int i=0; i<mSupportSize; i++) {
292 for (unsigned int l=0; l<d; l++) {
293 long a = mSupportIndex[i][l] + evaluateIndex[l];
294 long b = this->m_Coefficients->GetLargestPossibleRegion().GetSize(l);
297 correctedSupportIndex[i][l] = -a - d2*(-a/d2) - evaluateIndex[l];//mSupportIndex[i][l]-a;
300 correctedSupportIndex[i][l] = d2 - a - evaluateIndex[l];
302 correctedSupportIndex[i][l] = mSupportIndex[i][l]; //a - d2*(a/d2) - EvaluateIndex[l];
306 correctedSupportIndex[i][l] = d2 - a - EvaluateIndex[l];//mSupportIndex[i][l] - (a-(b-1));
309 correctedSupportIndex[i][l] = mSupportIndex[i][l];
314 // DD(correctedSupportIndex[i]);
315 correctedSupportOffset[i] = itk::Index2Offset<TImageType::ImageDimension>(correctedSupportIndex[i], mInputMemoryOffset);
317 psupport = &correctedSupportOffset[0];
319 psupport = &mSupportOffset[0];
322 // Get pointer to first coefficient. Even if in some boundary cases,
323 // EvaluateIndex is out of the coefficient image,
325 const CoefficientImagePixelType * pcoef = &(this->m_Coefficients->GetPixel(evaluateIndex));
327 // Main loop over BSpline support
328 CoefficientImagePixelType interpolated = itk::NumericTraits<CoefficientImagePixelType>::Zero;;
329 for (unsigned int p=0; p<mSupportSize; p++) {
330 interpolated += pcoef[*psupport] * (*pweights);
335 // Return interpolated value
336 return(interpolated);
338 //====================================================================
341 //====================================================================
342 template <class TImageType, class TCoordRep, class TCoefficientType>
344 VectorBSplineInterpolateImageFunctionWithLUT<TImageType,TCoordRep,TCoefficientType>::
345 EvaluateWeightsAtContinuousIndex(const ContinuousIndexType& x, const TCoefficientType ** pweights, IndexType & evaluateIndex)const
348 // JV Compute BSpline weights if not up to date! Problem const: pass image as last
349 // if (!mWeightsAreUpToDate) UpdatePrecomputedWeights();
351 // For shorter coding
352 static const unsigned int d = TImageType::ImageDimension;
354 // Compute the index of the first interpolation coefficient in the coefficient image
356 for (unsigned int l=0; l<d; l++) {
357 if (mSplineOrders[l] & 1) { // Use this index calculation for odd splineOrder (like cubic)
358 indx = (long)vcl_floor(x[l]) - mSplineOrders[l] / 2 ; //this->m_SplineOrder / 2;
359 evaluateIndex[l] = indx;
360 } else { // Use this index calculation for even splineOrder
361 if (mSplineOrders[l] == 0) evaluateIndex[l] = itk::Math::Round<long, typename ContinuousIndexType::ValueType>(x[l]);
363 indx = (long)vcl_floor((x[l]+ 0.5)) - mSplineOrders[l] / 2; //this->m_SplineOrder / 2;
364 evaluateIndex[l] = indx;
369 // Compute index of precomputed weights and get pointer to first weights
370 const IndexType weightIndex = GetSampleIndexOfPixelPosition(x, evaluateIndex);
371 *pweights = mWeightsCalculator.GetFirstTensorProduct(weightIndex);
374 //====================================================================
381 #endif //_CLITKVECTORBSPLINEINTERPOLATEIMAGEFUNCTIONWITHLUT_TXX