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