TuttleOFX  1
MergeFunctors.hpp
Go to the documentation of this file.
00001 #ifndef _TERRY_MERGEFUNCTORS_HPP_
00002 #define _TERRY_MERGEFUNCTORS_HPP_
00003 
00004 #include "MergeAbstractFunctor.hpp"
00005 
00006 #include <boost/gil/color_convert.hpp>
00007 #include <boost/gil/extension/color/hsl.hpp>
00008 #include <boost/math/constants/constants.hpp>
00009 #include <boost/type_traits/is_signed.hpp>
00010 
00011 #include <cmath>
00012 
00013 namespace terry {
00014 
00015 template<bool is_signed, typename Channel>
00016 struct is_negative_impl
00017 {
00018         static bool process( const Channel& v ) { return v < 0; }
00019 };
00020 
00021 template<typename Channel>
00022 struct is_negative_impl<false, Channel>
00023 {
00024         // if unsigned value can't be negative
00025         static bool process( const Channel& ) { return false; }
00026 };
00027 
00028 template<typename Channel>
00029 bool is_negative( const Channel& v )
00030 {
00031         return is_negative_impl<boost::is_signed<typename boost::gil::channel_traits<Channel>::value_type>::value, Channel>::process( v );
00032 }
00033 
00034 /******************************************************************************
00035 * Functors that doesn't need alpha                                           *
00036 ******************************************************************************/
00037 
00038 template <typename Pixel>
00039 struct FunctorAverage
00040         : public merge_functor<Pixel, merge_per_channel>
00041 {
00042         template<typename Channel>
00043         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00044         {
00045                 // (A + B) / 2
00046                 dst = (Channel)( ( A + B ) * 0.5 );
00047         }
00048 
00049 };
00050 
00051 template <typename Pixel>
00052 struct FunctorPlus
00053         : public merge_functor<Pixel, merge_per_channel>
00054 {
00055         template <typename Channel>
00056         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00057         {
00058                 // A + B
00059                 dst = (Channel)( A + B );
00060         }
00061 
00062 };
00063 
00064 template <typename Pixel>
00065 struct FunctorCopy
00066         : public merge_functor<Pixel, merge_per_channel>
00067 {
00068         template <typename Channel>
00069         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00070         {
00071                 // A
00072                 dst = (Channel)( A );
00073         }
00074 
00075 };
00076 
00077 template <typename Pixel>
00078 struct FunctorDifference
00079         : public merge_functor<Pixel, merge_per_channel>
00080 {
00081         template <typename Channel>
00082         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00083         {
00084                 // difference
00085                 dst = (Channel)( std::abs( A - B ) );
00086         }
00087 
00088 };
00089 
00090 template <typename Pixel>
00091 struct FunctorDivide
00092         : public merge_functor<Pixel, merge_per_channel>
00093 {
00094         //@todo: this functor only work on floats, on int types it
00095         //       needs to be specialized
00096         template <typename Channel>
00097         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00098         {
00099                 if( is_negative( A ) && is_negative( B ) )
00100                 {
00101                         dst = Channel( 0 );
00102                         return;
00103                 }
00104                 dst = (Channel)( A / B );
00105         }
00106 
00107 };
00108 
00109 template <typename Pixel>
00110 struct FunctorExclusion
00111         : public merge_functor<Pixel, merge_per_channel>
00112 {
00113         //@todo: this functor only work on floats, on int types it
00114         //       needs to be specialized
00115         // idea: on a 16 short type, A*B >> 15,
00116         // on 32 int types: (((int64_t)A)*B)>> 31
00117         template <typename Channel>
00118         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00119         {
00120                 dst = (Channel)( A + B - 2 * A * B );
00121         }
00122 
00123 };
00124 
00125 template <typename Pixel>
00126 struct FunctorFrom
00127         : public merge_functor<Pixel, merge_per_channel>
00128 {
00129         template <typename Channel>
00130         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00131         {
00132                 dst = (Channel)( B - A );
00133         }
00134 
00135 };
00136 
00137 template <typename Pixel>
00138 struct FunctorGeometric
00139         : public merge_functor<Pixel, merge_per_channel>
00140 {
00141         //@todo: this functor only work on floats, on int types it
00142         //       needs to be specialized
00143         // idea: on a 16 short type, A*B >> 15,
00144         // on 32 int types: (((int64_t)A)*B)>> 31
00145         template <typename Channel>
00146         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00147         {
00148                 dst = (Channel)( 2 * A * B / ( A + B ) );
00149         }
00150 
00151 };
00152 
00153 template <typename Pixel>
00154 struct FunctorMultiply
00155         : public merge_functor<Pixel, merge_per_channel>
00156 {
00157         template <typename Channel>
00158         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00159         {
00160                 if( is_negative( A ) && is_negative( B ) )
00161                 {
00162                         dst = (Channel)( 0 );
00163                         return;
00164                 }
00165                 dst = (Channel)( A * B );
00166         }
00167 
00168 };
00169 
00170 template <typename Pixel>
00171 struct FunctorScreen
00172         : public merge_functor<Pixel, merge_per_channel>
00173 {
00174         //@todo: this functor only work on floats, on int types it
00175         //       needs to be specialized
00176         // idea: on a 16 short type, A*B >> 15,
00177         // on 32 int types: (((int64_t)A)*B)>> 31
00178         template <typename Channel>
00179         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00180         {
00181                 dst = A + B - A * B;
00182         }
00183 
00184 };
00185 
00186 template <typename Pixel>
00187 struct FunctorHardLight
00188         : public merge_functor<Pixel, merge_per_channel>
00189 {
00190         //@todo: this functor only work on floats, on int types it
00191         //       needs to be specialized
00192         // idea: on a 16 short type, A*B >> 15,
00193         // on 32 int types: (((int64_t)A)*B)>> 31
00194         template <typename Channel>
00195         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00196         {
00197                 static const Channel max   = boost::gil::channel_traits<Channel>::max_value();
00198                 static const Channel maxs2 = max / 2;
00199 
00200                 if( A < maxs2 )
00201                         dst = 2 * A * B;
00202                 else
00203                         // Screen
00204                         dst = max - 2 * ( max - A ) * ( max - B );
00205         }
00206 
00207 };
00208 
00209 template <typename Pixel>
00210 struct FunctorHypot
00211         : public merge_functor<Pixel, merge_per_channel>
00212 {
00213         //@todo: this functor only work on floats, on int types it
00214         //       needs to be specialized
00215         // idea: on a 16 short type, A*B >> 15,
00216         // on 32 int types: (((int64_t)A)*B)>> 31
00217         template <typename Channel>
00218         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00219         {
00220                 dst = Channel( std::sqrt( (float)( A * A + B * B ) ) );
00221         }
00222 
00223 };
00224 
00225 template <typename Pixel>
00226 struct FunctorMinus
00227         : public merge_functor<Pixel, merge_per_channel>
00228 {
00229         template <typename Channel>
00230         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00231         {
00232                 dst = Channel( A - B );
00233         }
00234 
00235 };
00236 
00237 template <typename Pixel>
00238 struct FunctorDarken
00239         : public merge_functor<Pixel, merge_per_channel>
00240 {
00241         template <typename Channel>
00242         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00243         {
00244                 dst = Channel( std::min( A, B ) );
00245         }
00246 
00247 };
00248 
00249 template <typename Pixel>
00250 struct FunctorLighten
00251         : public merge_functor<Pixel, merge_per_channel>
00252 {
00253         template <typename Channel>
00254         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00255         {
00256                 dst = Channel( std::max( A, B ) );
00257         }
00258 
00259 };
00260 
00261 template <typename Pixel>
00262 struct FunctorOverlay
00263         : public merge_functor<Pixel, merge_per_channel>
00264 {
00265         //@todo: this functor only work on floats, on int types it
00266         //       needs to be specialized
00267         template <typename Channel>
00268         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00269         {
00270                 static const Channel max   = boost::gil::channel_traits<Channel>::max_value();
00271                 static const Channel maxs2 = max / 2;
00272 
00273                 if( B < maxs2 )
00274                         // Multiply
00275                         dst = 2 * A * B;
00276                 else
00277                         // Screen
00278                         dst = max - 2 * ( max - A ) * ( max - B );
00279         }
00280 
00281 };
00282 
00283 template <typename Pixel>
00284 struct FunctorColorDodge
00285         : public merge_functor<Pixel, merge_per_channel>
00286 {
00287         //@todo: this functor only work on floats, on int types it
00288         //       needs to be specialized
00289         template <typename Channel>
00290         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00291         {
00292                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00293 
00294                 // f(a,b) = a / (1.0f - b)
00295                 if( A < max )
00296                 {
00297                         dst = Channel( B / ( max - A ) );
00298                         if( dst > max )
00299                                 dst = max;
00300                 }
00301                 else
00302                         dst = max;
00303         }
00304 
00305 };
00306 
00307 template <typename Pixel>
00308 struct FunctorColorBurn
00309         : public merge_functor<Pixel, merge_per_channel>
00310 {
00311         //@todo: this functor only work on floats, on int types it
00312         //       needs to be specialized
00313         template <typename Channel>
00314         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00315         {
00316                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00317 
00318                 // f(a,b) = 1.0f - (1.0f - a) / b
00319                 if( B != 0 )
00320                 {
00321                         dst = max - Channel( ( max - A ) / B );
00322                         if( is_negative( dst ) )
00323                                 dst = 0;
00324                 }
00325                 else
00326                         dst = Channel( 0 );
00327         }
00328 
00329 };
00330 
00331 template <typename Pixel>
00332 struct FunctorPinLight
00333         : public merge_functor<Pixel, merge_per_channel>
00334 {
00335         //@todo: this functor only work on floats, on int types it
00336         //       needs to be specialized
00337         template <typename Channel>
00338         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00339         {
00340                 static const Channel maxs2 = boost::gil::channel_traits<Channel>::max_value() / 2;
00341 
00342                 dst = Channel( B >= maxs2 ? std::max( A, (Channel)( ( B - maxs2 ) * 2 ) )
00343                                            : std::min( A, (Channel)( B * 2 ) ) );
00344         }
00345 
00346 };
00347 
00348 // Quadratic mode: reflect
00349 template <typename Pixel>
00350 struct FunctorReflect
00351         : public merge_functor<Pixel, merge_per_channel>
00352 {
00353         //@todo: this functor only work on floats, on int types it
00354         //       needs to be specialized
00355         template <typename Channel>
00356         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00357         {
00358                 // f(a,b) = a² / (1 - b)
00359                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00360 
00361                 if( B >= max )
00362                         dst = max;
00363                 else
00364                 {
00365                         dst = Channel( A * A / ( max - B ) );
00366                         if( dst > max )
00367                                 dst = max;
00368                 }
00369         }
00370 
00371 };
00372 
00373 // Quadratic mode: freeze
00374 template <typename Pixel>
00375 struct FunctorFreeze
00376         : public merge_functor<Pixel, merge_per_channel>
00377 {
00378         //@todo: this functor only work on floats, on int types it
00379         //       needs to be specialized
00380         template <typename Channel>
00381         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00382         {
00383                 // f(a,b) = 1 - sqrt(1 - A) / B
00384                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00385 
00386                 if( B == 0 )
00387                         dst = 0;
00388                 else
00389                 {
00390                         dst = max - ( Channel ) std::sqrt( (float)max - A ) / B;
00391                         if( is_negative( dst ) )
00392                                 dst = 0;
00393                 }
00394         }
00395 
00396 };
00397 
00398 // Similar to average, but smoother...
00399 template <typename Pixel>
00400 struct FunctorInterpolated
00401         : public merge_functor<Pixel, merge_per_channel>
00402 {
00403         //@todo: this functor only work on floats, on int types it
00404         //       needs to be specialized
00405         template <typename Channel>
00406         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00407         {
00408                 static const Channel max   = boost::gil::channel_traits<Channel>::max_value();
00409                 static const Channel maxs2 = max / 2;
00410                 static const Channel maxs4 = max / 4;
00411 
00412                 //f(a,b) =  - cos(pi*a) - cos(pi*b)
00413                 // Very slow implementation: that's because we are working with floats.
00414                 // on integer types, we should be using a precomputed cosine table.
00415                 dst = maxs2 - maxs4 * ( Channel ) std::cos( boost::math::constants::pi<float>() * (float)A )
00416                       - maxs4 * ( Channel ) std::cos( boost::math::constants::pi<float>() * (float)B );
00417         }
00418 
00419 };
00420 
00421 /******************************************************************************
00422 * Functors that does need alpha                                              *
00423 ******************************************************************************/
00424 
00425 template <typename Pixel>
00426 struct FunctorATop
00427         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00428 {
00429         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00430         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00431         //@todo: this functor only work on floats, on int types it
00432         //       needs to be specialized
00433         template<typename Channel>
00434         inline void operator()( const Channel& A, const Channel& B, Channel& d )
00435         {
00436                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00437                 // Ab + B(1-a)
00438                 d = A * b + B * ( max - a );
00439         }
00440 
00441 };
00442 
00443 template <typename Pixel>
00444 struct FunctorConjointOver
00445         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00446 {
00447         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00448         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00449         //@todo: this functor only work on floats, on int types it
00450         //       needs to be specialized
00451         template <typename Channel>
00452         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00453         {
00454                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00455 
00456                 if( a > b )
00457                         // Copy
00458                         dst = A;
00459                 else
00460                         dst = (Channel)( A + B * ( max - a ) / b );
00461         }
00462 
00463 };
00464 
00465 template <typename Pixel>
00466 struct FunctorDisjointOver
00467         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00468 {
00469         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00470         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00471         //@todo: this functor only work on floats, on int types it
00472         //       needs to be specialized
00473         template <typename Channel>
00474         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00475         {
00476                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00477 
00478                 if( a + b < max )
00479                         dst = A + B;
00480                 else
00481                         dst = (Channel)( A + B * ( max - a ) / b );
00482         }
00483 
00484 };
00485 
00486 template <typename Pixel>
00487 struct FunctorIn
00488         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00489 {
00490         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00491         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00492         //@todo: this functor only work on floats, on int types it
00493         //       needs to be specialized
00494         template <typename Channel>
00495         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00496         {
00497                 dst = (Channel)( A * b );
00498         }
00499 
00500 };
00501 
00502 template <typename Pixel>
00503 struct FunctorMask
00504         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00505 {
00506         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00507         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00508         //@todo: this functor only work on floats, on int types it
00509         //       needs to be specialized
00510         template <typename Channel>
00511         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00512         {
00513                 dst = (Channel)( B * a );
00514         }
00515 
00516 };
00517 
00518 template <typename Pixel>
00519 struct FunctorMatte
00520         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00521 {
00522         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00523         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00524         //@todo: this functor only work on floats, on int types it
00525         //       needs to be specialized
00526         template <typename Channel>
00527         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00528         {
00529                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00530 
00531                 dst = (Channel)( A * a + B * ( max - a ) );
00532         }
00533 
00534 };
00535 
00536 template <typename Pixel>
00537 struct FunctorOut
00538         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00539 {
00540         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00541         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00542         //@todo: this functor only work on floats, on int types it
00543         //       needs to be specialized
00544         template <typename Channel>
00545         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00546         {
00547                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00548 
00549                 dst = (Channel)( A * ( max - b ) );
00550         }
00551 
00552 };
00553 
00554 template <typename Pixel>
00555 struct FunctorOver
00556         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00557 {
00558         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00559         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00560         //@todo: this functor only work on floats, on int types it
00561         //       needs to be specialized
00562         template <typename Channel>
00563         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00564         {
00565                 dst = (Channel)( A + B * ( boost::gil::channel_traits<Channel>::max_value() - a ) );
00566         }
00567 
00568 };
00569 
00570 template <typename Pixel>
00571 struct FunctorStencil
00572         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00573 {
00574         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00575         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00576         //@todo: this functor only work on floats, on int types it
00577         //       needs to be specialized
00578         template <typename Channel>
00579         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00580         {
00581                 dst = (Channel)( B * ( boost::gil::channel_traits<Channel>::max_value() - a ) );
00582         }
00583 
00584 };
00585 
00586 template <typename Pixel>
00587 struct FunctorUnder
00588         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00589 {
00590         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00591         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00592         //@todo: this functor only work on floats, on int types it
00593         //       needs to be specialized
00594         template <typename Channel>
00595         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00596         {
00597                 dst = (Channel)( A * ( boost::gil::channel_traits<Channel>::max_value() - b ) + B );
00598         }
00599 
00600 };
00601 
00602 template <typename Pixel>
00603 struct FunctorXOR
00604         : public merge_functor<Pixel, merge_per_channel_with_alpha>
00605 {
00606         using merge_functor<Pixel, merge_per_channel_with_alpha>::a;
00607         using merge_functor<Pixel, merge_per_channel_with_alpha>::b;
00608         //@todo: this functor only work on floats, on int types it
00609         //       needs to be specialized
00610         template <typename Channel>
00611         inline void operator()( const Channel& A, const Channel& B, Channel& dst )
00612         {
00613                 static const Channel max = boost::gil::channel_traits<Channel>::max_value();
00614 
00615                 dst = (Channel)( A * ( max - b ) + B * ( max - a ) );
00616         }
00617 
00618 };
00619 
00620 /*****************************************************************************
00621  * Functors that operates on pixels                                           *
00622  ******************************************************************************/
00623 
00624 template <typename Pixel>
00625 struct FunctorColor
00626         : public merge_functor<Pixel, merge_per_pixel>
00627 {
00628         //@todo: make this code faster
00629         inline void operator()( const Pixel& A, const Pixel& B, Pixel& C )
00630         {
00631                 using namespace hsl_color_space;
00632                 hsl32f_pixel_t hA, hB;
00633 
00634                 // @todo: improve this !
00635                 color_convert( A, hA );
00636                 color_convert( B, hB );
00637                 hsl32f_pixel_t hC( get_color( hB, hue_t() ),
00638                                    get_color( hB, saturation_t() ),
00639                                    get_color( hA, lightness_t() ) );
00640                 color_convert( hC, C );
00641         }
00642 
00643 };
00644 
00645 }
00646 
00647 #endif