TuttleOFX
1
|
00001 #ifndef _TERRY_COLOR_COLORTRANSFER_HPP_ 00002 #define _TERRY_COLOR_COLORTRANSFER_HPP_ 00003 00004 #include <terry/numeric/matrix.hpp> 00005 #include <terry/numeric/pow.hpp> 00006 #include <terry/numeric/log.hpp> 00007 #include <terry/numeric/clamp.hpp> 00008 #include <terry/typedefs.hpp> 00009 #include <terry/channel.hpp> 00010 00011 //#include <boost/gil/extension/color/hsl.hpp> 00012 //#include <boost/gil/extension/color/distribution.hpp> 00013 00014 namespace terry { 00015 namespace color { 00016 namespace transfer { 00017 00018 namespace detail { 00019 00020 template<typename T> 00021 struct matrices_rgb_to_lab_t 00022 { 00023 typedef boost::numeric::ublas::bounded_matrix<T, 3, 3 > Matrix33; 00024 Matrix33 _RGB_2_LMS; 00025 Matrix33 _LMS_2_LAB; 00026 00027 matrices_rgb_to_lab_t() 00028 : _RGB_2_LMS(3,3) 00029 , _LMS_2_LAB(3,3) 00030 { 00031 _RGB_2_LMS(0, 0) = 0.3811; 00032 _RGB_2_LMS(0, 1) = 0.5783; 00033 _RGB_2_LMS(0, 2) = 0.0402; 00034 _RGB_2_LMS(1, 0) = 0.1967; 00035 _RGB_2_LMS(1, 1) = 0.7244; 00036 _RGB_2_LMS(1, 2) = 0.0782; 00037 _RGB_2_LMS(2, 0) = 0.0241; 00038 _RGB_2_LMS(2, 1) = 0.1288; 00039 _RGB_2_LMS(2, 2) = 0.8444; 00040 00041 // LMS -> LAB 00042 // [L] [ 1/sqrt(3) 0 0 ] [ 1 1 1 ] [L] 00043 // [A] = [ 0 1/sqrt(6) 0 ] [ 1 1 -2 ] [M] 00044 // [B] [ 0 0 1/sqrt(2) ] [ 1 -1 0 ] [S] 00045 // 00046 // [L] [ 1/sqrt(3) 1/sqrt(3) 1/sqrt(3) ] [L] 00047 // [A] = [ 1/sqrt(6) 1/sqrt(6) -2/sqrt(6) ] [M] 00048 // [B] [ 1/sqrt(2) -1/sqrt(2) 0.0 ] [S] 00049 static const T invSqrt2 = 1.0 / std::sqrt( (double) 2.0 ); 00050 static const T invSqrt3 = 1.0 / std::sqrt( (double) 3.0 ); 00051 static const T invSqrt6 = 1.0 / std::sqrt( (double) 6.0 ); 00052 _LMS_2_LAB(0, 0) = invSqrt3; 00053 _LMS_2_LAB(0, 1) = invSqrt3; 00054 _LMS_2_LAB(0, 2) = invSqrt3; 00055 _LMS_2_LAB(1, 0) = invSqrt6; 00056 _LMS_2_LAB(1, 1) = invSqrt6; 00057 _LMS_2_LAB(1, 2) = -2.0 * invSqrt6; 00058 _LMS_2_LAB(2, 0) = invSqrt2; 00059 _LMS_2_LAB(2, 1) = -invSqrt2; 00060 _LMS_2_LAB(2, 2) = 0.0; 00061 } 00062 }; 00063 00064 template<typename T> 00065 struct matrices_lab_to_rgb_t 00066 { 00067 typedef boost::numeric::ublas::bounded_matrix<T, 3, 3 > Matrix33; 00068 Matrix33 _LAB_2_LMS; 00069 Matrix33 _LMS_2_RGB; 00070 00071 matrices_lab_to_rgb_t() 00072 : _LAB_2_LMS(3,3) 00073 , _LMS_2_RGB(3,3) 00074 { 00075 // LAB -> LMS 00076 // [L] [ 1 1 1 ] [ sqrt(3)/3 0 0 ] [L] 00077 // [M] = [ 1 1 -1 ] [ 0 sqrt(6)/6 0 ] [A] 00078 // [S] [ 1 -2 0 ] [ 0 0 sqrt(2)/2 ] [B] 00079 // 00080 // [L] [ sqrt(3)/3 sqrt(6)/6 sqrt(2)/2 ] [L] 00081 // [M] = [ sqrt(3)/3 sqrt(6)/6 -sqrt(2)/2 ] [A] 00082 // [S] [ sqrt(3)/3 -2*sqrt(6)/6 0 ] [B] 00083 static const T sqrt2_2 = 1.0 / std::sqrt( (double) 2.0 ); 00084 static const T sqrt3_3 = 1.0 / std::sqrt( (double) 3.0 ); 00085 static const T sqrt6_6 = 1.0 / std::sqrt( (double) 6.0 ); 00086 _LAB_2_LMS(0, 0) = sqrt3_3; 00087 _LAB_2_LMS(0, 1) = sqrt6_6; 00088 _LAB_2_LMS(0, 2) = sqrt2_2; 00089 _LAB_2_LMS(1, 0) = sqrt3_3; 00090 _LAB_2_LMS(1, 1) = sqrt6_6; 00091 _LAB_2_LMS(1, 2) = -sqrt2_2; 00092 _LAB_2_LMS(2, 0) = sqrt3_3; 00093 _LAB_2_LMS(2, 1) = -2.0 * sqrt6_6; 00094 _LAB_2_LMS(2, 2) = 0.0; 00095 00096 _LMS_2_RGB(0, 0) = 4.4679; 00097 _LMS_2_RGB(0, 1) = -3.5873; 00098 _LMS_2_RGB(0, 2) = 0.1193; 00099 _LMS_2_RGB(1, 0) = -1.2186; 00100 _LMS_2_RGB(1, 1) = 2.3809; 00101 _LMS_2_RGB(1, 2) = -0.1624; 00102 _LMS_2_RGB(2, 0) = 0.0497; 00103 _LMS_2_RGB(2, 1) = -0.2439; 00104 _LMS_2_RGB(2, 2) = 1.2045; 00105 00106 } 00107 }; 00108 } 00109 00110 template <typename PixelRef, typename PixelR = PixelRef> // models pixel concept 00111 struct pixel_rgb_to_lms_t 00112 { 00113 typedef typename channel_type<PixelR>::type ChannelR; 00114 typedef typename floating_channel_type_t<ChannelR>::type T; 00115 typedef typename detail::matrices_rgb_to_lab_t<T> MatrixContants; 00116 typedef typename MatrixContants::Matrix33 Matrix; 00117 00118 static const MatrixContants _matrices; 00119 00120 GIL_FORCEINLINE 00121 PixelR operator()( const PixelRef & rgb ) const 00122 { 00123 using namespace terry::numeric; 00124 // RGB to LMS 00125 return pixel_matrix33_multiply_t<PixelRef, Matrix, PixelR>( _matrices._RGB_2_LMS )( rgb ); 00126 } 00127 }; 00128 00129 template <typename PixelRef, typename PixelR> 00130 const typename pixel_rgb_to_lms_t<PixelRef, PixelR>::MatrixContants pixel_rgb_to_lms_t<PixelRef, PixelR>::_matrices; // init static variable. 00131 00132 template <typename PixelRef, typename PixelR = PixelRef> // models pixel concept 00133 struct pixel_rgb_to_lab_t 00134 { 00135 typedef typename channel_type<PixelR>::type ChannelR; 00136 typedef typename floating_channel_type_t<ChannelR>::type T; 00137 typedef typename detail::matrices_rgb_to_lab_t<T> MatrixContants; 00138 typedef typename MatrixContants::Matrix33 Matrix; 00139 00140 static const MatrixContants _matrices; 00141 00142 GIL_FORCEINLINE 00143 PixelR operator()( const PixelRef & rgb ) const 00144 { 00145 using namespace terry::numeric; 00146 static const T thresold = 1.0e-5; 00147 static const ChannelR channelThresold = ChannelR(thresold); //channel_convert<ChannelR, T>( thresold ); 00148 // RGB to LMS 00149 PixelR lms = pixel_matrix33_multiply_t<PixelRef, Matrix, PixelR>( _matrices._RGB_2_LMS )( rgb ); 00150 // log(v) 00151 PixelR lms_log = pixel_log10_t<PixelR, PixelR>()( 00152 // log10(x) is not defined for x <= 0, so we need to clamp 00153 pixel_clamp_lower_than_t<PixelR>( channelThresold, channelThresold )( 00154 lms 00155 ) 00156 ); 00157 // LMS to LAB (lambda alpha beta) 00158 PixelR lab = pixel_matrix33_multiply_t<PixelR, Matrix, PixelR>( _matrices._LMS_2_LAB )( lms_log ); 00159 return lab; 00160 } 00161 }; 00162 00163 template <typename PixelRef, typename PixelR> 00164 const typename pixel_rgb_to_lab_t<PixelRef, PixelR>::MatrixContants pixel_rgb_to_lab_t<PixelRef, PixelR>::_matrices; // init static variable. 00165 00166 template <typename PixelRef, typename PixelR = PixelRef> // models pixel concept 00167 struct pixel_lms_to_rgb_t 00168 { 00169 typedef typename channel_type<PixelR>::type ChannelR; 00170 typedef typename floating_channel_type_t<ChannelR>::type T; 00171 typedef typename detail::matrices_lab_to_rgb_t<T> MatrixContants; 00172 typedef typename MatrixContants::Matrix33 Matrix; 00173 00174 static const MatrixContants _matrices; 00175 00176 GIL_FORCEINLINE 00177 PixelR operator()( const PixelRef & lms ) const 00178 { 00179 using namespace terry::numeric; 00180 // LMS to RGB 00181 return pixel_matrix33_multiply_t<PixelR, Matrix, PixelR>( _matrices._LMS_2_RGB )( lms ); 00182 } 00183 }; 00184 00185 template <typename PixelRef, typename PixelR> 00186 const typename pixel_lms_to_rgb_t<PixelRef, PixelR>::MatrixContants pixel_lms_to_rgb_t<PixelRef, PixelR>::_matrices; // init static variable. 00187 00188 template <typename PixelRef, typename PixelR = PixelRef> // models pixel concept 00189 struct pixel_lab_to_rgb_t 00190 { 00191 typedef typename channel_type<PixelR>::type ChannelR; 00192 typedef typename floating_channel_type_t<ChannelR>::type T; 00193 typedef typename detail::matrices_lab_to_rgb_t<T> MatrixContants; 00194 typedef typename MatrixContants::Matrix33 Matrix; 00195 00196 static const MatrixContants _matrices; 00197 00198 GIL_FORCEINLINE 00199 PixelR operator()( const PixelRef & lab ) const 00200 { 00201 using namespace terry::numeric; 00202 00203 // LAB (lambda alpha beta) to LMS 00204 PixelR lms_log = pixel_matrix33_multiply_t<PixelRef, Matrix, PixelR>( _matrices._LAB_2_LMS )( lab ); 00205 // 10^v 00206 PixelR lms = pixel_scalar_pow_t<PixelR, T, PixelR>()( lms_log, 10.0 ); 00207 // LMS to RGB 00208 PixelR rgb = pixel_matrix33_multiply_t<PixelR, Matrix, PixelR>( _matrices._LMS_2_RGB )( lms ); 00209 return rgb; 00210 } 00211 }; 00212 00213 template <typename PixelRef, typename PixelR> 00214 const typename pixel_lab_to_rgb_t<PixelRef, PixelR>::MatrixContants pixel_lab_to_rgb_t<PixelRef, PixelR>::_matrices; // init static variable. 00215 00216 00217 } 00218 } 00219 } 00220 00221 #endif 00222 00223