TuttleOFX  1
SobelPlugin.cpp
Go to the documentation of this file.
00001 #include "SobelPlugin.hpp"
00002 #include "SobelProcess.hpp"
00003 #include "SobelDefinitions.hpp"
00004 
00005 #include <tuttle/plugin/ofxToGil/point.hpp>
00006 
00007 #include <terry/globals.hpp>
00008 #include <terry/point/operations.hpp>
00009 #include <terry/filter/gaussianKernel.hpp>
00010 
00011 #include <boost/gil/gil_all.hpp>
00012 #include <boost/lambda/lambda.hpp>
00013 
00014 
00015 namespace {
00016 namespace sobel {
00017 
00018 namespace exception = tuttle::plugin::exception;
00019 
00020 template< template<class,class> class Process,
00021           bool sPlanar, class SLayout, class SBits,
00022           bool dPlanar, class DLayout, class DBits,
00023           class Plugin >
00024 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args )
00025 {
00026         typedef boost::gil::pixel<SBits, SLayout> SPixel;
00027         typedef boost::gil::image<SPixel, sPlanar> SImage;
00028         typedef typename SImage::view_t SView;
00029 
00030         typedef boost::gil::pixel<DBits, DLayout> DPixel;
00031         typedef boost::gil::image<DPixel, dPlanar> DImage;
00032         typedef typename DImage::view_t DView;
00033 
00034         Process<SView, DView> procObj( plugin );
00035 
00036         procObj.setupAndProcess( args );
00037 }
00038 
00039 template< template<class,class> class Process,
00040           bool sPlanar, class SLayout, class SBits,
00041           bool dPlanar, class DLayout,
00042           class Plugin >
00043 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const OFX::EBitDepth dBitDepth )
00044 {
00045         switch( dBitDepth )
00046         {
00047                 case OFX::eBitDepthUByte:
00048                 {
00049                         localDoGilRender2<Process, sPlanar, SLayout, SBits, dPlanar, DLayout, boost::gil::bits8>( plugin, args );
00050                         return;
00051                 }
00052                 case OFX::eBitDepthUShort:
00053                 {
00054                         localDoGilRender2<Process, sPlanar, SLayout, SBits, dPlanar, DLayout, boost::gil::bits16>( plugin, args );
00055                         return;
00056                 }
00057                 case OFX::eBitDepthFloat:
00058                 {
00059                         localDoGilRender2<Process, sPlanar, SLayout, SBits, dPlanar, DLayout, boost::gil::bits32f>( plugin, args );
00060                         return;
00061                 }
00062                 case OFX::eBitDepthCustom:
00063                 case OFX::eBitDepthNone:
00064                 {
00065                         BOOST_THROW_EXCEPTION( exception::Unsupported()
00066                                 << exception::user() + "Bit depth (" + mapBitDepthEnumToString(dBitDepth) + ") not recognized by the plugin." );
00067                 }
00068         }
00069         BOOST_THROW_EXCEPTION( exception::Unknown() );
00070 }
00071 
00072 template< template<class,class> class Process,
00073           bool sPlanar, class SLayout, class SBits,
00074           bool dPlanar,
00075           class Plugin >
00076 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const OFX::EPixelComponent dComponent, const OFX::EBitDepth dBitDepth )
00077 {
00078         switch( dComponent )
00079         {
00080                 case OFX::ePixelComponentRGBA:
00081                 {
00082                         localDoGilRender2<Process, sPlanar, SLayout, SBits, dPlanar, boost::gil::rgba_layout_t>( plugin, args, dBitDepth );
00083                         return;
00084                 }
00085                 case OFX::ePixelComponentRGB:
00086                 {
00087                         localDoGilRender2<Process, sPlanar, SLayout, SBits, dPlanar, boost::gil::rgb_layout_t>( plugin, args, dBitDepth );
00088                         return;
00089                 }
00090                 case OFX::ePixelComponentAlpha:
00091                 case OFX::ePixelComponentCustom:
00092                 case OFX::ePixelComponentNone:
00093                 {
00094                         BOOST_THROW_EXCEPTION( exception::Unsupported()
00095                                 << exception::user() + "Pixel component (" + mapPixelComponentEnumToString(dComponent) + ") not supported by the plugin." );
00096                 }
00097         }
00098         BOOST_THROW_EXCEPTION( exception::Unknown() );
00099 }
00100 
00101 template< template<class,class> class Process,
00102           bool sPlanar, class SLayout, class SBits,
00103           class Plugin >
00104 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const bool dPlanar, const OFX::EPixelComponent dComponent, const OFX::EBitDepth dBitDepth )
00105 {
00106         if( dPlanar )
00107         {
00108 //              localDoGilRender2<Process, sPlanar, SLayout, SBits, true>( plugin, args, dComponent, dBitDepth );
00109         }
00110         else
00111         {
00112                 localDoGilRender2<Process, sPlanar, SLayout, SBits, false>( plugin, args, dComponent, dBitDepth );
00113         }
00114 }
00115 
00116 template< template<class,class> class Process,
00117           bool sPlanar, class SLayout,
00118           class Plugin >
00119 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const OFX::EBitDepth sBitDepth, const bool dPlanar, const OFX::EPixelComponent dComponent, const OFX::EBitDepth dBitDepth )
00120 {
00121         switch( sBitDepth )
00122         {
00123                 case OFX::eBitDepthUByte:
00124                 {
00125                         localDoGilRender2<Process, sPlanar, SLayout, boost::gil::bits8>( plugin, args, dPlanar, dComponent, dBitDepth );
00126                         return;
00127                 }
00128                 case OFX::eBitDepthUShort:
00129                 {
00130                         localDoGilRender2<Process, sPlanar, SLayout, boost::gil::bits16>( plugin, args, dPlanar, dComponent, dBitDepth );
00131                         return;
00132                 }
00133                 case OFX::eBitDepthFloat:
00134                 {
00135                         localDoGilRender2<Process, sPlanar, SLayout, boost::gil::bits32f>( plugin, args, dPlanar, dComponent, dBitDepth );
00136                         return;
00137                 }
00138                 case OFX::eBitDepthCustom:
00139                 case OFX::eBitDepthNone:
00140                 {
00141                         BOOST_THROW_EXCEPTION( exception::Unsupported()
00142                                 << exception::user() + "Bit depth (" + mapBitDepthEnumToString(sBitDepth) + ") not recognized by the plugin." );
00143                 }
00144         }
00145         BOOST_THROW_EXCEPTION( exception::Unknown() );
00146 }
00147 
00148 template< template<class,class> class Process,
00149           bool sPlanar,
00150           class Plugin >
00151 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const OFX::EPixelComponent sComponent, const OFX::EBitDepth sBitDepth, const bool dPlanar, const OFX::EPixelComponent dComponent, const OFX::EBitDepth dBitDepth )
00152 {
00153         switch( sComponent )
00154         {
00155                 case OFX::ePixelComponentRGBA:
00156                 {
00157                         localDoGilRender2<Process, sPlanar, boost::gil::rgba_layout_t>( plugin, args, sBitDepth, dPlanar, dComponent, dBitDepth );
00158                         return;
00159                 }
00160                 case OFX::ePixelComponentRGB:
00161                 {
00162                         localDoGilRender2<Process, sPlanar, boost::gil::rgb_layout_t>( plugin, args, sBitDepth, dPlanar, dComponent, dBitDepth );
00163                         return;
00164                 }
00165                 case OFX::ePixelComponentAlpha:
00166                 {
00167                         localDoGilRender2<Process, sPlanar, boost::gil::gray_layout_t>( plugin, args, sBitDepth, dPlanar, dComponent, dBitDepth );
00168                         return;
00169                 }
00170                 case OFX::ePixelComponentCustom:
00171                 case OFX::ePixelComponentNone:
00172                 {
00173                         BOOST_THROW_EXCEPTION( exception::Unsupported()
00174                                 << exception::user() + "Pixel component (" + mapPixelComponentEnumToString(sComponent) + ") not supported by the plugin." );
00175                 }
00176         }
00177 }
00178 
00179 
00180 template< template<class,class> class Process,
00181           class Plugin >
00182 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const bool sPlanar, const OFX::EPixelComponent sComponent, const OFX::EBitDepth sBitDepth, const bool dPlanar, const OFX::EPixelComponent dComponent, const OFX::EBitDepth dBitDepth )
00183 {
00184         if( sPlanar )
00185         {
00186 //              localDoGilRender2<Process, true>( plugin, args, sComponent, sBitDepth, dPlanar, dComponent, dBitDepth );
00187         }
00188         else
00189         {
00190                 localDoGilRender2<Process, false>( plugin, args, sComponent, sBitDepth, dPlanar, dComponent, dBitDepth );
00191         }
00192 }
00193 
00194 template< template<class,class> class Process,
00195           class Plugin>
00196 void localDoGilRender2( Plugin& plugin, const OFX::RenderArguments& args, const OFX::Clip& sClip, const OFX::Clip& dClip )
00197 {
00198         localDoGilRender2<Process, Plugin>( plugin, args, false, sClip.getPixelComponents(), sClip.getPixelDepth(), false, dClip.getPixelComponents(), dClip.getPixelDepth() );
00199 }
00200 
00201 }
00202 }
00203 
00204 namespace tuttle {
00205 namespace plugin {
00206 namespace sobel {
00207 
00208 
00209 SobelPlugin::SobelPlugin( OfxImageEffectHandle handle )
00210 : ImageEffectGilPlugin( handle )
00211 {
00212         _paramSize = fetchDouble2DParam( kParamSize );
00213         _paramNormalizedKernel = fetchBooleanParam( kParamNormalizedKernel );
00214         _paramReverseKernel = fetchBooleanParam( kParamReverseKernel );
00215         _paramPass = fetchChoiceParam( kParamPass );
00216         _paramKernelEpsilon = fetchDoubleParam( kParamKernelEpsilon );
00217         _paramUnidimensional = fetchBooleanParam( kParamUnidimensional );
00218         _paramBorder = fetchChoiceParam( kParamBorder );
00219         _paramComputeGradientNorm = fetchBooleanParam( kParamComputeGradientNorm );
00220         _paramGradientNormManhattan = fetchBooleanParam( kParamGradientNormManhattan );
00221         _paramComputeGradientDirection = fetchBooleanParam( kParamComputeGradientDirection );
00222         _paramGradientDirectionAbs = fetchBooleanParam( kParamGradientDirectionAbs );
00223         _paramOutputComponent = fetchChoiceParam( kParamOutputComponent );
00224 }
00225 
00226 SobelProcessParams<SobelPlugin::Scalar> SobelPlugin::getProcessParams( const OfxPointD& renderScale ) const
00227 {
00228         using namespace boost;
00229         using namespace boost::gil;
00230         using namespace terry;
00231         using namespace terry::filter;
00232         SobelProcessParams<Scalar> params;
00233 
00234         params._size   = ofxToGil( _paramSize->getValue() ) * ofxToGil( renderScale  );
00235         params._unidimensional = _paramUnidimensional->getValue();
00236         params._pass = static_cast<EParamPass>( _paramPass->getValue() );
00237 
00238         params._computeGradientNorm = _paramComputeGradientNorm->getValue();
00239         params._gradientNormManhattan = _paramGradientNormManhattan->getValue();
00240         params._computeGradientDirection = _paramComputeGradientDirection->getValue();
00241         params._gradientDirectionAbs = _paramGradientDirectionAbs->getValue();
00242 
00243         params._border = static_cast<EParamBorder>( _paramBorder->getValue() );
00244         params._boundary_option = convolve_option_extend_mirror;
00245         switch( params._border )
00246         {
00247                 case eParamBorderMirror:
00248                         params._boundary_option = convolve_option_extend_mirror;
00249                         break;
00250                 case eParamBorderConstant:
00251                         params._boundary_option = convolve_option_extend_constant;
00252                         break;
00253                 case eParamBorderBlack:
00254                         params._boundary_option = convolve_option_extend_zero;
00255                         break;
00256                 case eParamBorderPadded:
00257                         params._boundary_option = convolve_option_extend_padded;
00258                         break;
00259         }
00260 
00261         const bool normalizedKernel = _paramNormalizedKernel->getValue();
00262         const double kernelEpsilon = _paramKernelEpsilon->getValue();
00263 
00264         params._xKernelGaussianDerivative = buildGaussianDerivative1DKernel<Scalar>( params._size.x, normalizedKernel, kernelEpsilon );
00265         if( ! params._unidimensional )
00266                 params._xKernelGaussian = buildGaussian1DKernel<Scalar>( params._size.x, normalizedKernel, kernelEpsilon );
00267 
00268         if( params._size.x == params._size.y )
00269         {
00270                 params._yKernelGaussianDerivative = params._xKernelGaussianDerivative;
00271                 params._yKernelGaussian = params._xKernelGaussian;
00272         }
00273         else
00274         {
00275                 params._yKernelGaussianDerivative = buildGaussianDerivative1DKernel<Scalar>( params._size.y, normalizedKernel, kernelEpsilon );
00276                 if( ! params._unidimensional )
00277                         params._yKernelGaussian = buildGaussian1DKernel<Scalar>( params._size.y, normalizedKernel, kernelEpsilon );
00278         }
00279 
00280         if( _paramReverseKernel->getValue() )
00281         {
00282                 params._xKernelGaussianDerivative = reverse_kernel( params._xKernelGaussianDerivative );
00283                 params._yKernelGaussianDerivative = reverse_kernel( params._yKernelGaussianDerivative );
00284         }
00285         return params;
00286 }
00287 
00288 template< typename Scalar >
00289 std::ostream& operator<<( std::ostream& os, terry::filter::kernel_1d<Scalar>& kernel )
00290 {
00291         using namespace boost;
00292         os << "[";
00293         std::for_each( kernel.begin(), kernel.end(), os << lambda::_1 << "," );
00294         os << "]";
00295         return os;
00296 }
00297 
00298 void SobelPlugin::changedParam( const OFX::InstanceChangedArgs &args, const std::string &paramName )
00299 {
00300     if( paramName == kParamInfos )
00301     {
00302                 SobelProcessParams<Scalar> params = getProcessParams(args.renderScale);
00303 
00304                 std::ostringstream infos;
00305                 infos << "Kernel size for values (" << params._size.x << "x" << params._size.y << ") is:" << std::endl;
00306                 infos << "  for X (" << params._xKernelGaussian.size() << "x" << params._xKernelGaussianDerivative.size() << ")" << std::endl;
00307                 infos << "  for Y (" << params._yKernelGaussian.size() << "x" << params._yKernelGaussianDerivative.size() << ")" << std::endl;
00308                 infos << std::endl;
00309                 infos << "X :" << std::endl;
00310                 infos << params._xKernelGaussian << std::endl;
00311                 infos << params._xKernelGaussianDerivative << std::endl;
00312                 infos << "Y :" << std::endl;
00313                 infos << params._yKernelGaussian << std::endl;
00314                 infos << params._yKernelGaussianDerivative << std::endl;
00315                 infos << std::endl;
00316         
00317                 sendMessage( OFX::Message::eMessageMessage,
00318                      "", // No XML resources
00319                      infos.str() );
00320     }
00321 }
00322 
00323 void SobelPlugin::getClipPreferences( OFX::ClipPreferencesSetter& clipPreferences )
00324 {
00325         EParamOutputComponent comp = static_cast<EParamOutputComponent>(_paramOutputComponent->getValue());
00326         switch( comp )
00327         {
00328                 case eParamOutputComponentRGBA:
00329                 {
00330                         clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentRGBA );
00331                         break;
00332                 }
00333                 case eParamOutputComponentRGB:
00334                 {
00335                         clipPreferences.setClipComponents( *_clipDst, OFX::ePixelComponentRGB );
00336                         break;
00337                 }
00338         }
00339 }
00340 
00341 bool SobelPlugin::getRegionOfDefinition( const OFX::RegionOfDefinitionArguments& args, OfxRectD& rod )
00342 {
00343         OfxRectD srcRod = _clipSrc->getCanonicalRod( args.time );
00344 
00345         SobelProcessParams<Scalar> params = getProcessParams();
00346 
00347         switch( params._border )
00348         {
00349                 case eParamBorderPadded:
00350                         rod.x1 = srcRod.x1 + std::max( params._xKernelGaussianDerivative.left_size(), params._yKernelGaussian.left_size() );
00351                         rod.y1 = srcRod.y1 + std::max( params._xKernelGaussian.left_size(), params._yKernelGaussianDerivative.left_size() );
00352                         rod.x2 = srcRod.x2 - std::max( params._xKernelGaussianDerivative.right_size(), params._yKernelGaussian.right_size() );
00353                         rod.y2 = srcRod.y2 - std::max( params._xKernelGaussian.right_size(), params._yKernelGaussianDerivative.right_size() );
00354                         return true;
00355                 default:
00356                         break;
00357         }
00358         return false;
00359 }
00360 
00361 void SobelPlugin::getRegionsOfInterest( const OFX::RegionsOfInterestArguments& args, OFX::RegionOfInterestSetter& rois )
00362 {
00363         SobelProcessParams<Scalar> params = getProcessParams();
00364         OfxRectD srcRod                  = _clipSrc->getCanonicalRod( args.time );
00365 
00366         OfxRectD marge;
00367         marge.x1 = std::max( params._xKernelGaussianDerivative.left_size(), params._yKernelGaussian.left_size() );
00368         marge.y1 = std::max( params._xKernelGaussian.left_size(), params._yKernelGaussianDerivative.left_size() );
00369         marge.x2 = std::max( params._xKernelGaussianDerivative.right_size(), params._yKernelGaussian.right_size() );
00370         marge.y2 = std::max( params._xKernelGaussian.right_size(), params._yKernelGaussianDerivative.right_size() );
00371         switch( params._pass )
00372         {
00373                 case eParamPass1:
00374                 {
00375                         marge.y1 = 0;
00376                         marge.y2 = 0;
00377                         break;
00378                 }
00379                 case eParamPass2:
00380                 {
00381                         marge.x1 = 0;
00382                         marge.x2 = 0;
00383                         break;
00384                 }
00385                 case eParamPassFull:
00386                 {
00387                         break;
00388                 }
00389         }
00390         OfxRectD srcRoi;
00391         srcRoi.x1 = srcRod.x1 - marge.x1;
00392         srcRoi.y1 = srcRod.y1 - marge.y1;
00393         srcRoi.x2 = srcRod.x2 + marge.x2;
00394         srcRoi.y2 = srcRod.y2 + marge.y2;
00395         rois.setRegionOfInterest( *_clipSrc, srcRoi );
00396 }
00397 
00398 
00399 bool SobelPlugin::isIdentity( const OFX::RenderArguments& args, OFX::Clip*& identityClip, double& identityTime )
00400 {
00401         SobelProcessParams<Scalar> params = getProcessParams(args.renderScale);
00402         if( ( params._xKernelGaussianDerivative.size() == 0 || ( !params._unidimensional && params._xKernelGaussian.size() == 0 ) ) &&
00403             ( params._yKernelGaussianDerivative.size() == 0 || ( !params._unidimensional && params._yKernelGaussian.size() == 0 ) ) )
00404         {
00405                 identityClip = _clipSrc;
00406                 identityTime = args.time;
00407                 return true;
00408         }
00409         return false;
00410 }
00411 
00412 /**
00413  * @brief The overridden render function
00414  * @param[in]   args     Rendering parameters
00415  */
00416 void SobelPlugin::render( const OFX::RenderArguments &args )
00417 {
00418         ::sobel::localDoGilRender2<SobelProcess>( *this, args, *_clipSrc, *_clipDst );
00419 }
00420 
00421 
00422 }
00423 }
00424 }
00425 
00426