TuttleOFX  1
PushPixelProcess.tcc
Go to the documentation of this file.
00001 #include "PushPixelPlugin.hpp"
00002 #include "PushPixelDefinitions.hpp"
00003 #include "PushPixelProcess.hpp"
00004 
00005 #include <tuttle/plugin/exceptions.hpp>
00006 #include <tuttle/plugin/memory/OfxAllocator.hpp>
00007 #include <tuttle/common/math/rectOp.hpp>
00008 
00009 #include <terry/globals.hpp>
00010 #include <terry/basic_colors.hpp>
00011 #include <terry/channel_view.hpp>
00012 #include <terry/filter/motionVectors.hpp>
00013 #include <terry/filter/convolve.hpp>
00014 #include <terry/sampler/all.hpp>
00015 
00016 #include <boost/gil/utilities.hpp>
00017 #include <boost/mpl/if.hpp>
00018 #include <boost/type_traits/is_floating_point.hpp>
00019 
00020 namespace tuttle {
00021 namespace plugin {
00022 namespace pushPixel {
00023 
00024 template<class View>
00025 PushPixelProcess<View>::PushPixelProcess( PushPixelPlugin &effect )
00026 : ImageGilFilterProcessor<View>( effect, eImageOrientationIndependant )
00027 , _plugin( effect )
00028 {
00029         _clipMask = effect.fetchClip( kClipMask );
00030         _clipMaskConnected = this->_clipMask->isConnected();
00031 }
00032 
00033 template <class View>
00034 void PushPixelProcess<View>::setup( const OFX::RenderArguments& args )
00035 {
00036         ImageGilFilterProcessor<View>::setup( args );
00037 
00038         // mask view
00039         if( _clipMaskConnected )
00040         {
00041                 this->_mask.reset( _clipMask->fetchImage( args.time ) );
00042                 if( !this->_mask.get( ) )
00043                         BOOST_THROW_EXCEPTION( exception::ImageNotReady() );
00044                 if( this->_mask->getRowDistanceBytes( ) <= 0 )
00045                         BOOST_THROW_EXCEPTION( exception::WrongRowBytes() );
00046                 this->_maskView = this->getView( this->_mask.get(), _clipMask->getPixelRod(args.time, args.renderScale) );
00047                 
00048                 if( OFX::getImageEffectHostDescription()->hostName == "uk.co.thefoundry.nuke" )
00049                 {
00050                         // bug in nuke, getRegionOfDefinition() on OFX::Image returns bounds
00051                         _maskPixelRod   = _clipMask->getPixelRod( args.time, args.renderScale );
00052                 }
00053                 else
00054                 {
00055                         _maskPixelRod = _mask->getRegionOfDefinition();
00056                 }
00057         }
00058 
00059         _params = _plugin.getProcessParams( args.renderScale );
00060 
00061         /*
00062         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_renderArgs.fieldToRender );
00063         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_renderArgs.renderScale );
00064         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_renderArgs.renderWindow );
00065         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_renderArgs.time );
00066         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_srcPixelRod );
00067         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_dstPixelRod );
00068         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_srcView.width(), this->_srcView.height() );
00069         TUTTLE_LOG_VAR( TUTTLE_INFO, this->_dstView.width(), this->_dstView.height() );
00070         */
00071 }
00072 
00073 /**
00074  * @brief Function called by rendering thread each time a process must be done.
00075  * @param[in] procWindowRoW  Processing window
00076  */
00077 template<class View>
00078 void PushPixelProcess<View>::multiThreadProcessImages( const OfxRectI& procWindowRoW )
00079 {
00080         using namespace boost::gil;
00081         using namespace terry;
00082         using namespace terry::filter;
00083         
00084         typedef View MaskView; /// @todo add a MaskView template parameter...
00085         
00086         const OfxRectI procWindowOutput = this->translateRoWToOutputClipCoordinates( procWindowRoW );
00087         const OfxPointI procWindowSize = {
00088                 procWindowRoW.x2 - procWindowRoW.x1,
00089                 procWindowRoW.y2 - procWindowRoW.y1
00090                 };
00091 
00092         // use View channel type if floating point else use bit32f
00093         typedef typename channel_mapping_type<View>::type Channel;
00094         typedef typename boost::mpl::if_< boost::is_floating_point<Channel>,
00095                                    Channel,
00096                                                            bits32f>::type ChannelFloat;
00097         typedef pixel<ChannelFloat, gray_layout_t> PixelGray;
00098         typedef image<PixelGray, false> ImageGray;
00099         typedef typename ImageGray::view_t ViewGray;
00100 
00101         OfxRectI usedMaskPixelRod; // the mask RoD (depending on the clip mask used)
00102         if( _clipMaskConnected )
00103                 usedMaskPixelRod = this->_maskPixelRod;
00104         else
00105                 usedMaskPixelRod = this->_srcPixelRod;
00106 
00107         const OfxRectI imgGradientWin = rectanglesIntersection( procWindowRoW, usedMaskPixelRod );
00108         const bool partialGradient = (imgGradientWin != procWindowRoW); // if true we can only calculate a gradient for a subpart of the procWindow
00109         if( _params._output == eParamOutputMotionVectors && partialGradient )
00110         {
00111                 // fill the procWindow in black
00112                 View dst = subimage_view( this->_dstView, procWindowOutput.x1, procWindowOutput.y1,
00113                                                                   procWindowSize.x,
00114                                                                   procWindowSize.y );
00115                 Pixel fillingColor = get_black( this->_srcView );
00116                 boost::gil::fill_pixels( dst, fillingColor );
00117         }
00118         // if gradient window is empty there is nothing to do
00119         // so simply copy source clip
00120         if( (imgGradientWin.y2 - imgGradientWin.y1 == 0) ||
00121             (imgGradientWin.x2 - imgGradientWin.x1 == 0) )
00122         {
00123                 switch( _params._output )
00124                 {
00125                         case eParamOutputMotionVectors:
00126                         {
00127                                 BOOST_ASSERT( partialGradient == true );
00128                                 // the output is already fill in black
00129                                 return;
00130                         }
00131                         case eParamOutputPushPixel:
00132                         {
00133                                 const OfxRectI procWindowSrc = translateRegion( procWindowRoW, this->_srcPixelRod );
00134 
00135                                 View src = subimage_view( this->_srcView, procWindowSrc.x1, procWindowSrc.y1,
00136                                                                                   procWindowSize.x,
00137                                                                                   procWindowSize.y );
00138                                 View dst = subimage_view( this->_dstView, procWindowOutput.x1, procWindowOutput.y1,
00139                                                                                   procWindowSize.x,
00140                                                                                   procWindowSize.y );
00141                                 copy_pixels( src, dst );
00142                                 return;
00143                         }
00144                 }
00145         }
00146 
00147         const OfxPointI imgGradientSize = { imgGradientWin.x2 - imgGradientWin.x1,
00148                                             imgGradientWin.y2 - imgGradientWin.y1 };
00149         ImageGray xGradientImage( imgGradientSize.x, imgGradientSize.y );
00150         ImageGray yGradientImage( imgGradientSize.x, imgGradientSize.y );
00151         ViewGray xGradientView = view(xGradientImage);
00152         ViewGray yGradientView = view(yGradientImage);
00153         Point proc_mask_tl( imgGradientWin.x1 - usedMaskPixelRod.x1, imgGradientWin.y1 - usedMaskPixelRod.y1 );
00154         
00155         /*
00156         TUTTLE_LOG_VAR( TUTTLE_INFO, usedMaskPixelRod );
00157         TUTTLE_LOG_VAR( TUTTLE_INFO, imgGradientWin );
00158         TUTTLE_LOG_VAR( TUTTLE_INFO, procWindowRoW );
00159         TUTTLE_LOG_VAR( TUTTLE_INFO, partialGradient );
00160         TUTTLE_LOG_VAR( TUTTLE_INFO, procWindowOutput );
00161         TUTTLE_LOG_VAR( TUTTLE_INFO, procWindowSize );
00162         TUTTLE_LOG_VAR( TUTTLE_INFO, imgGradientSize );
00163         TUTTLE_LOG_VAR( TUTTLE_INFO, proc_mask_tl );
00164         */
00165 
00166         // compute motion vectors
00167         if( _clipMaskConnected )
00168         {
00169                 // choose the mask channel to use
00170                 // alpha_t if the image contains an alpha channel like rgba
00171                 // gray_t if grayscale image
00172                 typedef typename MaskView::value_type MaskPixel;
00173                 typedef typename boost::mpl::if_<contains_color<MaskPixel, alpha_t>,
00174                         alpha_t,
00175                         gray_t>::type MaskColorChannel;
00176                 typedef channel_view_type<MaskColorChannel, MaskView> KthChannelView;
00177                 typename KthChannelView::type channelMaskView = KthChannelView::make(this->_maskView); // gray or alpha channel
00178 
00179                 if( correlateMotionVectors<OfxAllocator, ViewGray, typename KthChannelView::type, Point, Scalar>( xGradientView, yGradientView, channelMaskView, proc_mask_tl, _params._kernelGaussianDerivative, _params._kernelGaussian, _params._boundary_option, this->getOfxProgress() ) )
00180                         return;
00181         }
00182         else
00183         {
00184                 typedef channel_view_type<alpha_t, View> KthChannelView;
00185                 typename KthChannelView::type channelMaskView = KthChannelView::make(this->_srcView); // alpha channel
00186                 
00187                 if( correlateMotionVectors<OfxAllocator, ViewGray, typename KthChannelView::type, Point, Scalar>( xGradientView, yGradientView, channelMaskView, proc_mask_tl, _params._kernelGaussianDerivative, _params._kernelGaussian, _params._boundary_option, this->getOfxProgress() ) )
00188                         return;
00189         }
00190 
00191         if( modifyVectors( xGradientView, yGradientView, this->_params._angle, _params._intensity, this->getOfxProgress() ) )
00192                         return;
00193 
00194         // apply motion vectors
00195         switch( _params._output )
00196         {
00197                 case eParamOutputMotionVectors:
00198                 {
00199                         const OfxRectI gradientRodInSrc = translateRegion( imgGradientWin, this->_srcPixelRod );
00200                         // subdst is the part of dst for which we have motion vectors information
00201                         View subdst = subimage_view( this->_dstView,
00202                                         gradientRodInSrc.x1, gradientRodInSrc.y1,
00203                                         imgGradientSize.x, imgGradientSize.y );
00204                         copy_and_convert_pixels( xGradientView, kth_channel_view<0>(subdst) ); // put x vectors
00205                         if( this->progressForward( procWindowSize.y * 0.5 ) )
00206                                 return;
00207                         copy_and_convert_pixels( yGradientView, kth_channel_view<1>(subdst) ); // put y vectors
00208                         if( this->progressForward( procWindowSize.y * 0.5 ) )
00209                                 return;
00210                         return;
00211                 }
00212                 case eParamOutputPushPixel:
00213                 {
00214                         switch( _params._interpolation )
00215                         {
00216                                 /// @todo add all interpolation methods
00217                                 case eParamInterpolationNearest:
00218                                         motionvectors_resample_pixels<sampler::nearest_neighbor_sampler>(
00219                                                         this->_srcView, this->_srcPixelRod,
00220                                                         xGradientView, yGradientView, imgGradientWin,
00221                                                         this->_dstView, this->_dstPixelRod,
00222                                                         procWindowRoW,
00223                                                         sampler::eParamFilterOutBlack,
00224                                                         this->getOfxProgress() );
00225                                         return;
00226                                 case eParamInterpolationBilinear:
00227                                         motionvectors_resample_pixels<sampler::bilinear_sampler>(
00228                                                         this->_srcView, this->_srcPixelRod,
00229                                                         xGradientView, yGradientView, imgGradientWin,
00230                                                         this->_dstView, this->_dstPixelRod,
00231                                                         procWindowRoW,
00232                                                         sampler::eParamFilterOutBlack,
00233                                                         this->getOfxProgress() );
00234                                         return;
00235                         }
00236                         TUTTLE_LOG_ERROR( "Interpolation method not recognize." );
00237                         return;
00238                 }
00239         }
00240 }
00241 
00242 }
00243 }
00244 }