TuttleOFX  1
gaussianKernel.hpp
Go to the documentation of this file.
00001 #ifndef _TERRY_FILTER_GAUSSIANKERNEL_HPP_
00002 #define _TERRY_FILTER_GAUSSIANKERNEL_HPP_
00003 
00004 #include "convolve.hpp"
00005 
00006 #include <terry/globals.hpp>
00007 
00008 #include <boost/math/constants/constants.hpp>
00009 #include <boost/math/special_functions/pow.hpp>
00010 #include <boost/lambda/core.hpp>
00011 #include <boost/lambda/lambda.hpp>
00012 #include <boost/lambda/algorithm.hpp>
00013 
00014 #include <cmath>
00015 #include <vector>
00016 #include <algorithm>
00017 
00018 namespace terry {
00019 namespace filter {
00020 
00021 static const double kConvolutionEpsilon = 0.1; ///< arbitrary value...
00022 
00023 /**
00024  * @brief gaussian function
00025  * @f[
00026  * G(x) = \frac{1}{\sqrt{2\pi \sigma^2}} e^{-\frac{x^2}{2 \sigma^2}}
00027  * @f]
00028  * or simplified...
00029  * @f[
00030  * G(x) = a e^{- { \frac{(x-b)^2 }{ 2 c^2} } }
00031  * @f]
00032  *
00033  * @return y <- gauss(x)
00034  */
00035 template<typename Scalar>
00036 Scalar gaussianValueAt( const Scalar x, const Scalar amplitude, const Scalar yscale = 1, const Scalar xcenter = 0 )
00037 {
00038         namespace bm = boost::math;
00039 //      return yscale * std::exp( -bu::pow<2>( x - xcenter ) / ( 2.0 * bu::pow<2>( amplitude ) ) );
00040         return yscale * std::exp( -bm::pow<2>( x - xcenter ) / ( 2.0 * amplitude ) ) / ( 2.0 * amplitude * bm::constants::pi<Scalar>() );
00041 }
00042 
00043 /**
00044  * @brief create the gaussian kernel
00045  * * found the kernel size
00046  * * fill kernel values
00047  */
00048 template<typename Scalar>
00049 terry::filter::kernel_1d<Scalar> buildGaussian1DKernel( const Scalar size, const bool normalize = true, const double epsilon = kConvolutionEpsilon )
00050 {
00051         using namespace boost;
00052         if( size == 0 )
00053         {
00054                 return terry::filter::kernel_1d<Scalar>();
00055         }
00056         const double rEpsilon = size > 1 ? epsilon / static_cast<double>(size) : epsilon;
00057         std::vector<Scalar> rightKernel;
00058         rightKernel.reserve( 10 );
00059         int x      = 1;
00060         Scalar v   = gaussianValueAt<Scalar>( x, size );
00061         Scalar sum = 0.0;
00062         do
00063         {
00064                 rightKernel.push_back( v );
00065                 sum += v;
00066                 ++x;
00067                 v = gaussianValueAt<Scalar>( x, size );
00068         }
00069         while( std::abs(v) > rEpsilon );
00070 
00071         std::vector<Scalar> kernel( rightKernel.size() * 2 + 1 );
00072         Scalar kernelCenter = gaussianValueAt<Scalar>( 0, size );
00073 
00074         sum *= 2.0;
00075         sum += kernelCenter;
00076 
00077         if( normalize )
00078         {
00079                 std::for_each( rightKernel.begin(), rightKernel.end(), lambda::_1 /= sum );
00080                 kernelCenter /= sum;
00081         }
00082 
00083         kernel[rightKernel.size()] = kernelCenter; // kernel center to 0
00084         std::copy( rightKernel.rbegin(), rightKernel.rend(), kernel.begin() );
00085         std::copy( rightKernel.begin(), rightKernel.end(), kernel.begin() + rightKernel.size() + 1 );
00086 
00087         //      TUTTLE_CLOG_VAR( TUTTLE_TRACE, rightKernel.size() );
00088         //      TUTTLE_CLOG_VAR( TUTTLE_TRACE, kernel.size() );
00089         //      std::cout << "[";
00090         //      std::for_each(rightKernel.begin(), rightKernel.end(), std::cout << lambda::_1 << ',');
00091         //      std::cout << "]" << std::endl;
00092         //      std::cout << "[";
00093         //      std::for_each(kernel.begin(), kernel.end(), std::cout << lambda::_1 << ',');
00094         //      std::cout << "]" << std::endl;
00095         return terry::filter::kernel_1d<Scalar>( &( kernel[0] ), kernel.size(), rightKernel.size() );
00096 }
00097 
00098 /**
00099  * @brief gaussian derivative function
00100  * @f[
00101  * G(x) = - x/a e^{- { \frac{(x-b)^2 }{ 2 c^2} } }
00102  * @f]
00103  *
00104  * @return y <- gauss(x)
00105  */
00106 template<typename Scalar>
00107 Scalar gaussianDerivativeValueAt( const Scalar x, const Scalar amplitude, const Scalar yscale = 1, const Scalar xcenter = 0 )
00108 {
00109         namespace bm = boost::math;
00110 //      return ( x / yscale ) * std::exp( -bu::pow<2>( x - xcenter ) / ( 2.0 * bu::pow<2>( amplitude ) ) );
00111         return ( /*-*/ x / yscale ) * std::exp( -bm::pow<2>( x - xcenter ) / ( 2.0 * amplitude ) ) / ( amplitude * bm::constants::pi<Scalar>() );
00112 }
00113 
00114 /**
00115  * @brief create the gaussian derivative kernel
00116  * * found the kernel size
00117  * * fill kernel values
00118  */
00119 template<typename Scalar>
00120 terry::filter::kernel_1d<Scalar> buildGaussianDerivative1DKernel( const Scalar size, const bool normalize = true, const double epsilon = kConvolutionEpsilon )
00121 {
00122         using namespace boost;
00123         if( size == 0 )
00124         {
00125                 return terry::filter::kernel_1d<Scalar>();
00126         }
00127         const double rEpsilon = size > 1 ? epsilon / static_cast<double>(size) : epsilon;
00128         std::vector<Scalar> rightKernel;
00129         rightKernel.reserve( 10 );
00130         int x = 1;
00131         Scalar v   = gaussianDerivativeValueAt<Scalar>( x, size );
00132         Scalar sum = 0.0;
00133         do
00134         {
00135                 rightKernel.push_back( v );
00136                 sum += v;
00137                 ++x;
00138                 v = gaussianDerivativeValueAt<Scalar>( x, size );
00139         }
00140         while( std::abs(v) > rEpsilon );
00141 
00142         if( rightKernel.size() == 0 || sum == 0 )
00143                 return terry::filter::kernel_1d<Scalar>();
00144 
00145         std::vector<Scalar> kernel( rightKernel.size() * 2 + 1 );
00146         Scalar kernelCenter = gaussianDerivativeValueAt<Scalar>( 0, size );
00147         sum += kernelCenter;
00148 
00149         if( normalize )
00150         {
00151                 std::for_each( rightKernel.begin(), rightKernel.end(), lambda::_1 /= sum );
00152                 kernelCenter /= sum;
00153         }
00154 
00155         kernel[rightKernel.size()] = kernelCenter; // kernel center to 0
00156         std::copy( rightKernel.rbegin(), rightKernel.rend(), kernel.begin() );
00157         std::copy( rightKernel.begin(), rightKernel.end(), kernel.begin() + rightKernel.size() + 1 );
00158 
00159         std::for_each( kernel.begin(), kernel.begin() + rightKernel.size(), lambda::_1 *= -1 );
00160 
00161         //      TUTTLE_CLOG_VAR( TUTTLE_TRACE, rightKernel.size() );
00162         //      TUTTLE_CLOG_VAR( TUTTLE_TRACE, kernel.size() );
00163         //      std::cout << "[";
00164         //      std::for_each(rightKernel.begin(), rightKernel.end(), std::cout << lambda::_1 << ',');
00165         //      std::cout << "]" << std::endl;
00166         //      std::cout << "[";
00167         //      std::for_each(kernel.begin(), kernel.end(), std::cout << lambda::_1 << ',');
00168         //      std::cout << "]" << std::endl;
00169         return terry::filter::kernel_1d<Scalar>( &( kernel[0] ), kernel.size(), rightKernel.size() );
00170 }
00171 
00172 }
00173 }
00174 
00175 #endif
00176