00001 #ifndef OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GAUSS_H
00002 #define OPENTISSUE_CORE_CONTAINERS_GRID_UTIL_GAUSS_H
00003
00004
00005
00006
00007
00008
00009
00010 #include <OpenTissue/configuration.h>
00011
00012 #include <OpenTissue/core/math/math_constants.h>
00013
00014
00015 #include <boost/cast.hpp>
00016
00017 #include <valarray>
00018 #include <vector>
00019 #include <iostream>
00020 #include <algorithm>
00021
00022 namespace OpenTissue
00023 {
00024 namespace grid
00025 {
00026
00027 namespace detail
00028 {
00039 template <typename array_type, typename real_type>
00040 inline void compute_gaussian_kernel( array_type & G, real_type const & s )
00041 {
00042 typedef typename array_type::value_type value_type;
00043
00044 using std::exp;
00045 real_type x = real_type();
00046 value_type sum = real_type();
00047
00048 size_t size = boost::numeric_cast<size_t>( G.size() );
00049
00050 if ( ( size % 2 ) == 0 )
00051 {
00052 ++size;
00053 std::cout << "compute_gaussian_kernel(): Oups, size of gaussian kernel was even!!!" << std::endl;
00054 }
00055
00056 real_type center = boost::numeric_cast<real_type>( floor( size / 2.0 ) );
00057
00058
00059
00060 for ( size_t i = 0; i < size; ++i )
00061 {
00062 x = i - center;
00063 G[ i ] = boost::numeric_cast<value_type>( exp( - ( x * x ) / ( 2.0 * s * s ) ) );
00064 sum += G[ i ];
00065 }
00066
00067
00068 for ( size_t i = 0; i < size; ++i )
00069 G[i] = G[i] / sum;
00070 }
00071
00083 template <typename value_type, typename real_type>
00084 inline void convolution1D(
00085 value_type * output
00086 , value_type const * input
00087 , int const & xdim
00088 , int const & ydim
00089 , int const & zdim
00090 , int const & dim
00091 , real_type const & s
00092 )
00093 {
00094 int size = xdim * ydim * zdim;
00095
00096
00097 if ( s <= 0 )
00098 {
00099 std::copy( input, input+size, output );
00100 return;
00101 }
00102
00103
00104 int N = boost::numeric_cast<int>( ceil( 4 * s ) + 1 );
00105 int N_half = boost::numeric_cast<int>( N/2.0);
00106 std::valarray<real_type> G( N );
00107 compute_gaussian_kernel( G, s );
00108
00109 for ( int k = 0; k < zdim; ++k )
00110 {
00111 for ( int j = 0; j < ydim; ++j )
00112 {
00113 for ( int i = 0; i < xdim; ++i )
00114 {
00115
00116
00117 int idx = ( i * ydim + j ) * zdim + k;
00118 if ( input[ idx ] == OpenTissue::math::detail::highest<value_type>() )
00119 {
00120 continue;
00121 }
00122
00123 real_type sum = real_type();
00124 for (int a = 0; a < N; ++a )
00125 {
00126
00127
00128 int newi = i;
00129 int newj = j;
00130 int newk = k;
00131 switch ( dim )
00132 {
00133 case 0:
00134 newi -= a - N_half;
00135 if ( newi < 0 )
00136 newi = -newi;
00137 if ( newi >= xdim )
00138 newi = 2 * xdim - newi - 1;
00139 break;
00140 case 1:
00141 newj -= a - N_half;
00142 if ( newj < 0 )
00143 newj = -newj;
00144 if ( newj >= ydim )
00145 newj = 2 * ydim - newj - 1;
00146 break;
00147 default:
00148 newk -= a - N_half;
00149 if ( newk < 0 )
00150 newk = -newk;
00151 if ( newk >= zdim )
00152 newk = 2 * zdim - newk - 1;
00153 break;
00154 }
00155
00156
00157 int idx2 = ( newi * ydim + newj ) * zdim + newk;
00158
00159
00160 if ( input[ idx2 ] != OpenTissue::math::detail::highest<value_type>() )
00161 sum += boost::numeric_cast<real_type>( input[ idx2 ] * G[ a ] );
00162 }
00163
00164 output[ idx ] = boost::numeric_cast<value_type>(sum);
00165 }
00166 }
00167 }
00168 }
00169
00182 template <typename value_type, typename real_type>
00183 inline void convolution3D(
00184 value_type * output
00185 , value_type const * input
00186 , int const & xdim
00187 , int const & ydim
00188 , int const & zdim
00189 , real_type const & sx
00190 , real_type const & sy
00191 , real_type const & sz
00192 )
00193 {
00194 int size = xdim * ydim * zdim;
00195
00196
00197 std::vector<value_type> tmp( size );
00198
00199
00200 std::copy( input, input+size, tmp.begin() );
00201 convolution1D( output, &(tmp[0]), xdim, ydim, zdim, 2, sz );
00202
00203
00204 std::copy( output, output+size, tmp.begin() );
00205 convolution1D( output, &(tmp[0]), xdim, ydim, zdim, 1, sy );
00206
00207
00208 std::copy( output, output+size, tmp.begin() );
00209 convolution1D( output, &(tmp[0]) , xdim, ydim, zdim, 0, sx );
00210 }
00211
00212 }
00213
00223 template<typename grid_type,typename real_type>
00224 inline void gaussian_convolution(grid_type const & src, grid_type & dst, real_type sx, real_type sy, real_type sz )
00225 {
00226 std::cout << "gaussian_convolution(): dimensions: "
00227 << src.I()
00228 << "x"
00229 << src.J()
00230 << "x"
00231 << src.K()
00232 << std::endl;
00233
00234 assert( dst.I() == src.I() || !"gaussian_convolution(): dst and src have differnet I dimension");
00235 assert( dst.J() == src.J() || !"gaussian_convolution(): dst and src have differnet I dimension");
00236 assert( dst.K() == src.K() || !"gaussian_convolution(): dst and src have differnet I dimension");
00237 int xdim = boost::numeric_cast< int>( src.I() );
00238 int ydim = boost::numeric_cast< int>( src.J() );
00239 int zdim = boost::numeric_cast< int>( src.K() );
00240 detail::convolution3D( dst.data(), src.data(), xdim, ydim, zdim, sx, sy, sz );
00241 }
00242
00243 }
00244 }
00245
00246
00247 #endif