TuttleOFX  1
AnisotropicDiffusionProcess.tcc
Go to the documentation of this file.
00001 #include <boost/math/constants/constants.hpp>
00002 
00003 
00004 namespace tuttle {
00005 namespace plugin {
00006 namespace anisotropicFilter {
00007 namespace diffusion {
00008 
00009 static const float kEpsilon = 1e-5f;
00010 
00011 template<class View>
00012 AnisotropicDiffusionProcess<View>::AnisotropicDiffusionProcess( AnisotropicDiffusionPlugin &instance )
00013 : ImageGilFilterProcessor<View>( instance, eImageOrientationIndependant )
00014 , _plugin( instance )
00015 {
00016     _fast_approx = instance.fetchBooleanParam( kParamFastApproximation );
00017     _amplitude = instance.fetchRGBParam( kParamAmplitude );
00018 }
00019 
00020 template<class View>
00021 void AnisotropicDiffusionProcess<View>::setup( const OFX::RenderArguments &args )
00022 {
00023         // Fetch output image
00024         this->_dst.reset( _plugin._clipDst->fetchImage( args.time ) );
00025         if( !this->_dst.get( ) )
00026                 BOOST_THROW_EXCEPTION( exception::ImageNotReady() << exception::user( "Output" ) );
00027         _dBounds = this->_dst->getBounds();
00028 
00029         OFX::EBitDepth dstBitDepth = this->_dst->getPixelDepth( );
00030         OFX::EPixelComponent dstComponents = this->_dst->getPixelComponents( );
00031 
00032         // Fetch main input image
00033         this->_src.reset( _plugin._clipSrc->fetchImage( args.time ) );
00034         if( !this->_src.get( ) )
00035                 BOOST_THROW_EXCEPTION( exception::ImageNotReady() << exception::user( "Input" ) );
00036         _upScaledSrcBounds = this->_src->getBounds();
00037 
00038         if( !_plugin._clipSrcTensors->isConnected( ) )
00039                 BOOST_THROW_EXCEPTION( exception::ImageNotConnected() << exception::user( "Tensor" ) );
00040 
00041         // Fetch input tensors image
00042         _srcTensor.reset( _plugin._clipSrcTensors->fetchImage( args.time ) );
00043         if( !_srcTensor.get( ) )
00044                 BOOST_THROW_EXCEPTION( exception::ImageNotReady() << exception::user( "Tensors" ) );
00045 
00046         if( _srcTensor->getRowDistanceBytes( ) < 0 ||
00047                 this->_dst->getRowDistanceBytes( ) < 0 ||
00048             this->_src->getRowDistanceBytes( ) != _srcTensor->getRowDistanceBytes( ) )
00049         {
00050                 BOOST_THROW_EXCEPTION( exception::InOutMismatch() << exception::user( "Incompatible row bytes !" ) );
00051         }
00052 
00053         // Make sure bit depths are same
00054         OFX::EBitDepth srcBitDepth = this->_src->getPixelDepth( );
00055         OFX::EPixelComponent srcComponents = this->_src->getPixelComponents( );
00056 
00057         // See if they have the same bit depths
00058         if( srcBitDepth != dstBitDepth || srcComponents != dstComponents )
00059         {
00060                 BOOST_THROW_EXCEPTION( exception::BitDepthMismatch() );
00061         }
00062 
00063         // Build views
00064         _srcView = interleaved_view( _upScaledSrcBounds.x2 - _upScaledSrcBounds.x1,
00065                                                              _upScaledSrcBounds.y2 - _upScaledSrcBounds.y1,
00066                                                              static_cast<Pixel*>(this->_src->getPixelData()),
00067                                                              this->_src->getRowDistanceBytes() );
00068 
00069         _srcTensorView = interleaved_view( _upScaledSrcBounds.x2 - _upScaledSrcBounds.x1,
00070                                                                    _upScaledSrcBounds.y2 - _upScaledSrcBounds.y1,
00071                                                                    static_cast<Pixel*>(_srcTensor->getPixelData()),
00072                                                                    _srcTensor->getRowDistanceBytes() );
00073 
00074         this->_dstView = interleaved_view( _dBounds.x2 - _dBounds.x1,
00075                                                                    _dBounds.y2 - _dBounds.y1,
00076                                                                    static_cast<Pixel*>(this->_dst->getPixelData()),
00077                                                                    this->_dst->getRowDistanceBytes() );
00078 }
00079 
00080 /**
00081  * @brief Function called by rendering thread each time a process must be done.
00082  * @param[in] procWindowRoW  Processing window in RoW
00083  */
00084 template<class View>
00085 void AnisotropicDiffusionProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW )
00086 {
00087     using namespace boost::gil;
00088     int margin = _plugin.getMargin();
00089         OfxRGBColourD amplitude_rgb = _amplitude->getValue();
00090     region_t dregion;
00091 
00092     // dest width and height
00093     dregion.dw = procWindowRoW.x2 - procWindowRoW.x1;
00094     dregion.dh = procWindowRoW.y2 - procWindowRoW.y1;
00095 
00096     // Set upscaled source
00097     OfxRectI srcRect;
00098     srcRect.x1 = procWindowRoW.x1 - margin;
00099     srcRect.y1 = procWindowRoW.y1 - margin;
00100     srcRect.x2 = procWindowRoW.x2 + margin + 1;
00101     srcRect.y2 = procWindowRoW.y2 + margin + 1;
00102 
00103     srcRect = rectanglesIntersection(srcRect, _upScaledSrcBounds);
00104 
00105     // dest starting offset among x and y
00106     dregion.dox = procWindowRoW.x1 - srcRect.x1;
00107     dregion.doy = procWindowRoW.y1 - srcRect.y1;
00108     dregion.dw  = dregion.dox + procWindowRoW.x2 - procWindowRoW.x1;
00109     dregion.dh  = dregion.doy + procWindowRoW.y2 - procWindowRoW.y1;
00110 
00111     // We want to work in the source roi space
00112     View src = subimage_view(_srcView,
00113                              srcRect.x1 - _upScaledSrcBounds.x1,
00114                              srcRect.y1 - _upScaledSrcBounds.y1,
00115                              srcRect.x2 - srcRect.x1,
00116                              srcRect.y2 - srcRect.y1);
00117 
00118     View srct = subimage_view(_srcTensorView,
00119                               srcRect.x1 - _upScaledSrcBounds.x1,
00120                               srcRect.y1 - _upScaledSrcBounds.y1,
00121                               srcRect.x2 - srcRect.x1,
00122                               srcRect.y2 - srcRect.y1);
00123 
00124     // We want to work in the source roi space
00125     View dst = subimage_view(this->_dstView,
00126                              procWindowRoW.x1 - this->_renderArgs.renderWindow.x1 - dregion.dox,
00127                              procWindowRoW.y1 - this->_renderArgs.renderWindow.y1 - dregion.doy,
00128                              procWindowRoW.x2 - procWindowRoW.x1 + dregion.dw,
00129                              procWindowRoW.y2 - procWindowRoW.y1 + dregion.dh);
00130 
00131     blur_anisotropic( dst, src, srct, dregion, amplitude_rgb, _fast_approx->getValue() );
00132 }
00133 
00134 /**
00135  * @brief Function called to apply an anisotropic blur
00136  *
00137  * @param[out]  dst     Destination image view
00138  * @param[in]   amplitude     Amplitude of the anisotropic blur
00139  * @param dl    spatial discretization.
00140  * @param da    angular discretization.
00141  * @param gauss_prec    precision of the gaussian function.
00142  * @param fast_approx   Tell to use the fast approximation or not.
00143  *
00144  * @return Result view of the blurring process
00145  */
00146 template<class View>
00147 void AnisotropicDiffusionProcess<View>::blur_anisotropic( View &dst, View &src, View &G, const region_t & dregion,
00148                                                  const OfxRGBColourD& amplitude, const bool fast_approx /*=true*/,
00149                                                  const float dl /* =0.8f */, const float da /* = 30.0f */,
00150                                                  const float gauss_prec /*=2.0f*/ )
00151 {
00152     using namespace boost::gil;
00153     using namespace terry;
00154         
00155     typedef typename View::x_iterator dIterator;
00156     typedef typename channel_type<View>::type pix_t;
00157     typedef typename channel_type<View>::type dpix_t;
00158 
00159     if( amplitude.r > 0.0f || amplitude.g > 0.0f || amplitude.b > 0.0f )
00160     {
00161         if( src.num_channels( ) < 3 || dst.num_channels( ) < 3 )
00162         {
00163             TUTTLE_LOG_ERROR( "blur_anisotropic() : Specified tensor field (" << (int)G.width( ) << ", " << (int)G.height( ) << ", " << (int)G.num_channels( ) << ") is not valid." );
00164             return;
00165         }
00166 
00167         if( src.dimensions( ) != G.dimensions( ) )
00168         {
00169             TUTTLE_LOG_ERROR( "blur_anisotropic() : Incompatible dimensions." );
00170             return;
00171         }
00172 
00173         // Create a float compatible view
00174         typedef pixel<bits32f, devicen_layout_t< num_channels<View>::value > > comp_pixel_t;
00175         typedef image<comp_pixel_t, false, std::allocator<unsigned char> > comp_image_t;
00176         typedef typename view_type_from_pixel<comp_pixel_t>::type comp_view_t;
00177         typedef typename comp_view_t::x_iterator tmp_iterator;
00178 
00179         comp_image_t itmp( src.dimensions( ) );
00180         comp_view_t tmpv( view( itmp ) );
00181 
00182         const float amplitude_tab[] = { amplitude.r, amplitude.g, amplitude.b };
00183         const float sqrt2amplitude_r = std::sqrt( 2.0f * amplitude.r );
00184         const float sqrt2amplitude_g = std::sqrt( 2.0f * amplitude.g );
00185         const float sqrt2amplitude_b = std::sqrt( 2.0f * amplitude.b );
00186         const unsigned int
00187             dx1 = src.width( ) - 1,
00188             dy1 = src.height( ) - 1,
00189             w = src.width( ),
00190             h = src.height( ),
00191             nc = std::min( ( int ) src.num_channels( ),
00192                  std::min( 3, ( int ) dst.num_channels( ) ) );
00193 
00194         std::vector<float> sW( w * h * nc );
00195         float *pW = NULL;
00196         std::vector<float> tmp( nc );
00197         int N = 0;
00198 
00199         this->progressBegin( ( int ) ( ( 360.0f - ( 360 % ( int ) da ) / 2.0f ) / da ) * h, "PDE Denoiser algorithm in progress" );
00200         fill_black( tmpv/*subimage_view(tmpv, dregion.dox, dregion.doy, dregion.dw, dregion.dh)*/ );
00201 
00202         // 2D version of the algorithm
00203         for( float theta = ( 360 % ( int ) da ) / 2.0f;
00204              theta < 360.0f; ( theta += da ), ++N )
00205         {
00206             const float
00207                 thetar = theta * boost::math::constants::pi<float>() / 180.0f,
00208                 vx = std::cos( thetar ),
00209                 vy = std::sin( thetar );
00210             pW = &sW[0];
00211             for( unsigned int yg = 0; yg < h; ++yg )
00212             {
00213                 dIterator iterG = G.row_begin( yg );
00214                 for( unsigned int xg = 0; xg < w; ++xg )
00215                 {
00216                     const float
00217                         a = ( *iterG )[0],
00218                         b = ( *iterG )[1],
00219                         c = ( *iterG )[2];
00220                     const float
00221                         u = a * vx + b*vy,
00222                         v = b * vx + c*vy,
00223                         n = std::sqrt( kEpsilon + u * u + v * v );
00224                     float dln = 0.0f;
00225                     if( n > 0.0f )
00226                         dln = dl / n;
00227 
00228                     pW[0] = u * dln;
00229                     pW[1] = v * dln;
00230                     pW[2] = n;
00231                     pW += nc;
00232                     iterG++;
00233                 }
00234             }
00235             pW = &sW[0];
00236             for( unsigned int y = 0; y < h; ++y )
00237             {
00238                 tmp_iterator tmp_it = tmpv.row_begin( y );
00239                 dIterator view_it = src.row_begin( y );
00240                 for( unsigned int x = 0; x < w; ++x )
00241                 {
00242                     memset( &tmp[0], 0, sizeof(float ) * nc );
00243                     const float
00244                         cu = pW[0],
00245                         cv = pW[1],
00246                         n = pW[2],
00247                         fsigma_r = sqrt2amplitude_r * n,
00248                         length_r = gauss_prec * fsigma_r,
00249                         fsigma2_r = 2.0f * fsigma_r * fsigma_r,
00250                         fsigma_g = sqrt2amplitude_g * n,
00251                         length_g = gauss_prec * fsigma_g,
00252                         fsigma2_g = 2.0f * fsigma_g * fsigma_g,
00253                         fsigma_b = sqrt2amplitude_b * n,
00254                         length_b = gauss_prec * fsigma_b,
00255                         fsigma2_b = 2.0f * fsigma_b * fsigma_b;
00256 
00257                     const float lrgba[] = { length_r, length_g, length_b,
00258                                             length_r + length_g + length_b / 3.0f };
00259 
00260                     const float srgba[] = { fsigma2_r, fsigma2_g, fsigma2_b,
00261                                             fsigma2_r + fsigma2_g + fsigma2_b / 3.0f };
00262 
00263                     float S, pu, pv, X, Y;
00264                     pW += nc;
00265                     if( n == 0.0f )
00266                     {
00267                         for( unsigned int i = 0; i < nc; ++i )
00268                             ( *tmp_it )[i] += ( *view_it )[i];
00269                     }
00270                     else
00271                     {
00272                         // Nearest-neighbor interpolation for 2D images
00273                         if( fast_approx )
00274                         {
00275                             for( unsigned int i = 0; i < nc; ++i )
00276                             {
00277                                 X = ( float ) x;
00278                                 Y = ( float ) y;
00279                                 S = 0.0f;
00280                                 pu = cu;
00281                                 pv = cv;
00282                                 if( amplitude_tab[i] > 0 )
00283                                     for( float l = 0.0f; l < lrgba[i] &&
00284                                          X >= 0.0f &&
00285                                          X <= dx1 &&
00286                                          Y >= 0.0f &&
00287                                          Y <= dy1; l += dl )
00288                                     {
00289                                         const int
00290                                             cx = ( int ) ( X + 0.5f ),
00291                                             cy = ( int ) ( Y + 0.5f );
00292                                         float
00293                                             u = sW[( cy * w + cx ) * nc + 0],
00294                                             v = sW[( cy * w + cx ) * nc + 1];
00295                                         if( ( pu * u + pv * v ) < 0.0f )
00296                                         {
00297                                             u = -u;
00298                                             v = -v;
00299                                         }
00300                                         tmp[i] += src( cx, cy )[i];
00301                                         ++S;
00302                                         X += ( pu = u );
00303                                         Y += ( pv = v );
00304                                     }
00305                                 if( S > 0 )
00306                                     ( *tmp_it )[i] += ( dpix_t ) ( tmp[i] / S );
00307                                 else
00308                                     (*tmp_it )[i] += ( *view_it )[i];
00309                             }
00310                         }
00311                         else
00312                         {
00313                             for( unsigned int i = 0; i < nc; ++i )
00314                             {
00315                                 X = ( float ) x;
00316                                 Y = ( float ) y;
00317                                 S = 0.0f;
00318                                 pu = cu;
00319                                 pv = cv;
00320                                 if( amplitude_tab[i] > 0.0f )
00321                                     for( float l = 0.0f; l < lrgba[i] &&
00322                                          X >= 0.0f &&
00323                                          X <= dx1 &&
00324                                          Y >= 0.0f &&
00325                                          Y <= dy1; l += dl )
00326                                     {
00327                                         const int
00328                                             cx = ( int ) ( X + 0.5f ),
00329                                             cy = ( int ) ( Y + 0.5f );
00330                                         float
00331                                             u = sW[( cy * w + cx ) * nc + 0],
00332                                             v = sW[( cy * w + cx ) * nc + 1];
00333                                         if( ( pu * u + pv * v ) < 0.0f )
00334                                         {
00335                                             u = -u;
00336                                             v = -v;
00337                                         }
00338                                         const float coef = std::exp( -l * l / srgba[i] );
00339                                         tmp[i] += coef * src( cx, cy )[i];
00340                                         S += coef;
00341                                         X += ( pu = u );
00342                                         Y += ( pv = v );
00343                                     }
00344                                 if( S > 0 )
00345                                     ( *tmp_it )[i] += ( dpix_t ) ( tmp[i] / S );
00346                                 else
00347                                     (*tmp_it )[i] += ( *view_it )[i];
00348                             }
00349                         }
00350                     }
00351                     ++view_it;
00352                     ++tmp_it;
00353                 }
00354                 if( this->progressForward( w ) )
00355                     return;
00356             }
00357         }
00358 
00359         for( unsigned int y = dregion.doy; y < dregion.dh; ++y )
00360         {
00361             tmp_iterator t_iter = tmpv.row_begin( y );
00362             dIterator d_iter = dst.row_begin( y );
00363             t_iter += dregion.dox;
00364             d_iter += dregion.dox;
00365 
00366             for( unsigned int x = dregion.dox; x < dregion.dw; ++x )
00367             {
00368                 for( unsigned int c = 0; c < nc; ++c )
00369                 {
00370                     ( *d_iter )[c] = ( dpix_t ) ( ( *t_iter )[c] / N );
00371                 }
00372                 ++d_iter;
00373                 ++t_iter;
00374             }
00375         }
00376     }
00377     else
00378         {
00379         copy_pixels( subimage_view(src, dregion.dox, dregion.doy, dregion.dw, dregion.dh),
00380                      subimage_view(dst, dregion.dox, dregion.doy, dregion.dw, dregion.dh) );
00381         }
00382 }
00383 
00384 }
00385 }
00386 }
00387 }