00001 /* 00002 Two-dimensional interpolation for irregularly-spaced data. 00003 00004 Copyright (C) 2010 - 2014 Christoph Haenisch 00005 00006 Chair of Medical Engineering (mediTEC) 00007 RWTH Aachen University 00008 Pauwelsstr. 20 00009 52074 Aachen 00010 Germany 00011 00012 See license.txt for more information. 00013 00014 Version 0.1.1 (2013-08-20) 00015 */ 00016 00021 #ifndef INTERPOLATION_2D_HPP_1443431201 00022 #define INTERPOLATION_2D_HPP_1443431201 00023 00024 00025 #include <algorithm> 00026 #include <cassert> 00027 #include <cmath> 00028 #include <cstddef> 00029 #include <stdexcept> 00030 #include <vector> 00031 00032 #include <flann/flann.hpp> 00033 00034 #include "Coordinate.hpp" 00035 #include "Tools.hpp" 00036 00037 /* 00038 00039 All data items are stored in a kd-tree, internally. If an algorithm needs to 00040 access them, the tree must be traversed. Since the tree behaves like normal 00041 container, this can be easily done with iterators . 00042 00043 The algorithms are called via a function pointer which is set by the constructor 00044 or a setter-method. 00045 00046 */ 00047 00048 namespace TRTK 00049 { 00050 00051 00282 template<class ValueType = double, 00283 class PointType = Coordinate<double>, 00284 class DataType = Coordinate<double> > 00285 class Interpolation2D 00286 { 00287 public: 00288 00289 typedef ValueType value_type; 00290 typedef PointType point_type; 00291 typedef DataType data_type; 00292 00293 typedef PointType Point; 00294 00295 enum InterpolationMethod 00296 { 00297 INVERSE_DISTANCE_WEIGHTING, 00298 INVERSE_DISTANCE_WEIGHTING_KNN, 00299 NEAREST_NEIGHBOR 00300 }; 00301 00302 Interpolation2D(const DataType & default_value = DataType(), 00303 InterpolationMethod interpolation_method = INVERSE_DISTANCE_WEIGHTING_KNN); 00304 00305 Interpolation2D(const std::vector<Point> & data_points, 00306 const std::vector<DataType> & data, 00307 const DataType & default_value = DataType(), 00308 InterpolationMethod interpolation_method = INVERSE_DISTANCE_WEIGHTING_KNN); 00309 00310 ~Interpolation2D(); 00311 00312 DataType operator()(const Point & point) const; 00313 DataType operator()(ValueType x, ValueType y) const; 00314 00315 DataType getData(const Point & point) const; 00316 DataType getData(ValueType x, ValueType y) const; 00317 00318 void setData(const std::vector<Point> & data_points, 00319 const std::vector<DataType> & data); 00320 00321 void setExponent(ValueType value = 2.0); 00322 00323 void setInterpolationMethod(InterpolationMethod interpolation_method); 00324 00325 void setNumberOfNearestNeighbors(unsigned number = 10); 00326 00327 void setRadius(ValueType radius); 00328 00329 protected: 00330 00331 DataType (Interpolation2D::*interpolation_function)(ValueType, ValueType) const; 00332 00333 DataType getDataInverseDistanceWeighting(ValueType x, ValueType y) const; 00334 DataType getDataInverseDistanceWeightingKNN(ValueType x, ValueType y) const; 00335 DataType getDataNearestNeighbor(ValueType x, ValueType y) const; 00336 00337 ValueType exponent; 00338 ValueType radius; 00339 00340 unsigned max_number_of_nearest_neighbors; 00341 00342 flann::Index<flann::L2<ValueType> > * tree; 00343 00344 const DataType data_type_default_value; 00345 00346 std::vector<DataType> data; 00347 00348 flann::Matrix<ValueType> data_points; 00349 mutable flann::Matrix<ValueType> query_point; 00350 mutable flann::Matrix<ValueType> distances; 00351 mutable flann::Matrix<int> indices; 00352 }; 00353 00354 00361 template<class ValueType, class PointType, class DataType> 00362 Interpolation2D<ValueType, PointType, DataType>::Interpolation2D(const DataType & default_value, InterpolationMethod interpolation_method) : 00363 exponent(2), 00364 radius(1), 00365 tree(NULL), 00366 data_type_default_value(default_value) 00367 { 00368 query_point = flann::Matrix<ValueType>(new ValueType[2], 1, 2); 00369 00370 setInterpolationMethod(interpolation_method); 00371 setNumberOfNearestNeighbors(10); 00372 } 00373 00374 00383 template<class ValueType, class PointType, class DataType> 00384 Interpolation2D<ValueType, PointType, DataType>::Interpolation2D(const std::vector<Point> & data_points, 00385 const std::vector<DataType> & data, 00386 const DataType & default_value, 00387 InterpolationMethod interpolation_method) : 00388 exponent(2), 00389 radius(1), 00390 tree(NULL), 00391 data_type_default_value(default_value) 00392 { 00393 query_point = flann::Matrix<ValueType>(new ValueType[2], 1, 2); 00394 00395 setData(data_points, data); 00396 setInterpolationMethod(interpolation_method); 00397 setNumberOfNearestNeighbors(10); 00398 } 00399 00400 00403 template<class ValueType, class PointType, class DataType> 00404 Interpolation2D<ValueType, PointType, DataType>::~Interpolation2D() 00405 { 00406 data_points.free(); 00407 query_point.free(); 00408 distances.free(); 00409 indices.free(); 00410 } 00411 00412 00419 template<class ValueType, class PointType, class DataType> 00420 inline DataType Interpolation2D<ValueType, PointType, DataType>::operator()(const Point & point) const 00421 { 00422 return (this->*interpolation_function)(point.x(), point.y()); 00423 } 00424 00425 00432 template<class ValueType, class PointType, class DataType> 00433 inline DataType Interpolation2D<ValueType, PointType, DataType>::operator()(ValueType x, ValueType y) const 00434 { 00435 return (this->*interpolation_function)(x, y); 00436 } 00437 00438 00445 template<class ValueType, class PointType, class DataType> 00446 inline DataType Interpolation2D<ValueType, PointType, DataType>::getData(const Point & point) const 00447 { 00448 return (this->*interpolation_function)(point.x(), point.y()); 00449 } 00450 00451 00458 template<class ValueType, class PointType, class DataType> 00459 inline DataType Interpolation2D<ValueType, PointType, DataType>::getData(ValueType x, ValueType y) const 00460 { 00461 return (this->*interpolation_function)(x, y); 00462 } 00463 00464 00488 template<class ValueType, class PointType, class DataType> 00489 DataType Interpolation2D<ValueType, PointType, DataType>::getDataInverseDistanceWeighting(ValueType x, ValueType y) const 00490 { 00491 if (this->tree->size() == 0) 00492 { 00493 throw std::range_error("Interpolation2D::getDataInverseDistanceWeighting(): Tree is empty."); 00494 } 00495 00496 query_point[0][0] = x; 00497 query_point[0][1] = y; 00498 00499 // Find the first nearest neighbor. 00500 00501 unsigned number_of_found_nearest_neighbors = tree->radiusSearch(query_point, indices, distances, radius, flann::SearchParams(128)); 00502 00503 if (number_of_found_nearest_neighbors == 0) 00504 { 00505 throw std::runtime_error("Interpolation2D::getDataInverseDistanceWeighting(): Radius too small. No nearest neighbor found."); 00506 } 00507 00508 // If the found point is the query point itself, just return the associated data... 00509 00510 if (Tools::isZero(distances[0][0])) 00511 { 00512 return data[indices[0][0]]; 00513 } 00514 00515 // ... otherwise return an interpolated datum from the first n nearest neighbors. 00516 00517 unsigned number_of_neighbors = std::min(number_of_found_nearest_neighbors, max_number_of_nearest_neighbors); 00518 00519 ValueType normalization_coefficient = 0; 00520 DataType data = data_type_default_value; 00521 00522 for (unsigned i = 0; i < number_of_neighbors; ++i) 00523 { 00524 using std::pow; 00525 ValueType weight = pow(distances[0][i], -exponent); 00526 00527 normalization_coefficient += weight; 00528 00529 data += this->data[indices[0][i]] * weight; 00530 } 00531 00532 return data * (1 / normalization_coefficient); 00533 } 00534 00535 00557 template<class ValueType, class PointType, class DataType> 00558 DataType Interpolation2D<ValueType, PointType, DataType>::getDataInverseDistanceWeightingKNN(ValueType x, ValueType y) const 00559 { 00560 if (this->tree->size() == 0) 00561 { 00562 throw std::range_error("Interpolation2D::getDataInverseDistanceWeightingKNN(): Tree is empty."); 00563 } 00564 00565 query_point[0][0] = x; 00566 query_point[0][1] = y; 00567 00568 // Find the first nearest neighbor. 00569 00570 tree->knnSearch(query_point, indices, distances, max_number_of_nearest_neighbors, flann::SearchParams(128)); 00571 00572 // If the found point is the query point itself, just return the associated data... 00573 00574 if (Tools::isZero(distances[0][0])) 00575 { 00576 return data[indices[0][0]]; 00577 } 00578 00579 // ... otherwise return an interpolated datum from the first n nearest neighbors. 00580 00581 const unsigned tree_size = tree->size(); 00582 00583 ValueType normalization_coefficient = 0; 00584 DataType data = data_type_default_value; 00585 00586 for (unsigned i = 0; i < max_number_of_nearest_neighbors && i < tree_size; ++i) 00587 { 00588 using std::pow; 00589 ValueType weight = pow(distances[0][i], -exponent); 00590 00591 normalization_coefficient += weight; 00592 00593 data += this->data[indices[0][i]] * weight; 00594 } 00595 00596 return data * (1 / normalization_coefficient); 00597 } 00598 00599 00612 template<class ValueType, class PointType, class DataType> 00613 DataType Interpolation2D<ValueType, PointType, DataType>::getDataNearestNeighbor(ValueType x, ValueType y) const 00614 { 00615 if (this->tree->size() == 0) 00616 { 00617 throw std::range_error("Interpolation2D::getDataNearestNeighbor(): Tree is empty."); 00618 } 00619 00620 query_point[0][0] = x; 00621 query_point[0][1] = y; 00622 00623 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128)); 00624 00625 return data[indices[0][0]]; 00626 } 00627 00628 00640 template<class ValueType, class PointType, class DataType> 00641 void Interpolation2D<ValueType, PointType, DataType>::setData(const std::vector<Point> & data_points, 00642 const std::vector<DataType> & data) 00643 { 00644 if (data_points.size() != data.size()) 00645 { 00646 throw std::logic_error("Interpolation3D::setData(): 'data_points' and 'data' must have the same size."); 00647 } 00648 00649 if (data_points.size() == 0) 00650 { 00651 throw std::runtime_error("Interpolation3D::setData(): The input data may not be emtpy."); 00652 } 00653 00654 // Copy the data points as well as the associated data. 00655 00656 const unsigned number_points = data_points.size(); 00657 00658 this->data_points.free(); 00659 this->data_points = flann::Matrix<ValueType>(new ValueType[2 * number_points], number_points, 2);; 00660 00661 for (unsigned i = 0; i < number_points; ++i) 00662 { 00663 this->data_points[i][0] = data_points[i][0]; 00664 this->data_points[i][1] = data_points[i][1]; 00665 } 00666 00667 this->data = data; 00668 00669 // Setup tree. 00670 00671 if (tree != NULL) delete tree; 00672 00673 tree = new flann::Index<flann::L2<ValueType> >(this->data_points, flann::KDTreeSingleIndexParams()); 00674 tree->buildIndex(); 00675 } 00676 00677 00685 template<class ValueType, class PointType, class DataType> 00686 void Interpolation2D<ValueType, PointType, DataType>::setExponent(ValueType value) 00687 { 00688 this->exponent = value; 00689 } 00690 00691 00701 template<class ValueType, class PointType, class DataType> 00702 void Interpolation2D<ValueType, PointType, DataType>::setInterpolationMethod(InterpolationMethod interpolation_method) 00703 { 00704 switch (interpolation_method) 00705 { 00706 case INVERSE_DISTANCE_WEIGHTING: 00707 { 00708 interpolation_function = &Interpolation2D::getDataInverseDistanceWeighting; 00709 break; 00710 } 00711 00712 case INVERSE_DISTANCE_WEIGHTING_KNN: 00713 { 00714 interpolation_function = &Interpolation2D::getDataInverseDistanceWeightingKNN; 00715 break; 00716 } 00717 00718 case NEAREST_NEIGHBOR: 00719 { 00720 interpolation_function = &Interpolation2D::getDataNearestNeighbor; 00721 break; 00722 } 00723 00724 default: 00725 { 00726 throw std::logic_error("Interpolation2D::setInterpolationMethod(): Unknown interpolation method."); 00727 } 00728 } 00729 } 00730 00731 00742 template<class ValueType, class PointType, class DataType> 00743 void Interpolation2D<ValueType, PointType, DataType>::setNumberOfNearestNeighbors(unsigned number) 00744 { 00745 if (number == 0) 00746 { 00747 throw std::logic_error("Interpolation2D::setNumberOfNearestNeighbors(): " 00748 "Number of nearest neighbors must be greater than zero."); 00749 } 00750 00751 this->max_number_of_nearest_neighbors = number; 00752 00753 indices.free(); 00754 distances.free(); 00755 00756 indices = flann::Matrix<int>(new int[number], 1, number); 00757 distances = flann::Matrix<ValueType>(new ValueType[number], 1, number); 00758 00759 } 00760 00761 00771 template<class ValueType, class PointType, class DataType> 00772 void Interpolation2D<ValueType, PointType, DataType>::setRadius(ValueType radius) 00773 { 00774 if (radius <= 0) 00775 { 00776 throw std::logic_error("Interpolation2D::setRadius(): Radius must be greater than zero."); 00777 } 00778 00779 this->radius = radius; 00780 } 00781 00782 00783 } 00784 00785 00786 #endif // INTERPOLATION_2D_HPP_1443431201
Documentation generated by Doxygen