TuttleOFX
1
|
00001 /** 00002 * @brief This file provides a class for tensors image generation. 00003 */ 00004 00005 #ifndef _TUTTLE_PLUGIN_IMAGE_TENSORS_HPP_ 00006 #define _TUTTLE_PLUGIN_IMAGE_TENSORS_HPP_ 00007 00008 #include "filters/edgeDetect.hpp" 00009 #include "filters/blurFilters.hpp" 00010 00011 #include <tuttle/plugin/IProgress.hpp> 00012 #include <terry/math.hpp> 00013 00014 #include <boost/gil/gil_all.hpp> 00015 00016 #include <vector> 00017 #include <string> 00018 #include <float.h> 00019 00020 namespace tuttle { 00021 namespace imageUtils { 00022 00023 /** 00024 * @brief Structure handling anisotropic gradient parameters. 00025 */ 00026 template <typename TensorView> 00027 struct tensor_t 00028 { 00029 00030 tensor_t( ) 00031 : dox(0), doy(0), dw(0), dh(0), algorithm( false ), stAlgo( 0 ), 00032 alpha( 0.0 ), sigma( 0.0 ), sharpness( 0.0 ), 00033 anisotropy( 0.0 ), geom_fact( 0.0 ), threshold( 0.0 ) { }; 00034 int dox, doy, dw, dh; 00035 bool algorithm; ///< Generation algorithm 00036 int stAlgo; ///< Structure tensors algorithm 00037 double alpha; ///< Pre-blurring (noise scale) 00038 double sigma; ///< Post-blurring 00039 double sharpness; ///< Contour preservation 00040 double anisotropy; ///< Anisotropic filtering 00041 double geom_fact; ///< Geometry factor 00042 double threshold; ///< Thresholding quantization factor 00043 }; 00044 00045 /** 00046 * @brief Class used to render tensors 00047 */ 00048 template <class View> 00049 class ImageTensors : public View 00050 { 00051 private: 00052 template <class D_ITER> 00053 void compute_vectors( D_ITER & iter_dst, const std::vector<double> & val, 00054 const std::vector<double> & vec, 00055 const double power1, const double power2 ); 00056 00057 public: 00058 00059 typedef enum 00060 { 00061 eAnisotGradient 00062 } E_TensorsAlgorithm; 00063 00064 ImageTensors( const View & view ) : View( view ) { } 00065 00066 ImageTensors( int &width, int &height, typename View::xy_locator loc ) : View( width, height, loc ) { } 00067 00068 virtual ~ImageTensors( ) { } 00069 //@todo: add other constructors 00070 00071 void process( const View & srcView, E_TensorsAlgorithm tensAlgo, 00072 tuttle::plugin::IProgress *progress, void *args ); 00073 void anisotropic_gradient( const View & src, tuttle::plugin::IProgress *progress, tensor_t<View> *args ); 00074 }; 00075 00076 /** 00077 * @brief Process rendering 00078 * 00079 * @param[in] srcView source view 00080 * @param[in] progress tensor algorithm 00081 * @param[in] args algorithm parameters 00082 * 00083 */ 00084 template <class View> 00085 void ImageTensors<View>::process( const View & srcView, E_TensorsAlgorithm tensAlgo, 00086 tuttle::plugin::IProgress *progress, void *args ) 00087 { 00088 switch( tensAlgo ) 00089 { 00090 case eAnisotGradient: 00091 anisotropic_gradient( srcView, progress, ( tensor_t<View>* )args ); 00092 break; 00093 } 00094 progress->progressEnd( ); 00095 } 00096 00097 template <class View> 00098 template <class D_ITER> 00099 void ImageTensors<View>::compute_vectors( D_ITER & iter_dst, const std::vector<double> & val, 00100 const std::vector<double> & vec, 00101 const double power1, const double power2 ) 00102 { 00103 typedef typename bgil::channel_type<D_ITER>::type pix_t; 00104 const double 00105 // The more is l1 high, the more smoothing will be performed along 00106 // the edges direction (because n1 << n2). 00107 // Otherwise, the smoothing will be performed 00108 // along all directions (because n1 =~ n2). 00109 l1 = val[1], 00110 l2 = val[0], 00111 // (ux,uy) is orthogonal to (vx, vy) 00112 vx = vec[0], 00113 vy = vec[1], 00114 ux = vec[2], 00115 uy = vec[3], 00116 // n1, n2 set the strengths of the desired smoothing factor along 00117 // respectives directions. 00118 n1 = std::pow( 1.0 + l1 + l2, -power1 ), 00119 n2 = std::pow( 1.0 + l1 + l2, -power2 ), 00120 // Gaussian kernel strength for horizontal smoothing 00121 c0 = n1 * ux * ux + n2 * vx*vx, 00122 // Gaussian kernel strength for diagonal smoothing 00123 c1 = n1 * ux * uy + n2 * vx*vy, 00124 // Gaussian kernel strength for vertical smoothing 00125 c2 = n1 * uy * uy + n2 * vy*vy; 00126 /* 00127 c0 = c0 < 0.0 ? 0.0 : (c0 > 1.0 ? 1.0 : c0); 00128 c1 = c1 < 0.0 ? 0.0 : (c1 > 1.0 ? 1.0 : c1); 00129 c2 = c2 < 0.0 ? 0.0 : (c2 > 1.0 ? 1.0 : c2); 00130 */ 00131 // Compute final values 00132 ( *iter_dst )[0] = pix_t( c0 ); 00133 ( *iter_dst )[1] = pix_t( c1 ); 00134 ( *iter_dst )[2] = pix_t( c2 ); 00135 } 00136 00137 /** 00138 * @brief Anisotropic gradient 00139 * 00140 * @param[in] srcView source view 00141 * @param[in] args algorithm parameters 00142 * 00143 */ 00144 template <class View> 00145 void ImageTensors<View>::anisotropic_gradient( const View & src, tuttle::plugin::IProgress *progress, tensor_t<View> *args ) 00146 { 00147 using namespace boost::gil; 00148 using namespace terry; 00149 float alpha = ( float ) args->alpha; 00150 float sigma = ( float ) args->sigma; 00151 float sharpness = ( float ) args->sharpness; 00152 float anisotropy = ( float ) args->anisotropy; 00153 float geom_factor = ( float ) args->geom_fact; 00154 float threshold = ( float ) args->threshold / 1000.0f; 00155 int stAlgo = args->stAlgo; 00156 bool tensorAlgo = args->algorithm; 00157 00158 if( anisotropy < 0.0f || anisotropy > 1.0f ) 00159 return; 00160 if( alpha < 0.0f ) 00161 return; 00162 if( sigma < 0.0f ) 00163 return; 00164 if( sharpness < 0.0f ) 00165 return; 00166 00167 // Float type to process computation with reals 00168 typedef typename image_from_view<View>::type image_t; 00169 typedef typename View::x_iterator iterator; 00170 typedef typename View::x_iterator tmp_iterator; 00171 typedef typename View::locator locator; 00172 00173 const double nsharpness = std::max( ( double ) sharpness, 1e-5 ), 00174 power1 = 0.5 * nsharpness, 00175 power2 = power1 / ( 1e-7 + 1.0 - anisotropy ); 00176 std::vector<double> val( 2 ); 00177 std::vector<double> vec( 4 ); 00178 View & dst = *( View* )this; 00179 00180 progress->progressBegin( 5 * 25, "Tensors generator algorithm in progress" ); 00181 image_t tmp1( src.dimensions() ); 00182 image_t tmp2( src.dimensions() ); 00183 View tmpv1( view( tmp1 ) ); 00184 View tmpv2( view( tmp2 ) ); 00185 // Apply pre-blur (attenuate noise effect in tensors map) 00186 dericheFilter( src, tmpv1, alpha ); 00187 if( progress->progressForward( 25 ) ) 00188 return; 00189 00190 // Multiply or normalize tensors to amplify image geometry 00191 if( geom_factor > 0.0f ) 00192 multiply( tmpv1, tmpv2, geom_factor ); 00193 else if( geom_factor < 0.0f ) 00194 normalize( tmpv1, tmpv2, 0.0f, -geom_factor ); 00195 else 00196 copy_pixels( tmpv1, tmpv2 ); 00197 if( progress->progressForward( 25 ) ) 00198 return; 00199 00200 // Compute structure tensors 00201 switch( stAlgo ) 00202 { 00203 case 0: 00204 // Using precise forward backward finite differences 00205 simple_structure_tensor( tmpv2, tmpv1, threshold ); 00206 break; 00207 case 1: 00208 // Using harris edges detection 00209 harris( tmpv2, tmpv1, threshold ); 00210 break; 00211 case 2: 00212 // Using canny-deriche edges detection 00213 dericheFilter( tmpv2, tmpv1, alpha, 1, threshold ); 00214 break; 00215 default: 00216 return; 00217 break; 00218 } 00219 00220 if( progress->progressForward( 25 ) ) 00221 return; 00222 00223 // Apply a post-blur to attenuate the texture 00224 // of the gradient image 00225 dericheFilter( tmpv1, tmpv2, sigma ); 00226 if( progress->progressForward( 25 ) ) 00227 return; 00228 00229 // Compute diffusion tensors (gaussian kernel directions map). 00230 if( tensorAlgo == false ) 00231 { 00232 const float step = 25 / (args->dh - args->doy); 00233 for( int y = args->doy; y < args->dh; ++y ) 00234 { 00235 iterator src_it = tmpv2.row_begin( y ); 00236 iterator dst_it = this->row_begin( y - args->doy ); 00237 if( progress->progressForward( ( int ) step ) ) 00238 return; 00239 src_it += args->dox; 00240 for( int x = args->dox; x < args->dw; ++x ) 00241 { 00242 // eigen value and vectors gives strength and direction of 00243 // the vectors for the gaussian kernel. 00244 symmetric_eigen( src_it, val, vec ); 00245 // Compute vector directions: 00246 // r = along X, g = along diagonal, b = along y 00247 compute_vectors( dst_it, val, vec, power1, power2 ); 00248 dst_it++; 00249 src_it++; 00250 } 00251 } 00252 } 00253 else 00254 { 00255 copy_pixels( subimage_view(tmpv2, args->dox, args->doy, dst.width(), dst.height()), dst ); 00256 } 00257 } 00258 00259 } 00260 } 00261 00262 #endif