TuttleOFX
1
|
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