TuttleOFX
1
|
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