TuttleOFX  1
motionVectors.hpp
Go to the documentation of this file.
00001 #ifndef _TERRY_FILTER_MOTIONVECTORS_HPP_
00002 #define _TERRY_FILTER_MOTIONVECTORS_HPP_
00003 
00004 #include <terry/channel.hpp>
00005 #include <terry/filter/convolve.hpp>
00006 #include <terry/sampler/sampler.hpp>
00007 #include <terry/sampler/details.hpp>
00008 #include <terry/point/operations.hpp>
00009 
00010 #include <boost/gil/utilities.hpp>
00011 #include <boost/gil/typedefs.hpp>
00012 
00013 #include <boost/mpl/if.hpp>
00014 #include <boost/type_traits/is_same.hpp>
00015 
00016 #include <cmath>
00017 
00018 namespace terry {
00019 namespace filter {
00020 
00021 /**
00022  * @brief change intensity and rotate vectors.
00023  * @param [in/out] xVecView image of x vectors
00024  * @param [in/out] yVecView image of y vectors
00025  * @param [in] angle rotation to apply on vectors (radian)
00026  * @param [in] intensity scale vectors values
00027  * @param [in] p inform progress
00028  */
00029 template< typename View, typename Progress >
00030 // Models RandomAccess2DImageViewConcept
00031 bool modifyVectors( const View& xVecView, const View& yVecView,
00032                     const double angle, const double intensity,
00033                     Progress& p )
00034 {
00035         BOOST_ASSERT( yVecView.width() != 0 );
00036         BOOST_ASSERT( yVecView.height() != 0 );
00037         BOOST_ASSERT( yVecView.width() == xVecView.width() );
00038         BOOST_ASSERT( yVecView.height() == xVecView.height() );
00039 
00040         typedef typename View::point_t Point2Integer;
00041         typedef typename terry::channel_base_type<typename boost::gil::channel_type<View>::type>::type VecChannel;
00042         typedef typename boost::gil::point2<VecChannel> VecPoint2;
00043 
00044         const double cosAngle = std::cos( angle );
00045         const double sinAngle = std::sin( angle );
00046 
00047         for( int y = 0;
00048              y < xVecView.height();
00049              ++y )
00050         {
00051                 typename View::x_iterator it_xVec    = xVecView.row_begin( y );
00052                 typename View::x_iterator itEnd_xVec = xVecView.row_end( y );
00053                 typename View::x_iterator it_yVec    = yVecView.row_begin( y );
00054                 for( ;
00055                      it_xVec != itEnd_xVec;
00056                      ++it_xVec, ++it_yVec )
00057                 {
00058                         VecPoint2 gradient;
00059                         gradient.x = boost::gil::get_color( *it_xVec, boost::gil::gray_color_t() );
00060                         gradient.y = boost::gil::get_color( *it_yVec, boost::gil::gray_color_t() );
00061 
00062                         // apply rotation on gradient vector
00063                         VecPoint2 motion;
00064                         motion.x = gradient.x * cosAngle + gradient.y * sinAngle;
00065                         motion.y = gradient.y * cosAngle - gradient.x * sinAngle;
00066 
00067                         motion *= intensity;
00068 
00069                         boost::gil::get_color( *it_xVec, boost::gil::gray_color_t() ) = motion.x;
00070                         boost::gil::get_color( *it_yVec, boost::gil::gray_color_t() ) = motion.y;
00071                 }
00072                 if( p.progressForward( xVecView.width() ) )
00073                         return true;
00074         }
00075         return false;
00076 }
00077 
00078 template<
00079         typename GView,
00080         typename View,
00081         typename Point,
00082         typename Scalar,
00083         typename Progress>
00084 bool correlateMotionVectors( GView& xGradientView, GView& yGradientView, View& img, const Point& topleft,
00085                              const terry::filter::kernel_1d<Scalar>& kernel, const convolve_boundary_option boundary_option,
00086                              Progress& p )
00087 {
00088         typedef typename GView::value_type GPixel;
00089         using namespace boost::gil;
00090         correlate_rows<GPixel>( color_converted_view<GPixel>( img ), kernel, xGradientView, topleft, boundary_option );
00091         if( p.progressForward( xGradientView.size() ) )
00092                 return true;
00093         correlate_cols<GPixel>( color_converted_view<GPixel>( img ), kernel, yGradientView, topleft, boundary_option );
00094         if( p.progressForward( yGradientView.size() ) )
00095                 return true;
00096         return false;
00097 }
00098 
00099 template<
00100         template<typename> class Alloc,
00101         typename GView,
00102         typename View,
00103         typename Point,
00104         typename Scalar,
00105         typename Progress>
00106 bool correlateMotionVectors( GView& xGradientView, GView& yGradientView, View& img, const Point& topleft,
00107                                                          const terry::filter::kernel_1d<Scalar>& kernel, const terry::filter::kernel_1d<Scalar>& kernelSecondary,
00108                                                          const convolve_boundary_option boundary_option,
00109                                                          Progress& p )
00110 {
00111         typedef typename GView::value_type GPixel;
00112         using namespace boost::gil;
00113         correlate_rows_cols<GPixel,Alloc>( color_converted_view<GPixel>( img ), kernel, kernelSecondary, xGradientView, topleft, boundary_option );
00114         if( p.progressForward( xGradientView.size() ) )
00115                 return true;
00116         correlate_rows_cols<GPixel,Alloc>( color_converted_view<GPixel>( img ), kernelSecondary, kernel, yGradientView, topleft, boundary_option );
00117         if( p.progressForward( yGradientView.size() ) )
00118                 return true;
00119         return false;
00120 }
00121 
00122 /**
00123  * @brief Moves the pixels based on the variation of the mask (the derivative: [-1 0 1] kernel)
00124  */
00125 template<
00126         typename Sampler, // Models SamplerConcept
00127         typename SrcView, // Models RandomAccess2DImageViewConcept
00128         typename VecView, // Models RandomAccess2DImageViewConcept
00129         typename DstView,
00130         typename Progress>
00131 // Models MutableRandomAccess2DImageViewConcept
00132 bool motionvectors_resample_pixels( const SrcView& srcView, const Rect<std::ssize_t>& srcRod,
00133                                     const VecView& xVecView, const VecView& yVecView, const Rect<std::ssize_t>& vecRod,
00134                                     const DstView& dstView, const Rect<std::ssize_t>& dstRod,
00135                                     const Rect<std::ssize_t>& procWindowRoW,
00136                                     const sampler::EParamFilterOutOfImage outOfImageProcess,
00137                                     Progress& p,
00138                                     Sampler sampler = Sampler() )
00139 {
00140         BOOST_ASSERT( srcView.width() == srcRod.x2 - srcRod.x1 );
00141         BOOST_ASSERT( srcView.height() == srcRod.y2 - srcRod.y1 );
00142 
00143         BOOST_ASSERT( xVecView.width() == vecRod.x2 - vecRod.x1 );
00144         BOOST_ASSERT( xVecView.height() == vecRod.y2 - vecRod.y1 );
00145 
00146         BOOST_ASSERT( yVecView.width() == xVecView.width() );
00147         BOOST_ASSERT( yVecView.height() == xVecView.height() );
00148 
00149         BOOST_ASSERT( dstView.width() == dstRod.x2 - dstRod.x1 );
00150         BOOST_ASSERT( dstView.height() == dstRod.y2 - dstRod.y1 );
00151 
00152         typedef typename DstView::point_t Point2Integer;
00153         typedef typename boost::gil::channel_type<VecView>::type::base_channel_t VecChannel;
00154         typedef typename boost::gil::point2<VecChannel> VecPoint2;
00155         typedef typename DstView::coord_t Coord;
00156         typedef typename DstView::value_type DstPixel;
00157 
00158         const point2<std::ssize_t> procWindowSize = procWindowRoW.size();
00159         
00160         DstPixel black;
00161         color_convert( boost::gil::rgba32f_pixel_t( 0.0, 0.0, 0.0, 0.0 ), black );
00162 
00163         // shift between the procWindow and the output clip RoD
00164         // __________________________
00165         // |\        dst RoD         |
00166         // | \_________________      |
00167         // |  |   procWindow   |     |
00168         // |  |                |     |
00169         // |  |                |     |
00170         // |  |________________|     |
00171         // |                    \    |
00172         // |                      \  |
00173         // |________________________\|
00174         // procWindow is necessarily contained in dst RoD
00175         //
00176         Rect<std::ssize_t> shiftProcWinDstRod; // only positive values
00177         shiftProcWinDstRod.x1 = procWindowRoW.x1 - dstRod.x1;
00178         shiftProcWinDstRod.y1 = procWindowRoW.y1 - dstRod.y1;
00179         shiftProcWinDstRod.x2 = dstRod.x2 - procWindowRoW.x2;
00180         shiftProcWinDstRod.y2 = dstRod.y2 - procWindowRoW.y2;
00181         Rect<std::ssize_t> shiftProcWinVecRod;
00182         shiftProcWinVecRod.x1 = procWindowRoW.x1 - vecRod.x1;
00183         shiftProcWinVecRod.y1 = procWindowRoW.y1 - vecRod.y1;
00184         shiftProcWinVecRod.x2 = vecRod.x2 - procWindowRoW.x2;
00185         shiftProcWinVecRod.y2 = vecRod.y2 - procWindowRoW.y2;
00186 
00187         for( Coord y = procWindowRoW.y1; y < procWindowRoW.y2; ++y )
00188         {
00189                 const Coord yDst = y - dstRod.y1;
00190                 const Coord ySrc = y - srcRod.y1;
00191                 const Coord yVec = y - vecRod.y1;
00192                 typename DstView::x_iterator xit_dst  = dstView.x_at( shiftProcWinDstRod.x1, yDst );
00193                 typename VecView::x_iterator xit_xVec = xVecView.x_at( shiftProcWinVecRod.x1, yVec );
00194                 typename VecView::x_iterator xit_yVec = yVecView.x_at( shiftProcWinVecRod.x1, yVec );
00195                 for( Coord x = procWindowRoW.x1;
00196                      x < procWindowRoW.x2;
00197                      ++x, ++xit_dst, ++xit_xVec, ++xit_yVec )
00198                 {
00199                         const Coord xSrc = x - srcRod.x1;
00200                         const VecPoint2 pos( xSrc, ySrc );
00201 
00202                         VecPoint2 motion;
00203                         if( x < vecRod.x1 || x > vecRod.x2 ||
00204                             y < vecRod.y1 || y > vecRod.y2 )
00205                         {
00206                                 motion.x = 0;
00207                                 motion.y = 0;
00208                         }
00209                         else
00210                         {
00211                                 motion.x = boost::gil::get_color( *xit_xVec, boost::gil::gray_color_t() );
00212                                 motion.y = boost::gil::get_color( *xit_yVec, boost::gil::gray_color_t() );
00213                         }
00214 
00215                         // compute the pixel value according to the resample method
00216                         if( !terry::sampler::sample( sampler, srcView, pos + motion, *xit_dst, outOfImageProcess ) )
00217                         {
00218                                 *xit_dst = black; // if it is outside of the source image
00219                         }
00220                 }
00221 
00222                 // notify the end of the line to inform the progress
00223                 // and allows the host to abort
00224                 if( p.progressForward( procWindowSize.x ) )
00225                         return true;
00226         }
00227         return false;
00228 }
00229 
00230 }
00231 }
00232 
00233 #endif
00234