TuttleOFX
1
|
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 ¶mName ) 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