00001 /* 00002 Three-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.2 (2013-08-20) 00015 */ 00016 00021 #ifndef INTERPOLATION_3D_HPP_4326730820 00022 #define INTERPOLATION_3D_HPP_4326730820 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 Interpolation3D 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 Interpolation3D(const DataType & default_value = DataType(), 00303 InterpolationMethod interpolation_method = INVERSE_DISTANCE_WEIGHTING_KNN); 00304 00305 Interpolation3D(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 ~Interpolation3D(); 00311 00312 DataType operator()(const Point & point) const; 00313 DataType operator()(ValueType x, ValueType y, ValueType z) const; 00314 00315 DataType getData(const Point & point) const; 00316 DataType getData(ValueType x, ValueType y, ValueType z) 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 (Interpolation3D::*interpolation_function)(ValueType, ValueType, ValueType) const; 00332 00333 DataType getDataInverseDistanceWeighting(ValueType x, ValueType y, ValueType z) const; 00334 DataType getDataInverseDistanceWeightingKNN(ValueType x, ValueType y, ValueType z) const; 00335 DataType getDataNearestNeighbor(ValueType x, ValueType y, ValueType z) 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 Interpolation3D<ValueType, PointType, DataType>::Interpolation3D(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[3], 1, 3); 00369 00370 setInterpolationMethod(interpolation_method); 00371 setNumberOfNearestNeighbors(10); 00372 } 00373 00374 00383 template<class ValueType, class PointType, class DataType> 00384 Interpolation3D<ValueType, PointType, DataType>::Interpolation3D(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[3], 1, 3); 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 Interpolation3D<ValueType, PointType, DataType>::~Interpolation3D() 00405 { 00406 if (tree != NULL) delete tree; 00407 00408 data_points.free(); 00409 query_point.free(); 00410 distances.free(); 00411 indices.free(); 00412 } 00413 00414 00421 template<class ValueType, class PointType, class DataType> 00422 inline DataType Interpolation3D<ValueType, PointType, DataType>::operator()(const Point & point) const 00423 { 00424 return (this->*interpolation_function)(point.x(), point.y(), point.z()); 00425 } 00426 00427 00434 template<class ValueType, class PointType, class DataType> 00435 inline DataType Interpolation3D<ValueType, PointType, DataType>::operator()(ValueType x, ValueType y, ValueType z) const 00436 { 00437 return (this->*interpolation_function)(x, y, z); 00438 } 00439 00440 00447 template<class ValueType, class PointType, class DataType> 00448 inline DataType Interpolation3D<ValueType, PointType, DataType>::getData(const Point & point) const 00449 { 00450 return (this->*interpolation_function)(point.x(), point.y(), point.z()); 00451 } 00452 00453 00460 template<class ValueType, class PointType, class DataType> 00461 inline DataType Interpolation3D<ValueType, PointType, DataType>::getData(ValueType x, ValueType y, ValueType z) const 00462 { 00463 return (this->*interpolation_function)(x, y, z); 00464 } 00465 00466 00491 template<class ValueType, class PointType, class DataType> 00492 DataType Interpolation3D<ValueType, PointType, DataType>::getDataInverseDistanceWeighting(ValueType x, ValueType y, ValueType z) const 00493 { 00494 if (this->tree->size() == 0) 00495 { 00496 throw std::range_error("Interpolation3D::getDataInverseDistanceWeighting(): Tree is empty."); 00497 } 00498 00499 query_point[0][0] = x; 00500 query_point[0][1] = y; 00501 query_point[0][2] = z; 00502 00503 // Find the first nearest neighbor. 00504 00505 unsigned number_of_found_nearest_neighbors = tree->radiusSearch(query_point, indices, distances, radius, flann::SearchParams(128)); 00506 00507 if (number_of_found_nearest_neighbors == 0) 00508 { 00509 throw std::runtime_error("Interpolation3D::getDataInverseDistanceWeighting(): Radius too small. No nearest neighbor found."); 00510 } 00511 00512 // If the found point is the query point itself, just return the associated data... 00513 00514 if (Tools::isZero(distances[0][0])) 00515 { 00516 return data[indices[0][0]]; 00517 } 00518 00519 // ... otherwise return an interpolated datum from the first n nearest neighbors. 00520 00521 unsigned number_of_neighbors = std::min(number_of_found_nearest_neighbors, max_number_of_nearest_neighbors); 00522 00523 ValueType normalization_coefficient = 0; 00524 DataType data = data_type_default_value; 00525 00526 for (unsigned i = 0; i < number_of_neighbors; ++i) 00527 { 00528 using std::pow; 00529 ValueType weight = pow(distances[0][i], -exponent); 00530 00531 normalization_coefficient += weight; 00532 00533 data += this->data[indices[0][i]] * weight; 00534 } 00535 00536 return data * (1 / normalization_coefficient); 00537 } 00538 00539 00562 template<class ValueType, class PointType, class DataType> 00563 DataType Interpolation3D<ValueType, PointType, DataType>::getDataInverseDistanceWeightingKNN(ValueType x, ValueType y, ValueType z) const 00564 { 00565 if (this->tree->size() == 0) 00566 { 00567 throw std::range_error("Interpolation3D::getDataInverseDistanceWeightingKNN(): Tree is empty."); 00568 } 00569 00570 query_point[0][0] = x; 00571 query_point[0][1] = y; 00572 query_point[0][2] = z; 00573 00574 // Find the first nearest neighbor. 00575 00576 tree->knnSearch(query_point, indices, distances, max_number_of_nearest_neighbors, flann::SearchParams(128)); 00577 00578 // If the found point is the query point itself, just return the associated data... 00579 00580 if (Tools::isZero(distances[0][0])) 00581 { 00582 return data[indices[0][0]]; 00583 } 00584 00585 // ... otherwise return an interpolated datum from the first n nearest neighbors. 00586 00587 const unsigned tree_size = tree->size(); 00588 00589 ValueType normalization_coefficient = 0; 00590 DataType data = data_type_default_value; 00591 00592 for (unsigned i = 0; i < max_number_of_nearest_neighbors && i < tree_size; ++i) 00593 { 00594 using std::pow; 00595 ValueType weight = pow(distances[0][i], -exponent); 00596 00597 normalization_coefficient += weight; 00598 00599 data += this->data[indices[0][i]] * weight; 00600 } 00601 00602 return data * (1 / normalization_coefficient); 00603 } 00604 00605 00619 template<class ValueType, class PointType, class DataType> 00620 DataType Interpolation3D<ValueType, PointType, DataType>::getDataNearestNeighbor(ValueType x, ValueType y, ValueType z) const 00621 { 00622 if (this->tree->size() == 0) 00623 { 00624 throw std::range_error("Interpolation3D::getDataNearestNeighbor(): Tree is empty."); 00625 } 00626 00627 query_point[0][0] = x; 00628 query_point[0][1] = y; 00629 query_point[0][2] = z; 00630 00631 tree->knnSearch(query_point, indices, distances, 1, flann::SearchParams(128)); 00632 00633 return data[indices[0][0]]; 00634 } 00635 00636 00648 template<class ValueType, class PointType, class DataType> 00649 void Interpolation3D<ValueType, PointType, DataType>::setData(const std::vector<Point> & data_points, 00650 const std::vector<DataType> & data) 00651 { 00652 if (data_points.size() != data.size()) 00653 { 00654 throw std::logic_error("Interpolation3D::setData(): 'data_points' and 'data' must have the same size."); 00655 } 00656 00657 if (data_points.size() == 0) 00658 { 00659 throw std::runtime_error("Interpolation3D::setData(): The input data may not be emtpy."); 00660 } 00661 00662 // Copy the data points as well as the associated data. 00663 00664 const unsigned number_points = data_points.size(); 00665 00666 this->data_points.free(); 00667 this->data_points = flann::Matrix<ValueType>(new ValueType[3 * number_points], number_points, 3);; 00668 00669 for (unsigned i = 0; i < number_points; ++i) 00670 { 00671 this->data_points[i][0] = data_points[i][0]; 00672 this->data_points[i][1] = data_points[i][1]; 00673 this->data_points[i][2] = data_points[i][2]; 00674 } 00675 00676 this->data = data; 00677 00678 // Setup tree. 00679 00680 if (tree != NULL) delete tree; 00681 00682 tree = new flann::Index<flann::L2<ValueType> >(this->data_points, flann::KDTreeSingleIndexParams()); 00683 tree->buildIndex(); 00684 } 00685 00686 00694 template<class ValueType, class PointType, class DataType> 00695 void Interpolation3D<ValueType, PointType, DataType>::setExponent(ValueType value) 00696 { 00697 this->exponent = value; 00698 } 00699 00700 00710 template<class ValueType, class PointType, class DataType> 00711 void Interpolation3D<ValueType, PointType, DataType>::setInterpolationMethod(InterpolationMethod interpolation_method) 00712 { 00713 switch (interpolation_method) 00714 { 00715 case INVERSE_DISTANCE_WEIGHTING: 00716 { 00717 interpolation_function = &Interpolation3D::getDataInverseDistanceWeighting; 00718 break; 00719 } 00720 00721 case INVERSE_DISTANCE_WEIGHTING_KNN: 00722 { 00723 interpolation_function = &Interpolation3D::getDataInverseDistanceWeightingKNN; 00724 break; 00725 } 00726 00727 case NEAREST_NEIGHBOR: 00728 { 00729 interpolation_function = &Interpolation3D::getDataNearestNeighbor; 00730 break; 00731 } 00732 00733 default: 00734 { 00735 throw std::logic_error("Interpolation3D::setInterpolationMethod(): Unknown interpolation method."); 00736 } 00737 } 00738 } 00739 00740 00751 template<class ValueType, class PointType, class DataType> 00752 void Interpolation3D<ValueType, PointType, DataType>::setNumberOfNearestNeighbors(unsigned number) 00753 { 00754 if (number == 0) 00755 { 00756 throw std::logic_error("Interpolation3D::setNumberOfNearestNeighbors(): " 00757 "Number of nearest neighbors must be greater than zero."); 00758 } 00759 00760 this->max_number_of_nearest_neighbors = number; 00761 00762 indices.free(); 00763 distances.free(); 00764 00765 indices = flann::Matrix<int>(new int[number], 1, number); 00766 distances = flann::Matrix<ValueType>(new ValueType[number], 1, number); 00767 00768 } 00769 00770 00780 template<class ValueType, class PointType, class DataType> 00781 void Interpolation3D<ValueType, PointType, DataType>::setRadius(ValueType radius) 00782 { 00783 if (radius <= 0) 00784 { 00785 throw std::logic_error("Interpolation3D::setRadius(): Radius must be greater than zero."); 00786 } 00787 00788 this->radius = radius; 00789 } 00790 00791 00792 } 00793 00794 00795 #endif // INTERPOLATION_3D_HPP_4326730820
Documentation generated by Doxygen