All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Properties Friends Macros Groups Pages
Interpolator.cpp
Go to the documentation of this file.
1 /* Copyright (C) 2008 National Institute For Space Research (INPE) - Brazil.
2 
3  This file is part of the TerraLib - a Framework for building GIS enabled applications.
4 
5  TerraLib is free software: you can redistribute it and/or modify
6  it under the terms of the GNU Lesser General Public License as published by
7  the Free Software Foundation, either version 3 of the License,
8  or (at your option) any later version.
9 
10  TerraLib is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  GNU Lesser General Public License for more details.
14 
15  You should have received a copy of the GNU Lesser General Public License
16  along with TerraLib. See COPYING. If not, write to
17  TerraLib Team at <terralib-team@terralib.org>.
18  */
19 
20 /*!
21  \file terralib/raster/Interpolator.cpp
22 
23  \brief It interpolates one pixel based on a selected algorithm.
24 */
25 
26 // TerraLib
27 #include "Interpolator.h"
28 #include "Band.h"
29 #include "BandProperty.h"
30 #include "Utils.h"
31 #include "Exception.h"
32 
33 // STL
34 #include <cassert>
35 
36 #define BICUBIC_MODULE( x ) ( ( x < 0 ) ? ( -1 * x ) : x )
37 #define BICUBIC_K1( x , a ) ( ( ( a + 2 ) * x * x * x ) - \
38  ( ( a + 3 ) * x * x ) + 1 )
39 #define BICUBIC_K2( x , a ) ( ( a * x * x * x ) - ( 5 * a * x * x ) + \
40  ( 8 * a * x ) - ( 4 * a ) )
41 #define BICUBIC_RANGES(x,a) \
42  ( ( ( 0 <= x ) && ( x <= 1 ) ) ? \
43  BICUBIC_K1(x,a) \
44  : ( ( ( 1 < x ) && ( x <= 2 ) ) ? \
45  BICUBIC_K2(x,a) \
46  : 0 ) )
47 #define BICUBIC_KERNEL( x , a ) BICUBIC_RANGES( BICUBIC_MODULE(x) , a )
48 
50 {
51  if( ! initialize( r, m, std::vector< std::complex<double> >() ) )
52  {
53  throw te::rst::Exception("Interpolator initialization error");
54  }
55 }
56 
58  const std::vector< std::complex<double> >& noDataValues )
59 {
60  if( ! initialize( r, m, noDataValues ) )
61  {
62  throw te::rst::Exception("Interpolator initialization error");
63  }
64 }
65 
67 {
68  m_function = 0;
69 }
70 
71 void te::rst::Interpolator::getValues(const double& c, const double& r, std::vector<std::complex<double> >& values)
72 {
73  values.clear();
74 
75  std::complex<double> v;
76 
77  for(std::size_t b = 0; b < m_raster->getNumberOfBands(); b++)
78  {
79  getValue(c, r, v, b);
80 
81  values.push_back(v);
82  }
83 }
84 
86 {
87  te::rst::Interpolator* newInstancePtr = new te::rst::Interpolator( m_raster, m_method );
88  return newInstancePtr;
89 }
90 
91 void te::rst::Interpolator::nearestNeighborGetValue(const double& c, const double& r, std::complex<double>& v, const std::size_t& b)
92 {
93  if( ( c > (-0.5) ) && ( r > (-0.5) ) && ( c < m_nnLastCol ) && ( r < m_nnLastRow ) )
94  {
95  m_nnCR = (unsigned int) te::rst::Round(c);
96  m_nnRR = (unsigned int) te::rst::Round(r);
97 
98  m_raster->getValue(m_nnCR, m_nnRR, v, b);
99  }
100  else
101  {
102  v = m_noDataValues[ b ];
103  }
104 }
105 
106 void te::rst::Interpolator::bilinearGetValue(const double& c, const double& r, std::complex<double>& v, const std::size_t& b)
107 {
108  if( (r < 0.0) || (c < 0.0) || (r > m_bilLastRow) || (c > m_bilLastCol) )
109  {
110  nearestNeighborGetValue(c, r, v, b);
111  return;
112  }
113 
114  m_bilRowMin = std::floor(r);
115  m_bilRowMax = (m_bilRowMin == r)? m_bilRowMin: (m_bilRowMin + 1.0);
116 
117  m_bilColMin = std::floor(c);
118  m_bilColMax = (m_bilColMin == c)? m_bilColMin: (m_bilColMin + 1.0);
119 
120  m_bilRowDifMin = r - m_bilRowMin;
121  m_bilRowDifMax = m_bilRowMax - r;
122 
123  m_bilColDifMin = c - m_bilColMin;
124  m_bilColDifMax = m_bilColMax - c;
125 
126  m_bilDistances[0] = std::sqrt((m_bilRowDifMin * m_bilRowDifMin) + (m_bilColDifMin * m_bilColDifMin));
127  m_bilDistances[1] = std::sqrt((m_bilRowDifMin * m_bilRowDifMin) + (m_bilColDifMax * m_bilColDifMax));
128  m_bilDistances[2] = std::sqrt((m_bilRowDifMax * m_bilRowDifMax) + (m_bilColDifMin * m_bilColDifMin));
129  m_bilDistances[3] = std::sqrt((m_bilRowDifMax * m_bilRowDifMax) + (m_bilColDifMin * m_bilColDifMax));
130 
131  m_bilWeights[0] = (m_bilDistances[0] == 0)? 1.0: (1 / m_bilDistances[0]);
132  m_bilWeights[1] = (m_bilDistances[1] == 0)? 1.0: (1 / m_bilDistances[1]);
133  m_bilWeights[2] = (m_bilDistances[2] == 0)? 1.0: (1 / m_bilDistances[2]);
134  m_bilWeights[3] = (m_bilDistances[3] == 0)? 1.0: (1 / m_bilDistances[3]);
135 
136  m_raster->getValue((unsigned) m_bilColMin, (unsigned) m_bilRowMin, m_bilValues[0], b);
137  if( m_bilValues[0] == m_noDataValues[ b ] )
138  {
139  nearestNeighborGetValue(c, r, v, b);
140  return;
141  }
142 
143  m_raster->getValue((unsigned) m_bilColMax, (unsigned) m_bilRowMin, m_bilValues[1], b);
144  if( m_bilValues[1] == m_noDataValues[ b ] )
145  {
146  nearestNeighborGetValue(c, r, v, b);
147  return;
148  }
149 
150  m_raster->getValue((unsigned) m_bilColMin, (unsigned) m_bilRowMax, m_bilValues[2], b);
151  if( m_bilValues[2] == m_noDataValues[ b ] )
152  {
153  nearestNeighborGetValue(c, r, v, b);
154  return;
155  }
156 
157  m_raster->getValue((unsigned) m_bilColMax, (unsigned) m_bilRowMax, m_bilValues[3], b);
158  if( m_bilValues[3] == m_noDataValues[ b ] )
159  {
160  nearestNeighborGetValue(c, r, v, b);
161  return;
162  }
163 
164  double vr = ( (m_bilValues[0].real() * m_bilWeights[0]) +
165  (m_bilValues[1].real() * m_bilWeights[1]) +
166  (m_bilValues[2].real() * m_bilWeights[2]) +
167  (m_bilValues[3].real() * m_bilWeights[3]) ) /
168  (m_bilWeights[0] + m_bilWeights[1] + m_bilWeights[2] + m_bilWeights[3]);
169  double vi = ( (m_bilValues[0].imag() * m_bilWeights[0]) +
170  (m_bilValues[1].imag() * m_bilWeights[1]) +
171  (m_bilValues[2].imag() * m_bilWeights[2]) +
172  (m_bilValues[3].imag() * m_bilWeights[3]) ) /
173  (m_bilWeights[0] + m_bilWeights[1] + m_bilWeights[2] + m_bilWeights[3]);
174  v = std::complex<double>(vr,vi);
175 }
176 
177 void te::rst::Interpolator::bicubicGetValue(const double& c, const double& r, std::complex<double>& v, const std::size_t& b)
178 {
179  if( (r <= 1.0) || (c <= 1.0) || (r >= m_bicRowBound) || (c >= m_bicColBound) )
180  {
181  nearestNeighborGetValue(c, r, v, b);
182  return;
183  }
184 
185  m_bicGridRow = ((unsigned) std::floor(r)) - 1;
186  m_bicGridCol = ((unsigned) std::floor(c)) - 1;
187 
188  // fill buffer
189  for(m_bicBufRow = 0; m_bicBufRow < 4; ++m_bicBufRow)
190  {
191  for(m_bicBufCol = 0; m_bicBufCol < 4 ; ++m_bicBufCol)
192  {
193 
194  m_raster->getValue(m_bicGridCol + m_bicBufCol, m_bicGridRow + m_bicBufRow,
195  m_bicReadRealValue, b);
196  m_raster->getIValue(m_bicGridCol + m_bicBufCol, m_bicGridRow + m_bicBufRow,
197  m_bicReadImagValue, b);
198 
199  if( ( m_bicReadRealValue == m_noDataValues[ b ].real() ) &&
200  ( m_bicReadImagValue == m_noDataValues[ b ] ) )
201  {
202  nearestNeighborGetValue(c, r, v, b);
203  return;
204  }
205 
206  m_bicBbufferReal[m_bicBufRow][m_bicBufCol] = m_bicReadRealValue;
207  m_bicBbufferImag[m_bicBufRow][m_bicBufCol] = m_bicReadImagValue;
208  }
209  }
210 
211  // calcule weights for the required position.
212  m_bicOffsetX = c - (double)(m_bicGridCol + 1);
213  m_bicOffsetY = r - (double)(m_bicGridRow + 1);
214 
215  m_bicHWeights[0] = BICUBIC_KERNEL(1.0 + m_bicOffsetX, m_bicKernel);
216  m_bicHWeights[1] = BICUBIC_KERNEL(m_bicOffsetX, m_bicKernel);
217  m_bicHWeights[2] = BICUBIC_KERNEL(1.0 - m_bicOffsetX, m_bicKernel);
218  m_bicHWeights[3] = BICUBIC_KERNEL(2.0 - m_bicOffsetX, m_bicKernel);
219 
220  m_bicVWeights[0] = BICUBIC_KERNEL(1.0 + m_bicOffsetY, m_bicKernel);
221  m_bicVWeights[1] = BICUBIC_KERNEL(m_bicOffsetY, m_bicKernel);
222  m_bicVWeights[2] = BICUBIC_KERNEL(1.0 - m_bicOffsetY, m_bicKernel);
223  m_bicVWeights[3] = BICUBIC_KERNEL(2.0 - m_bicOffsetY, m_bicKernel);
224 
225  m_bicHSum = m_bicHWeights[0] + m_bicHWeights[1] + m_bicHWeights[2] + m_bicHWeights[3];
226  m_bicVSum = m_bicVWeights[0] + m_bicVWeights[1] + m_bicVWeights[2] + m_bicVWeights[3];
227 
228  // interpolating the value
229  for(m_bicBufRow = 0 ; m_bicBufRow < 4 ; ++m_bicBufRow)
230  {
231  m_bicRowAccumReal = 0.0;
232  m_bicRowAccumImag = 0.0;
233  for(m_bicBufCol = 0; m_bicBufCol < 4; ++m_bicBufCol)
234  {
235  m_bicRowAccumReal += m_bicBbufferReal[m_bicBufRow][m_bicBufCol] *
236  m_bicHWeights[m_bicBufCol];
237  m_bicRowAccumImag += m_bicBbufferImag[m_bicBufRow][m_bicBufCol] *
238  m_bicHWeights[m_bicBufCol];
239  }
240 
241  m_bicRowsValuesReal[m_bicBufRow] = m_bicRowAccumReal / m_bicHSum;
242  m_bicRowsValuesImag[m_bicBufRow] = m_bicRowAccumImag / m_bicHSum;
243  }
244  double vr = ( m_bicRowsValuesReal[0] * m_bicVWeights[0] +
245  m_bicRowsValuesReal[1] * m_bicVWeights[1] +
246  m_bicRowsValuesReal[2] * m_bicVWeights[2] +
247  m_bicRowsValuesReal[3] * m_bicVWeights[3] ) / m_bicVSum;
248 
249  double vi = ( m_bicRowsValuesImag[0] * m_bicVWeights[0] +
250  m_bicRowsValuesImag[1] * m_bicVWeights[1] +
251  m_bicRowsValuesImag[2] * m_bicVWeights[2] +
252  m_bicRowsValuesImag[3] * m_bicVWeights[3] ) / m_bicVSum;
253  v = std::complex<double>(vr,vi);
254 }
255 
256 bool te::rst::Interpolator::initialize(Raster const * const rasterPointer, int method,
257  const std::vector< std::complex<double> >& noDataValues )
258 {
259  if( rasterPointer == 0 )
260  {
261  return false;
262  }
263  if( ! ( rasterPointer->getAccessPolicy() & te::common::RAccess ) )
264  {
265  return false;
266  }
267 
268  m_raster = rasterPointer;
269 
270  switch(method)
271  {
272  case Bicubic:
274  break;
275  case Bilinear:
277  break;
278  case NearestNeighbor:
280  break;
281  default :
282  throw te::rst::Exception("Invalid interpolation method");
283  break;
284  }
285 
286  m_method = method;
287 
288  // raster no-data values (for each band)
289 
290  m_noDataValues.clear();
291 
292  if( noDataValues.empty() )
293  {
294  std::complex<double> auxC;
295 
296  for( unsigned int bandIdx = 0 ; bandIdx < rasterPointer->getNumberOfBands() ; ++bandIdx )
297  {
298  auxC.real( rasterPointer->getBand( bandIdx )->getProperty()->m_noDataValue );
299  m_noDataValues.push_back( auxC );
300  }
301  }
302  else
303  {
304  if( noDataValues.size() > rasterPointer->getNumberOfBands() )
305  {
306  throw te::rst::Exception("Invalid no-data values");
307  }
308 
309  m_noDataValues = noDataValues;
310  }
311 
312  // ancillary values for nearest Neighbor interpolation
313 
314  m_nnLastRow = ( (double) m_raster->getNumberOfRows() ) - 0.5;
315  m_nnLastCol = ( (double) m_raster->getNumberOfColumns() ) - 0.5;
316 
317  // ancillary values for bilinear interpolation
318  m_bilValues.resize(4, 0);
319 
320  m_bilLastRow = (double) m_raster->getNumberOfRows() - 1.0;
321 
322  m_bilLastCol = (double) m_raster->getNumberOfColumns() - 1.0;
323 
324  // ancillary values for bicubic interpolation
325  m_bicKernel = -1.0;
326 
327  m_bicRowBound = m_bilLastRow - 1.0;
328 
329  m_bicColBound = m_bilLastCol - 1.0;
330 
331  return true;
332 }
void getValues(const double &c, const double &r, std::vector< std::complex< double > > &values)
Get the interpolated value for all bands.
void nearestNeighborGetValue(const double &c, const double &r, std::complex< double > &v, const std::size_t &b)
Nearest neighbor interpolation method.
Near neighborhood interpolation method.
Definition: Enums.h:95
It describes one band (or dimension) of a raster.
virtual const Band * getBand(std::size_t i) const =0
Returns the raster i-th band.
It interpolates one pixel based on a selected algorithm. Methods currently available are Nearest Neig...
Definition: Interpolator.h:55
bool initialize(Raster const *const rasterPointer, int method, const std::vector< std::complex< double > > &noDataValues)
Initialize this instance..
void bilinearGetValue(const double &c, const double &r, std::complex< double > &v, const std::size_t &b)
Bilinear interpolation method.
double m_noDataValue
Value to indicate elements where there is no data, default is std::numeric_limits::max().
Definition: BandProperty.h:136
te::common::AccessPolicy getAccessPolicy() const
Returns the raster access policy.
Definition: Raster.cpp:89
An exception class for the Raster module.
te::rst::Interpolator * clone() const
Create a clone copy of this instance.
#define BICUBIC_KERNEL(x, a)
TERASTEREXPORT int Round(double val)
Round a double value to a integer value.
Definition: Utils.cpp:298
An abstract class for raster data strucutures.
Definition: Raster.h:71
BandProperty * getProperty()
Returns the band property.
Definition: Band.cpp:428
virtual std::size_t getNumberOfBands() const =0
Returns the number of bands (dimension of cells attribute values) in the raster.
Utility functions for the raster module.
virtual ~Interpolator()
Destructor.
It gives access to values in one band (dimension) of a raster.
Interpolator(Raster const *r, int m)
Constructor.
Bicubic interpolation method.
Definition: Enums.h:97
void bicubicGetValue(const double &c, const double &r, std::complex< double > &v, const std::size_t &b)
Bicubic interpolation method.
Bilinear interpolation method.
Definition: Enums.h:96
It interpolates one pixel based on a selected algorithm.