TuttleOFX
1
|
00001 #include "SobelPlugin.hpp" 00002 00003 00004 #include <tuttle/plugin/memory/OfxAllocator.hpp> 00005 #include <tuttle/plugin/exceptions.hpp> 00006 00007 #include <terry/globals.hpp> 00008 #include <terry/color/gradient.hpp> 00009 #include <terry/color/norm.hpp> 00010 #include <terry/algorithm/transform_pixels_progress.hpp> 00011 #include <terry/filter/convolve.hpp> 00012 #include <terry/algorithm/pixel_by_channel.hpp> 00013 #include <terry/typedefs.hpp> 00014 00015 #include <boost/gil/utilities.hpp> 00016 #include <boost/mpl/bool.hpp> 00017 #include <boost/mpl/if.hpp> 00018 #include <boost/type_traits/is_floating_point.hpp> 00019 #include <boost/math/special_functions/pow.hpp> 00020 00021 #include <cmath> 00022 00023 00024 namespace tuttle { 00025 namespace plugin { 00026 namespace sobel { 00027 00028 template<class SView, class DView> 00029 SobelProcess<SView,DView>::SobelProcess( SobelPlugin &effect ) 00030 : ImageGilFilterProcessor<SView,DView>( effect, eImageOrientationFromBottomToTop ) 00031 , _plugin( effect ) 00032 { 00033 using namespace terry::numeric; 00034 pixel_zeros_t<DPixel>()(_pixelZero); 00035 } 00036 00037 template <class SView, class DView> 00038 void SobelProcess<SView,DView>::setup( const OFX::RenderArguments& args ) 00039 { 00040 ImageGilFilterProcessor<SView,DView>::setup( args ); 00041 00042 _params = _plugin.getProcessParams( args.renderScale ); 00043 } 00044 00045 template <class SView, class DView> 00046 void SobelProcess<SView,DView>::preProcess() 00047 { 00048 this->progressBegin( 5 /* steps */ * this->_renderWindowSize.x * this->_renderWindowSize.y ); 00049 } 00050 00051 /** 00052 * @brief Function called by rendering thread each time a process must be done. 00053 * @param[in] procWindowRoW Processing window 00054 */ 00055 template<class SView, class DView> 00056 void SobelProcess<SView,DView>::multiThreadProcessImages( const OfxRectI& procWindowRoW ) 00057 { 00058 using namespace boost; 00059 using namespace terry; 00060 using namespace terry::numeric; 00061 using namespace terry::filter; 00062 using namespace terry::algorithm; 00063 00064 // TUTTLE_LOG_INFO( "Sobel X: " << _params._xKernelGaussianDerivative.size() << "x" << _params._xKernelGaussian.size() ); 00065 // TUTTLE_LOG_INFO( "Sobel Y: " << _params._yKernelGaussianDerivative.size() << "x" << _params._yKernelGaussian.size() ); 00066 00067 const OfxRectI procWindowOutput = this->translateRoWToOutputClipCoordinates( procWindowRoW ); 00068 const OfxPointI procWindowSize = { 00069 procWindowRoW.x2 - procWindowRoW.x1, 00070 procWindowRoW.y2 - procWindowRoW.y1 00071 }; 00072 00073 typedef typename channel_mapping_type<DView>::type DChannel; 00074 typedef typename terry::floating_channel_type_t<DChannel>::type DChannelFloat; 00075 typedef pixel<DChannelFloat, gray_layout_t> DPixelGray; 00076 00077 DView dst = subimage_view( this->_dstView, 00078 procWindowOutput.x1, procWindowOutput.y1, 00079 procWindowSize.x, procWindowSize.y ); 00080 00081 const Point proc_tl( procWindowRoW.x1 - this->_srcPixelRod.x1, procWindowRoW.y1 - this->_srcPixelRod.y1 ); 00082 00083 if( _params._xKernelGaussianDerivative.size() == 0 || ( !_params._unidimensional && _params._xKernelGaussian.size() == 0 ) ) 00084 { 00085 fill_pixels( kth_channel_view<0>(dst), _pixelZero ); 00086 } 00087 else 00088 { 00089 if( _params._unidimensional ) 00090 { 00091 correlate_rows_auto<DPixelGray>( 00092 color_converted_view<DPixelGray>( this->_srcView ), 00093 _params._xKernelGaussianDerivative, 00094 kth_channel_view<0>(dst), 00095 proc_tl, 00096 _params._boundary_option ); 00097 } 00098 else 00099 { 00100 switch( _params._pass ) 00101 { 00102 case eParamPassFull: 00103 { 00104 correlate_rows_cols_auto<DPixelGray, OfxAllocator>( 00105 color_converted_view<DPixelGray>( this->_srcView ), 00106 _params._xKernelGaussianDerivative, 00107 _params._xKernelGaussian, 00108 kth_channel_view<0>(dst), 00109 proc_tl, 00110 _params._boundary_option ); 00111 break; 00112 } 00113 case eParamPass1: 00114 { 00115 correlate_rows_auto<DPixelGray>( 00116 color_converted_view<DPixelGray>( this->_srcView ), 00117 _params._xKernelGaussianDerivative, 00118 kth_channel_view<0>(dst), 00119 proc_tl, 00120 _params._boundary_option ); 00121 break; 00122 } 00123 case eParamPass2: 00124 { 00125 correlate_cols_auto<DPixelGray>( 00126 kth_channel_view<0>( this->_srcView ), 00127 _params._xKernelGaussian, 00128 kth_channel_view<0>(dst), 00129 proc_tl, 00130 _params._boundary_option ); 00131 break; 00132 } 00133 } 00134 } 00135 } 00136 if( this->progressForward( dst.size() ) ) 00137 return; 00138 00139 if( _params._yKernelGaussianDerivative.size() == 0 || ( !_params._unidimensional && _params._yKernelGaussian.size() == 0 ) ) 00140 { 00141 fill_pixels( kth_channel_view<1>(dst), _pixelZero ); 00142 } 00143 else 00144 { 00145 if( _params._unidimensional ) 00146 { 00147 correlate_cols_auto<DPixelGray>( 00148 color_converted_view<DPixelGray>( this->_srcView ), 00149 _params._yKernelGaussianDerivative, 00150 kth_channel_view<1>(dst), 00151 proc_tl, 00152 _params._boundary_option ); 00153 } 00154 else 00155 { 00156 switch( _params._pass ) 00157 { 00158 case eParamPassFull: 00159 { 00160 correlate_rows_cols_auto<DPixelGray, OfxAllocator>( 00161 color_converted_view<DPixelGray>( this->_srcView ), 00162 _params._yKernelGaussian, 00163 _params._yKernelGaussianDerivative, 00164 kth_channel_view<1>(dst), 00165 proc_tl, 00166 _params._boundary_option ); 00167 break; 00168 } 00169 case eParamPass1: 00170 { 00171 correlate_rows_auto<DPixelGray>( 00172 color_converted_view<DPixelGray>( this->_srcView ), 00173 _params._yKernelGaussian, 00174 kth_channel_view<1>(dst), 00175 proc_tl, 00176 _params._boundary_option ); 00177 break; 00178 } 00179 case eParamPass2: 00180 { 00181 typedef boost::mpl::bool_<( num_channels<SView>::value >= 2 )> Enable; 00182 computeYPass2<DPixelGray>( dst, proc_tl, Enable() ); 00183 break; 00184 } 00185 } 00186 } 00187 } 00188 if( this->progressForward( dst.size() ) ) 00189 return; 00190 00191 if( ! _params._computeGradientNorm ) 00192 { 00193 fill_pixels( kth_channel_view<2>(dst), _pixelZero ); 00194 } 00195 else if( _params._gradientNormManhattan ) 00196 { 00197 transform_pixels_progress( 00198 kth_channel_view<0>(dst), // srcX 00199 kth_channel_view<1>(dst), // srcY 00200 kth_channel_view<2>(dst), // dst: gradient direction 00201 transform_pixel_by_channel_t<terry::color::channel_normManhattan_t>(), 00202 this->getOfxProgress() 00203 ); 00204 } 00205 else 00206 { 00207 transform_pixels_progress( 00208 kth_channel_view<0>(dst), // srcX 00209 kth_channel_view<1>(dst), // srcY 00210 kth_channel_view<2>(dst), // dst: gradient direction 00211 transform_pixel_by_channel_t<terry::color::channel_norm_t>(), 00212 this->getOfxProgress() 00213 ); 00214 } 00215 if( this->progressForward( dst.size() ) ) 00216 return; 00217 00218 computeGradientDirection( dst, boost::mpl::bool_<(boost::gil::num_channels<DView>::value >= 4)>() ); 00219 } 00220 00221 template<class SView, class DView> 00222 void SobelProcess<SView, DView>::computeGradientDirection( DView& dst, boost::mpl::true_ ) 00223 { 00224 using namespace boost; 00225 using namespace terry; 00226 using namespace terry::algorithm; 00227 00228 if( ! _params._computeGradientDirection ) 00229 { 00230 fill_pixels( kth_channel_view<3>(dst), channel_traits< typename channel_type<DView>::type >::max_value() ); 00231 if( this->progressForward( dst.size() ) ) 00232 return; 00233 } 00234 else 00235 { 00236 if( _params._gradientDirectionAbs ) 00237 { 00238 transform_pixels_progress( 00239 kth_channel_view<0>(dst), // srcX 00240 kth_channel_view<1>(dst), // srcY 00241 kth_channel_view<3>(dst), // dst: gradient direction 00242 transform_pixel_by_channel_t<terry::color::channel_gradientDirectionAbs_t>(), 00243 this->getOfxProgress() 00244 ); 00245 } 00246 else 00247 { 00248 transform_pixels_progress( 00249 kth_channel_view<0>(dst), // srcX 00250 kth_channel_view<1>(dst), // srcY 00251 kth_channel_view<3>(dst), // dst: gradient direction 00252 transform_pixel_by_channel_t<terry::color::channel_gradientDirection_t>(), 00253 this->getOfxProgress() 00254 ); 00255 } 00256 } 00257 } 00258 00259 } 00260 } 00261 }