TuttleOFX
1
|
00001 #ifndef _TERRY_COLOR_MATRIX_HPP_ 00002 #define _TERRY_COLOR_MATRIX_HPP_ 00003 00004 #include <terry/math/Matrix.hpp> 00005 00006 #include <boost/math/constants/constants.hpp> 00007 00008 namespace terry { 00009 namespace color { 00010 00011 // http://www.graficaobscura.com/matrix/index.html 00012 00013 static const double s_redLum = 0.3086; 00014 static const double s_greenLum = 0.6094; 00015 static const double s_blueLum = 0.0820; 00016 00017 00018 /** 00019 * @brief Make a color scale matrix. 00020 */ 00021 template<class Matrix5x5> 00022 Matrix5x5 scaleMatrix( 00023 const typename Matrix5x5::value_type rScale, 00024 const typename Matrix5x5::value_type gScale, 00025 const typename Matrix5x5::value_type bScale, 00026 const typename Matrix5x5::value_type aScale ) 00027 { 00028 Matrix5x5 matrix(5, 5); 00029 00030 matrix(0, 0) = rScale; 00031 matrix(0, 1) = 0.0; 00032 matrix(0, 2) = 0.0; 00033 matrix(0, 3) = 0.0; 00034 matrix(0, 4) = 0.0; 00035 00036 matrix(1, 0) = 0.0; 00037 matrix(1, 1) = gScale; 00038 matrix(1, 2) = 0.0; 00039 matrix(1, 3) = 0.0; 00040 matrix(1, 4) = 0.0; 00041 00042 matrix(2, 0) = 0.0; 00043 matrix(2, 1) = 0.0; 00044 matrix(2, 2) = bScale; 00045 matrix(2, 3) = 0.0; 00046 matrix(2, 4) = 0.0; 00047 00048 matrix(3, 0) = 0.0; 00049 matrix(3, 1) = 0.0; 00050 matrix(3, 2) = 0.0; 00051 matrix(3, 3) = aScale; 00052 matrix(3, 4) = 0.0; 00053 00054 matrix(4, 0) = 0.0; 00055 matrix(4, 1) = 0.0; 00056 matrix(4, 2) = 0.0; 00057 matrix(4, 3) = 0.0; 00058 matrix(4, 4) = 1.0; 00059 00060 return matrix; 00061 } 00062 00063 /** 00064 * @brief Make a contrast matrix. 00065 */ 00066 template<class Matrix5x5> 00067 Matrix5x5 contrastMatrix( 00068 const typename Matrix5x5::value_type rScale, 00069 const typename Matrix5x5::value_type gScale, 00070 const typename Matrix5x5::value_type bScale, 00071 const typename Matrix5x5::value_type aScale ) 00072 { 00073 Matrix5x5 matrix(5, 5); 00074 00075 matrix(0, 0) = rScale; 00076 matrix(0, 1) = 0.0; 00077 matrix(0, 2) = 0.0; 00078 matrix(0, 3) = 0.0; 00079 matrix(0, 4) = 0.0; 00080 00081 matrix(1, 0) = 0.0; 00082 matrix(1, 1) = gScale; 00083 matrix(1, 2) = 0.0; 00084 matrix(1, 3) = 0.0; 00085 matrix(1, 4) = 0.0; 00086 00087 matrix(2, 0) = 0.0; 00088 matrix(2, 1) = 0.0; 00089 matrix(2, 2) = bScale; 00090 matrix(2, 3) = 0.0; 00091 matrix(2, 4) = 0.0; 00092 00093 matrix(3, 0) = 0.0; 00094 matrix(3, 1) = 0.0; 00095 matrix(3, 2) = 0.0; 00096 matrix(3, 3) = 0.0; 00097 matrix(3, 4) = 0.0; 00098 00099 matrix(4, 0) = (1.0 - rScale) * 0.5; 00100 matrix(4, 1) = (1.0 - gScale) * 0.5; 00101 matrix(4, 2) = (1.0 - bScale) * 0.5; 00102 matrix(4, 3) = (1.0 - aScale) * 0.5; 00103 matrix(4, 4) = 1.0; 00104 00105 return matrix; 00106 } 00107 00108 /** 00109 * @brief Make a saturation matrix. 00110 */ 00111 template<class Matrix5x5> 00112 Matrix5x5 saturationMatrix( const typename Matrix5x5::value_type saturation ) 00113 { 00114 typedef typename Matrix5x5::value_type T; 00115 00116 const T a = (1.0-saturation) * s_redLum + saturation; 00117 const T b = (1.0-saturation) * s_redLum; 00118 const T c = (1.0-saturation) * s_redLum; 00119 const T d = (1.0-saturation) * s_greenLum; 00120 const T e = (1.0-saturation) * s_greenLum + saturation; 00121 const T f = (1.0-saturation) * s_greenLum; 00122 const T g = (1.0-saturation) * s_blueLum; 00123 const T h = (1.0-saturation) * s_blueLum; 00124 const T i = (1.0-saturation) * s_blueLum + saturation; 00125 00126 Matrix5x5 matrix(5, 5); 00127 00128 matrix(0, 0) = a; 00129 matrix(0, 1) = b; 00130 matrix(0, 2) = c; 00131 matrix(0, 3) = 0.0; 00132 matrix(0, 4) = 0.0; 00133 00134 matrix(1, 0) = d; 00135 matrix(1, 1) = e; 00136 matrix(1, 2) = f; 00137 matrix(1, 3) = 0.0; 00138 matrix(1, 4) = 0.0; 00139 00140 matrix(2, 0) = g; 00141 matrix(2, 1) = h; 00142 matrix(2, 2) = i; 00143 matrix(2, 3) = 0.0; 00144 matrix(2, 4) = 0.0; 00145 00146 matrix(3, 0) = 0.0; 00147 matrix(3, 1) = 0.0; 00148 matrix(3, 2) = 0.0; 00149 matrix(3, 3) = 1.0; // no saturation on alpha channel 00150 matrix(3, 4) = 0.0; 00151 00152 matrix(4, 0) = 0.0; 00153 matrix(4, 1) = 0.0; 00154 matrix(4, 2) = 0.0; 00155 matrix(4, 3) = 0.0; 00156 matrix(4, 4) = 1.0; 00157 00158 return matrix; 00159 } 00160 00161 /** 00162 * @brief Offset r, g, and b. 00163 */ 00164 template<class Matrix5x5> 00165 Matrix5x5 offsetMatrix( 00166 const typename Matrix5x5::value_type rOffset, 00167 const typename Matrix5x5::value_type gOffset, 00168 const typename Matrix5x5::value_type bOffset, 00169 const typename Matrix5x5::value_type aOffset ) 00170 { 00171 Matrix5x5 matrix(5, 5); 00172 00173 matrix(0, 0) = 1.0; 00174 matrix(0, 1) = 0.0; 00175 matrix(0, 2) = 0.0; 00176 matrix(0, 3) = 0.0; 00177 matrix(0, 4) = 0.0; 00178 00179 matrix(1, 0) = 0.0; 00180 matrix(1, 1) = 1.0; 00181 matrix(1, 2) = 0.0; 00182 matrix(1, 3) = 0.0; 00183 matrix(1, 4) = 0.0; 00184 00185 matrix(2, 0) = 0.0; 00186 matrix(2, 1) = 0.0; 00187 matrix(2, 2) = 1.0; 00188 matrix(2, 3) = 0.0; 00189 matrix(2, 4) = 0.0; 00190 00191 matrix(3, 0) = 0.0; 00192 matrix(3, 1) = 0.0; 00193 matrix(3, 2) = 0.0; 00194 matrix(3, 3) = 1.0; 00195 matrix(3, 4) = 0.0; 00196 00197 matrix(4, 0) = rOffset; 00198 matrix(4, 1) = gOffset; 00199 matrix(4, 2) = bOffset; 00200 matrix(4, 3) = aOffset; 00201 matrix(4, 4) = 1.0; 00202 00203 return matrix; 00204 } 00205 00206 /** 00207 * @brief rotate about the x (red) axis. 00208 */ 00209 template<class Matrix5x5> 00210 Matrix5x5 xRotateMatrix( 00211 const typename Matrix5x5::value_type rs, 00212 const typename Matrix5x5::value_type rc ) 00213 { 00214 Matrix5x5 matrix(5, 5); 00215 00216 matrix(0, 0) = 1.0; 00217 matrix(0, 1) = 0.0; 00218 matrix(0, 2) = 0.0; 00219 matrix(0, 3) = 0.0; 00220 matrix(0, 4) = 0.0; 00221 00222 matrix(1, 0) = 0.0; 00223 matrix(1, 1) = rc; 00224 matrix(1, 2) = rs; 00225 matrix(1, 3) = 0.0; 00226 matrix(1, 4) = 0.0; 00227 00228 matrix(2, 0) = 0.0; 00229 matrix(2, 1) = -rs; 00230 matrix(2, 2) = rc; 00231 matrix(2, 3) = 0.0; 00232 matrix(2, 4) = 0.0; 00233 00234 matrix(3, 0) = 0.0; 00235 matrix(3, 1) = 0.0; 00236 matrix(3, 2) = 0.0; 00237 matrix(3, 3) = 1.0; 00238 matrix(3, 4) = 0.0; 00239 00240 matrix(4, 0) = 0.0; 00241 matrix(4, 1) = 0.0; 00242 matrix(4, 2) = 0.0; 00243 matrix(4, 3) = 0.0; 00244 matrix(4, 4) = 1.0; 00245 00246 return matrix; 00247 } 00248 00249 /** 00250 * @brief Rotate about the y (green) axis. 00251 */ 00252 template<class Matrix5x5> 00253 Matrix5x5 yRotateMatrix( 00254 const typename Matrix5x5::value_type rs, 00255 const typename Matrix5x5::value_type rc ) 00256 { 00257 Matrix5x5 matrix(5, 5); 00258 00259 matrix(0, 0) = rc; 00260 matrix(0, 1) = 0.0; 00261 matrix(0, 2) = -rs; 00262 matrix(0, 3) = 0.0; 00263 matrix(0, 4) = 0.0; 00264 00265 matrix(1, 0) = 0.0; 00266 matrix(1, 1) = 1.0; 00267 matrix(1, 2) = 0.0; 00268 matrix(1, 3) = 0.0; 00269 matrix(1, 4) = 0.0; 00270 00271 matrix(2, 0) = rs; 00272 matrix(2, 1) = 0.0; 00273 matrix(2, 2) = rc; 00274 matrix(2, 3) = 0.0; 00275 matrix(2, 4) = 0.0; 00276 00277 matrix(3, 0) = 0.0; 00278 matrix(3, 1) = 0.0; 00279 matrix(3, 2) = 0.0; 00280 matrix(3, 3) = 1.0; 00281 matrix(3, 4) = 0.0; 00282 00283 matrix(4, 0) = 0.0; 00284 matrix(4, 1) = 0.0; 00285 matrix(4, 2) = 0.0; 00286 matrix(4, 3) = 0.0; 00287 matrix(4, 4) = 1.0; 00288 00289 return matrix; 00290 } 00291 00292 /** 00293 * @brief Rotate about the z (blue) axis. 00294 */ 00295 template<class Matrix5x5> 00296 Matrix5x5 zRotateMatrix( 00297 const typename Matrix5x5::value_type rs, 00298 const typename Matrix5x5::value_type rc ) 00299 { 00300 Matrix5x5 matrix(5, 5); 00301 00302 matrix(0, 0) = rc; 00303 matrix(0, 1) = rs; 00304 matrix(0, 2) = 0.0; 00305 matrix(0, 3) = 0.0; 00306 matrix(0, 4) = 0.0; 00307 00308 matrix(1, 0) = -rs; 00309 matrix(1, 1) = rc; 00310 matrix(1, 2) = 0.0; 00311 matrix(1, 3) = 0.0; 00312 matrix(1, 4) = 0.0; 00313 00314 matrix(2, 0) = 0.0; 00315 matrix(2, 1) = 0.0; 00316 matrix(2, 2) = 1.0; 00317 matrix(2, 3) = 0.0; 00318 matrix(2, 4) = 0.0; 00319 00320 matrix(3, 0) = 0.0; 00321 matrix(3, 1) = 0.0; 00322 matrix(3, 2) = 0.0; 00323 matrix(3, 3) = 1.0; 00324 matrix(3, 4) = 0.0; 00325 00326 matrix(4, 0) = 0.0; 00327 matrix(4, 1) = 0.0; 00328 matrix(4, 2) = 0.0; 00329 matrix(4, 3) = 0.0; 00330 matrix(4, 4) = 1.0; 00331 00332 return matrix; 00333 } 00334 00335 /** 00336 * @brief Shear z using x and y. 00337 */ 00338 template<class Matrix5x5> 00339 Matrix5x5 zShearMatrix( 00340 const typename Matrix5x5::value_type dx, 00341 const typename Matrix5x5::value_type dy ) 00342 { 00343 Matrix5x5 matrix(5, 5); 00344 00345 matrix(0, 0) = 1.0; 00346 matrix(0, 1) = 0.0; 00347 matrix(0, 2) = dx; 00348 matrix(0, 3) = 0.0; 00349 matrix(0, 4) = 0.0; 00350 00351 matrix(1, 0) = 0.0; 00352 matrix(1, 1) = 1.0; 00353 matrix(1, 2) = dy; 00354 matrix(1, 3) = 0.0; 00355 matrix(1, 4) = 0.0; 00356 00357 matrix(2, 0) = 0.0; 00358 matrix(2, 1) = 0.0; 00359 matrix(2, 2) = 1.0; 00360 matrix(2, 3) = 0.0; 00361 matrix(2, 4) = 0.0; 00362 00363 matrix(3, 0) = 0.0; 00364 matrix(3, 1) = 0.0; 00365 matrix(3, 2) = 0.0; 00366 matrix(3, 3) = 1.0; 00367 matrix(3, 4) = 0.0; 00368 00369 matrix(4, 0) = 0.0; 00370 matrix(4, 1) = 0.0; 00371 matrix(4, 2) = 0.0; 00372 matrix(4, 3) = 0.0; 00373 matrix(4, 4) = 1.0; 00374 00375 return matrix; 00376 } 00377 00378 /** 00379 * @brief Simple hue rotation. This changes luminance. 00380 */ 00381 template<class Matrix5x5> 00382 Matrix5x5 simpleHueRotateMatrix( const typename Matrix5x5::value_type rotate ) 00383 { 00384 typedef typename Matrix5x5::value_type T; 00385 using boost::numeric::ublas::prec_prod; 00386 00387 Matrix5x5 matrix = boost::numeric::ublas::identity_matrix<T>( 5 ); 00388 00389 /* rotate the grey vector into positive Z */ 00390 static const T xmag = sqrt(2.0); 00391 static const T xrs = 1.0/xmag; 00392 static const T xrc = 1.0/xmag; 00393 matrix = prec_prod( matrix, 00394 xRotateMatrix<Matrix5x5>( xrs, xrc ) 00395 ); 00396 00397 static const T ymag = sqrt(3.0); 00398 static const T yrs = -1.0/ymag; 00399 static const T yrc = sqrt(2.0)/ymag; 00400 00401 matrix = prec_prod( matrix, 00402 yRotateMatrix<Matrix5x5>( yrs, yrc ) 00403 ); 00404 00405 /* rotate the hue */ 00406 const T zrs = std::sin( rotate * boost::math::constants::pi<T>() / 180.0 ); 00407 const T zrc = std::cos( rotate * boost::math::constants::pi<T>() / 180.0 ); 00408 matrix = prec_prod( matrix, 00409 zRotateMatrix( zrs, zrc ) 00410 ); 00411 00412 /* rotate the grey vector back into place */ 00413 matrix = prec_prod( matrix, 00414 yRotateMatrix<Matrix5x5>( -yrs, yrc ) 00415 ); 00416 matrix = prec_prod( matrix, 00417 xRotateMatrix<Matrix5x5>( -xrs, xrc ) 00418 ); 00419 00420 return matrix; 00421 } 00422 00423 00424 /** 00425 * @brief Simple hue rotation. This changes luminance. 00426 */ 00427 template<class Matrix5x5> 00428 void xformpnt( 00429 const Matrix5x5& matrix, 00430 const typename Matrix5x5::value_type x, 00431 const typename Matrix5x5::value_type y, 00432 const typename Matrix5x5::value_type z, 00433 typename Matrix5x5::value_type* tx, 00434 typename Matrix5x5::value_type* ty, 00435 typename Matrix5x5::value_type* tz ) 00436 { 00437 *tx = x*matrix(0, 0) + y*matrix(1, 0) + z*matrix(2, 0) + matrix(4, 0); 00438 *ty = x*matrix(0, 1) + y*matrix(1, 1) + z*matrix(2, 1) + matrix(4, 1); 00439 *tz = x*matrix(0, 2) + y*matrix(1, 2) + z*matrix(2, 2) + matrix(4, 2); 00440 } 00441 00442 /** 00443 * @brief rotate the hue, while maintaining luminance. 00444 */ 00445 template<class Matrix5x5> 00446 Matrix5x5 hueRotateMatrix( const typename Matrix5x5::value_type rotate ) 00447 { 00448 typedef typename Matrix5x5::value_type T; 00449 using boost::numeric::ublas::prec_prod; 00450 00451 Matrix5x5 matrix = boost::numeric::ublas::identity_matrix<T>( 5 ); 00452 00453 // rotate the grey vector into positive Z 00454 const T xmag = std::sqrt(2.0); 00455 const T xrs = 1.0/xmag; 00456 const T xrc = 1.0/xmag; 00457 matrix = prec_prod( matrix, 00458 xRotateMatrix<Matrix5x5>( xrs, xrc ) ); 00459 00460 const T ymag = std::sqrt(3.0); 00461 const T yrs = -1.0/ymag; 00462 const T yrc = std::sqrt(2.0)/ymag; 00463 matrix = prec_prod( matrix, 00464 yRotateMatrix<Matrix5x5>( yrs, yrc ) ); 00465 00466 T lx; 00467 T ly; 00468 T lz; 00469 00470 // shear the space to make the luminance plane horizontal 00471 xformpnt( matrix, s_redLum, s_greenLum, s_blueLum, &lx, &ly, &lz ); 00472 00473 BOOST_ASSERT( lz != 0 ); 00474 const T zsx = lx/lz; 00475 const T zsy = ly/lz; 00476 matrix = prec_prod( matrix, 00477 zShearMatrix<Matrix5x5>( zsx, zsy ) 00478 ); 00479 00480 // rotate the hue 00481 const T zrs = std::sin(rotate * boost::math::constants::pi<T>() / 180.0); 00482 const T zrc = std::cos(rotate * boost::math::constants::pi<T>() / 180.0); 00483 matrix = prec_prod( matrix, 00484 zRotateMatrix<Matrix5x5>( zrs, zrc ) 00485 ); 00486 00487 // unshear the space to put the luminance plane back 00488 matrix = prec_prod( matrix, 00489 zShearMatrix<Matrix5x5>( -zsx, -zsy ) 00490 ); 00491 00492 // rotate the grey vector back into place 00493 matrix = prec_prod( matrix, 00494 yRotateMatrix<Matrix5x5>( -yrs, yrc ) 00495 ); 00496 matrix = prec_prod( matrix, 00497 xRotateMatrix<Matrix5x5>( -xrs, xrc ) 00498 ); 00499 00500 return matrix; 00501 } 00502 00503 00504 } 00505 } 00506 00507 #endif 00508