00001
00133 #include <math.h>
00134 #include <stdio.h>
00135 #include <string.h>
00136 #include <ctype.h>
00137 #include "colorspace.h"
00138
00139 #ifdef MATLAB_MEX_FILE
00140 #include "mex.h"
00141 #endif
00142
00144 #define MIN(A,B) (((A) <= (B)) ? (A) : (B))
00145
00147 #define MAX(A,B) (((A) >= (B)) ? (A) : (B))
00148
00150 #define MIN3(A,B,C) (((A) <= (B)) ? MIN(A,C) : MIN(B,C))
00151
00153 #define MAX3(A,B,C) (((A) >= (B)) ? MAX(A,C) : MAX(B,C))
00154
00155 #ifndef M_PI
00156
00157 #define M_PI 3.14159265358979323846264338327950288
00158 #endif
00159
00164 #define GAMMACORRECTION(t) \
00165 (((t) <= 0.0031306684425005883) ? \
00166 (12.92*(t)) : (1.055*pow((t), 0.416666666666666667) - 0.055))
00167
00171 #define INVGAMMACORRECTION(t) \
00172 (((t) <= 0.0404482362771076) ? \
00173 ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))
00174
00179 #define LABF(t) \
00180 ((t >= 8.85645167903563082e-3) ? \
00181 pow(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))
00182
00187 #define LABINVF(t) \
00188 ((t >= 0.206896551724137931) ? \
00189 ((t)*(t)*(t)) : (108.0/841.0)*((t) - (4.0/29.0)))
00190
00192 #define WHITEPOINT_U ((4*WHITEPOINT_X) \
00193 /(WHITEPOINT_X + 15*WHITEPOINT_Y + 3*WHITEPOINT_Z))
00194 #define WHITEPOINT_V ((9*WHITEPOINT_Y) \
00195 /(WHITEPOINT_X + 15*WHITEPOINT_Y + 3*WHITEPOINT_Z))
00196
00198 #define UNKNOWN_SPACE 0
00199 #define RGB_SPACE 1
00200 #define YUV_SPACE 2
00201 #define YCBCR_SPACE 3
00202 #define JPEGYCBCR_SPACE 4
00203 #define YPBPR_SPACE 5
00204 #define YDBDR_SPACE 6
00205 #define YIQ_SPACE 7
00206 #define HSV_SPACE 8
00207 #define HSL_SPACE 9
00208 #define HSI_SPACE 10
00209 #define XYZ_SPACE 11
00210 #define LAB_SPACE 12
00211 #define LUV_SPACE 13
00212 #define LCH_SPACE 14
00213 #define CAT02LMS_SPACE 15
00214
00215 #define NUM_TRANSFORM_PAIRS 18
00216
00217
00219 static const struct
00220 {
00221 int Space[2];
00222 void (*Fun[2])(num*, num*, num*, num, num, num);
00223 } TransformPair[NUM_TRANSFORM_PAIRS] = {
00224 {{RGB_SPACE, YUV_SPACE}, {Rgb2Yuv, Yuv2Rgb}},
00225 {{RGB_SPACE, YCBCR_SPACE}, {Rgb2Ycbcr, Ycbcr2Rgb}},
00226 {{RGB_SPACE, JPEGYCBCR_SPACE}, {Rgb2Jpegycbcr, Jpegycbcr2Rgb}},
00227 {{RGB_SPACE, YPBPR_SPACE}, {Rgb2Ypbpr, Ypbpr2Rgb}},
00228 {{RGB_SPACE, YDBDR_SPACE}, {Rgb2Ydbdr, Ydbdr2Rgb}},
00229 {{RGB_SPACE, YIQ_SPACE}, {Rgb2Yiq, Yiq2Rgb}},
00230 {{RGB_SPACE, HSV_SPACE}, {Rgb2Hsv, Hsv2Rgb}},
00231 {{RGB_SPACE, HSL_SPACE}, {Rgb2Hsl, Hsl2Rgb}},
00232 {{RGB_SPACE, HSI_SPACE}, {Rgb2Hsi, Hsi2Rgb}},
00233 {{RGB_SPACE, XYZ_SPACE}, {Rgb2Xyz, Xyz2Rgb}},
00234 {{XYZ_SPACE, LAB_SPACE}, {Xyz2Lab, Lab2Xyz}},
00235 {{XYZ_SPACE, LUV_SPACE}, {Xyz2Luv, Luv2Xyz}},
00236 {{XYZ_SPACE, LCH_SPACE}, {Xyz2Lch, Lch2Xyz}},
00237 {{XYZ_SPACE, CAT02LMS_SPACE}, {Xyz2Cat02lms, Cat02lms2Xyz}},
00238 {{RGB_SPACE, LAB_SPACE}, {Rgb2Lab, Lab2Rgb}},
00239 {{RGB_SPACE, LUV_SPACE}, {Rgb2Luv, Luv2Rgb}},
00240 {{RGB_SPACE, LCH_SPACE}, {Rgb2Lch, Lch2Rgb}},
00241 {{RGB_SPACE, CAT02LMS_SPACE}, {Rgb2Cat02lms, Cat02lms2Rgb}}
00242 };
00243
00244
00245
00246
00247
00248
00249
00250
00251
00252
00261 void Rgb2Yuv(num *Y, num *U, num *V, num R, num G, num B)
00262 {
00263 *Y = (num)( 0.299*R + 0.587*G + 0.114*B);
00264 *U = (num)(-0.147*R - 0.289*G + 0.436*B);
00265 *V = (num)( 0.615*R - 0.515*G - 0.100*B);
00266 }
00267
00268
00275 void Yuv2Rgb(num *R, num *G, num *B, num Y, num U, num V)
00276 {
00277 *R = (num)(Y - 3.945707070708279e-05*U + 1.1398279671717170825*V);
00278 *G = (num)(Y - 0.3946101641414141437*U - 0.5805003156565656797*V);
00279 *B = (num)(Y + 2.0319996843434342537*U - 4.813762626262513e-04*V);
00280 }
00281
00282
00284 void Rgb2Ycbcr(num *Y, num *Cb, num *Cr, num R, num G, num B)
00285 {
00286 *Y = (num)( 65.481*R + 128.553*G + 24.966*B + 16);
00287 *Cb = (num)(-37.797*R - 74.203*G + 112.0 *B + 128);
00288 *Cr = (num)(112.0 *R - 93.786*G - 18.214*B + 128);
00289 }
00290
00291
00293 void Ycbcr2Rgb(num *R, num *G, num *B, num Y, num Cr, num Cb)
00294 {
00295 Y -= 16;
00296 Cb -= 128;
00297 Cr -= 128;
00298 *R = (num)(0.00456621004566210107*Y + 1.1808799897946415e-09*Cr + 0.00625892896994393634*Cb);
00299 *G = (num)(0.00456621004566210107*Y - 0.00153632368604490212*Cr - 0.00318811094965570701*Cb);
00300 *B = (num)(0.00456621004566210107*Y + 0.00791071623355474145*Cr + 1.1977497040190077e-08*Cb);
00301 }
00302
00303
00305 void Rgb2Jpegycbcr(num *Y, num *Cb, num *Cr, num R, num G, num B)
00306 {
00307 Rgb2Ypbpr(Y, Cb, Cr, R, G, B);
00308 *Cb += (num)0.5;
00309 *Cr += (num)0.5;
00310 }
00311
00313 void Jpegycbcr2Rgb(num *R, num *G, num *B, num Y, num Cb, num Cr)
00314 {
00315 Cb -= (num)0.5;
00316 Cr -= (num)0.5;
00317 Ypbpr2Rgb(R, G, B, Y, Cb, Cr);
00318 }
00319
00320
00322 void Rgb2Ypbpr(num *Y, num *Pb, num *Pr, num R, num G, num B)
00323 {
00324 *Y = (num)( 0.299 *R + 0.587 *G + 0.114 *B);
00325 *Pb = (num)(-0.1687367*R - 0.331264*G + 0.5 *B);
00326 *Pr = (num)( 0.5 *R - 0.418688*G - 0.081312*B);
00327 }
00328
00329
00331 void Ypbpr2Rgb(num *R, num *G, num *B, num Y, num Pb, num Pr)
00332 {
00333 *R = (num)(0.99999999999914679361*Y - 1.2188941887145875e-06*Pb + 1.4019995886561440468*Pr);
00334 *G = (num)(0.99999975910502514331*Y - 0.34413567816504303521*Pb - 0.71413649331646789076*Pr);
00335 *B = (num)(1.00000124040004623180*Y + 1.77200006607230409200*Pb + 2.1453384174593273e-06*Pr);
00336 }
00337
00338
00340 void Rgb2Ydbdr(num *Y, num *Db, num *Dr, num R, num G, num B)
00341 {
00342 *Y = (num)( 0.299*R + 0.587*G + 0.114*B);
00343 *Db = (num)(-0.450*R - 0.883*G + 1.333*B);
00344 *Dr = (num)(-1.333*R + 1.116*G + 0.217*B);
00345 }
00346
00347
00349 void Ydbdr2Rgb(num *R, num *G, num *B, num Y, num Db, num Dr)
00350 {
00351 *R = (num)(Y + 9.2303716147657e-05*Db - 0.52591263066186533*Dr);
00352 *G = (num)(Y - 0.12913289889050927*Db + 0.26789932820759876*Dr);
00353 *B = (num)(Y + 0.66467905997895482*Db - 7.9202543533108e-05*Dr);
00354 }
00355
00356
00358 void Rgb2Yiq(num *Y, num *I, num *Q, num R, num G, num B)
00359 {
00360 *Y = (num)(0.299 *R + 0.587 *G + 0.114 *B);
00361 *I = (num)(0.595716*R - 0.274453*G - 0.321263*B);
00362 *Q = (num)(0.211456*R - 0.522591*G + 0.311135*B);
00363 }
00364
00365
00367 void Yiq2Rgb(num *R, num *G, num *B, num Y, num I, num Q)
00368 {
00369 *R = (num)(Y + 0.9562957197589482261*I + 0.6210244164652610754*Q);
00370 *G = (num)(Y - 0.2721220993185104464*I - 0.6473805968256950427*Q);
00371 *B = (num)(Y - 1.1069890167364901945*I + 1.7046149983646481374*Q);
00372 }
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382
00383
00400 void Rgb2Hsv(num *H, num *S, num *V, num R, num G, num B)
00401 {
00402 num Max = MAX3(R, G, B);
00403 num Min = MIN3(R, G, B);
00404 num C = Max - Min;
00405
00406
00407 *V = Max;
00408
00409 if(C > 0)
00410 {
00411 if(Max == R)
00412 {
00413 *H = (G - B) / C;
00414
00415 if(G < B)
00416 *H += 6;
00417 }
00418 else if(Max == G)
00419 *H = 2 + (B - R) / C;
00420 else
00421 *H = 4 + (R - G) / C;
00422
00423 *H *= 60;
00424 *S = C / Max;
00425 }
00426 else
00427 *H = *S = 0;
00428 }
00429
00430
00446 void Hsv2Rgb(num *R, num *G, num *B, num H, num S, num V)
00447 {
00448 num C = S * V;
00449 num Min = V - C;
00450 num X;
00451
00452
00453 H -= 360*floor(H/360);
00454 H /= 60;
00455 X = C*(1 - fabs(H - 2*floor(H/2) - 1));
00456
00457 switch((int)H)
00458 {
00459 case 0:
00460 *R = Min + C;
00461 *G = Min + X;
00462 *B = Min;
00463 break;
00464 case 1:
00465 *R = Min + X;
00466 *G = Min + C;
00467 *B = Min;
00468 break;
00469 case 2:
00470 *R = Min;
00471 *G = Min + C;
00472 *B = Min + X;
00473 break;
00474 case 3:
00475 *R = Min;
00476 *G = Min + X;
00477 *B = Min + C;
00478 break;
00479 case 4:
00480 *R = Min + X;
00481 *G = Min;
00482 *B = Min + C;
00483 break;
00484 case 5:
00485 *R = Min + C;
00486 *G = Min;
00487 *B = Min + X;
00488 break;
00489 default:
00490 *R = *G = *B = 0;
00491 }
00492 }
00493
00494
00512 void Rgb2Hsl(num *H, num *S, num *L, num R, num G, num B)
00513 {
00514 num Max = MAX3(R, G, B);
00515 num Min = MIN3(R, G, B);
00516 num C = Max - Min;
00517
00518
00519 *L = (Max + Min)/2;
00520
00521 if(C > 0)
00522 {
00523 if(Max == R)
00524 {
00525 *H = (G - B) / C;
00526
00527 if(G < B)
00528 *H += 6;
00529 }
00530 else if(Max == G)
00531 *H = 2 + (B - R) / C;
00532 else
00533 *H = 4 + (R - G) / C;
00534
00535 *H *= 60;
00536 *S = (*L <= 0.5) ? (C/(2*(*L))) : (C/(2 - 2*(*L)));
00537 }
00538 else
00539 *H = *S = 0;
00540 }
00541
00542
00558 void Hsl2Rgb(num *R, num *G, num *B, num H, num S, num L)
00559 {
00560 num C = (L <= 0.5) ? (2*L*S) : ((2 - 2*L)*S);
00561 num Min = L - 0.5*C;
00562 num X;
00563
00564
00565 H -= 360*floor(H/360);
00566 H /= 60;
00567 X = C*(1 - fabs(H - 2*floor(H/2) - 1));
00568
00569 switch((int)H)
00570 {
00571 case 0:
00572 *R = Min + C;
00573 *G = Min + X;
00574 *B = Min;
00575 break;
00576 case 1:
00577 *R = Min + X;
00578 *G = Min + C;
00579 *B = Min;
00580 break;
00581 case 2:
00582 *R = Min;
00583 *G = Min + C;
00584 *B = Min + X;
00585 break;
00586 case 3:
00587 *R = Min;
00588 *G = Min + X;
00589 *B = Min + C;
00590 break;
00591 case 4:
00592 *R = Min + X;
00593 *G = Min;
00594 *B = Min + C;
00595 break;
00596 case 5:
00597 *R = Min + C;
00598 *G = Min;
00599 *B = Min + X;
00600 break;
00601 default:
00602 *R = *G = *B = 0;
00603 }
00604 }
00605
00606
00622 void Rgb2Hsi(num *H, num *S, num *I, num R, num G, num B)
00623 {
00624 num alpha = 0.5*(2*R - G - B);
00625 num beta = 0.866025403784439*(G - B);
00626
00627
00628 *I = (R + G + B)/3;
00629
00630 if(*I > 0)
00631 {
00632 *S = 1 - MIN3(R,G,B) / *I;
00633 *H = atan2(beta, alpha)*(180/M_PI);
00634
00635 if(*H < 0)
00636 *H += 360;
00637 }
00638 else
00639 *H = *S = 0;
00640 }
00641
00642
00658 void Hsi2Rgb(num *R, num *G, num *B, num H, num S, num I)
00659 {
00660 H -= 360*floor(H/360);
00661
00662 if(H < 120)
00663 {
00664 *B = I*(1 - S);
00665 *R = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
00666 *G = 3*I - *R - *B;
00667 }
00668 else if(H < 240)
00669 {
00670 H -= 120;
00671 *R = I*(1 - S);
00672 *G = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
00673 *B = 3*I - *R - *G;
00674 }
00675 else
00676 {
00677 H -= 240;
00678 *G = I*(1 - S);
00679 *B = I*(1 + S*cos(H*(M_PI/180))/cos((60 - H)*(M_PI/180)));
00680 *R = 3*I - *G - *B;
00681 }
00682 }
00683
00684
00685
00686
00687
00688
00689
00690
00691
00692
00693
00704 void Rgb2Xyz(num *X, num *Y, num *Z, num R, num G, num B)
00705 {
00706 R = INVGAMMACORRECTION(R);
00707 G = INVGAMMACORRECTION(G);
00708 B = INVGAMMACORRECTION(B);
00709 *X = (num)(0.4123955889674142161*R + 0.3575834307637148171*G + 0.1804926473817015735*B);
00710 *Y = (num)(0.2125862307855955516*R + 0.7151703037034108499*G + 0.07220049864333622685*B);
00711 *Z = (num)(0.01929721549174694484*R + 0.1191838645808485318*G + 0.9504971251315797660*B);
00712 }
00713
00714
00726 void Xyz2Rgb(num *R, num *G, num *B, num X, num Y, num Z)
00727 {
00728 num R1, B1, G1, Min;
00729
00730
00731 R1 = (num)( 3.2406*X - 1.5372*Y - 0.4986*Z);
00732 G1 = (num)(-0.9689*X + 1.8758*Y + 0.0415*Z);
00733 B1 = (num)( 0.0557*X - 0.2040*Y + 1.0570*Z);
00734
00735 Min = MIN3(R1, G1, B1);
00736
00737
00738 if(Min < 0)
00739 {
00740 R1 -= Min;
00741 G1 -= Min;
00742 B1 -= Min;
00743 }
00744
00745
00746 *R = GAMMACORRECTION(R1);
00747 *G = GAMMACORRECTION(G1);
00748 *B = GAMMACORRECTION(B1);
00749 }
00750
00751
00760 void Xyz2Lab(num *L, num *a, num *b, num X, num Y, num Z)
00761 {
00762 X /= WHITEPOINT_X;
00763 Y /= WHITEPOINT_Y;
00764 Z /= WHITEPOINT_Z;
00765 X = LABF(X);
00766 Y = LABF(Y);
00767 Z = LABF(Z);
00768 *L = 116*Y - 16;
00769 *a = 500*(X - Y);
00770 *b = 200*(Y - Z);
00771 }
00772
00773
00782 void Lab2Xyz(num *X, num *Y, num *Z, num L, num a, num b)
00783 {
00784 L = (L + 16)/116;
00785 a = L + a/500;
00786 b = L - b/200;
00787 *X = WHITEPOINT_X*LABINVF(a);
00788 *Y = WHITEPOINT_Y*LABINVF(L);
00789 *Z = WHITEPOINT_Z*LABINVF(b);
00790 }
00791
00792
00801 void Xyz2Luv(num *L, num *u, num *v, num X, num Y, num Z)
00802 {
00803 num u1, v1, Denom;
00804
00805
00806 if((Denom = X + 15*Y + 3*Z) > 0)
00807 {
00808 u1 = (4*X) / Denom;
00809 v1 = (9*Y) / Denom;
00810 }
00811 else
00812 u1 = v1 = 0;
00813
00814 Y /= WHITEPOINT_Y;
00815 Y = LABF(Y);
00816 *L = 116*Y - 16;
00817 *u = 13*(*L)*(u1 - WHITEPOINT_U);
00818 *v = 13*(*L)*(v1 - WHITEPOINT_V);
00819 }
00820
00821
00830 void Luv2Xyz(num *X, num *Y, num *Z, num L, num u, num v)
00831 {
00832 *Y = (L + 16)/116;
00833 *Y = WHITEPOINT_Y*LABINVF(*Y);
00834
00835 if(L != 0)
00836 {
00837 u /= L;
00838 v /= L;
00839 }
00840
00841 u = u/13 + WHITEPOINT_U;
00842 v = v/13 + WHITEPOINT_V;
00843 *X = (*Y) * ((9*u)/(4*v));
00844 *Z = (*Y) * ((3 - 0.75*u)/v - 5);
00845 }
00846
00847
00858 void Xyz2Lch(num *L, num *C, num *H, num X, num Y, num Z)
00859 {
00860 num a, b;
00861
00862
00863 Xyz2Lab(L, &a, &b, X, Y, Z);
00864 *C = sqrt(a*a + b*b);
00865 *H = atan2(b, a)*180.0/M_PI;
00866
00867 if(*H < 0)
00868 *H += 360;
00869 }
00870
00877 void Lch2Xyz(num *X, num *Y, num *Z, num L, num C, num H)
00878 {
00879 num a = C * cos(H*(M_PI/180.0));
00880 num b = C * sin(H*(M_PI/180.0));
00881
00882
00883 Lab2Xyz(X, Y, Z, L, a, b);
00884 }
00885
00886
00888 void Xyz2Cat02lms(num *L, num *M, num *S, num X, num Y, num Z)
00889 {
00890 *L = (num)( 0.7328*X + 0.4296*Y - 0.1624*Z);
00891 *M = (num)(-0.7036*X + 1.6975*Y + 0.0061*Z);
00892 *S = (num)( 0.0030*X + 0.0136*Y + 0.9834*Z);
00893 }
00894
00895
00897 void Cat02lms2Xyz(num *X, num *Y, num *Z, num L, num M, num S)
00898 {
00899 *X = (num)( 1.096123820835514*L - 0.278869000218287*M + 0.182745179382773*S);
00900 *Y = (num)( 0.454369041975359*L + 0.473533154307412*M + 0.072097803717229*S);
00901 *Z = (num)(-0.009627608738429*L - 0.005698031216113*M + 1.015325639954543*S);
00902 }
00903
00904
00905
00906
00907
00908
00909 void Rgb2Lab(num *L, num *a, num *b, num R, num G, num B)
00910 {
00911 num X, Y, Z;
00912 Rgb2Xyz(&X, &Y, &Z, R, G, B);
00913 Xyz2Lab(L, a, b, X, Y, Z);
00914 }
00915
00916
00917 void Lab2Rgb(num *R, num *G, num *B, num L, num a, num b)
00918 {
00919 num X, Y, Z;
00920 Lab2Xyz(&X, &Y, &Z, L, a, b);
00921 Xyz2Rgb(R, G, B, X, Y, Z);
00922 }
00923
00924
00925 void Rgb2Luv(num *L, num *u, num *v, num R, num G, num B)
00926 {
00927 num X, Y, Z;
00928 Rgb2Xyz(&X, &Y, &Z, R, G, B);
00929 Xyz2Luv(L, u, v, X, Y, Z);
00930 }
00931
00932
00933 void Luv2Rgb(num *R, num *G, num *B, num L, num u, num v)
00934 {
00935 num X, Y, Z;
00936 Luv2Xyz(&X, &Y, &Z, L, u, v);
00937 Xyz2Rgb(R, G, B, X, Y, Z);
00938 }
00939
00940 void Rgb2Lch(num *L, num *C, num *H, num R, num G, num B)
00941 {
00942 num X, Y, Z;
00943 Rgb2Xyz(&X, &Y, &Z, R, G, B);
00944 Xyz2Lch(L, C, H, X, Y, Z);
00945 }
00946
00947
00948 void Lch2Rgb(num *R, num *G, num *B, num L, num C, num H)
00949 {
00950 num X, Y, Z;
00951 Lch2Xyz(&X, &Y, &Z, L, C, H);
00952 Xyz2Rgb(R, G, B, X, Y, Z);
00953 }
00954
00955
00956 void Rgb2Cat02lms(num *L, num *M, num *S, num R, num G, num B)
00957 {
00958 num X, Y, Z;
00959 Rgb2Xyz(&X, &Y, &Z, R, G, B);
00960 Xyz2Cat02lms(L, M, S, X, Y, Z);
00961 }
00962
00963
00964 void Cat02lms2Rgb(num *R, num *G, num *B, num L, num M, num S)
00965 {
00966 num X, Y, Z;
00967 Cat02lms2Xyz(&X, &Y, &Z, L, M, S);
00968 Xyz2Rgb(R, G, B, X, Y, Z);
00969 }
00970
00971
00972
00973
00974
00975
00976
00977
00978
00980 static int IdFromName(const char *Name)
00981 {
00982 if(!strcmp(Name, "rgb") || *Name == 0)
00983 return RGB_SPACE;
00984 else if(!strcmp(Name, "yuv"))
00985 return YUV_SPACE;
00986 else if(!strcmp(Name, "ycbcr"))
00987 return YCBCR_SPACE;
00988 else if(!strcmp(Name, "jpegycbcr"))
00989 return YCBCR_SPACE;
00990 else if(!strcmp(Name, "ypbpr"))
00991 return YPBPR_SPACE;
00992 else if(!strcmp(Name, "ydbdr"))
00993 return YDBDR_SPACE;
00994 else if(!strcmp(Name, "yiq"))
00995 return YIQ_SPACE;
00996 else if(!strcmp(Name, "hsv") || !strcmp(Name, "hsb"))
00997 return HSV_SPACE;
00998 else if(!strcmp(Name, "hsl") || !strcmp(Name, "hls"))
00999 return HSL_SPACE;
01000 else if(!strcmp(Name, "hsi"))
01001 return HSI_SPACE;
01002 else if(!strcmp(Name, "xyz") || !strcmp(Name, "ciexyz"))
01003 return XYZ_SPACE;
01004 else if(!strcmp(Name, "lab") || !strcmp(Name, "cielab"))
01005 return LAB_SPACE;
01006 else if(!strcmp(Name, "luv") || !strcmp(Name, "cieluv"))
01007 return LUV_SPACE;
01008 else if(!strcmp(Name, "lch") || !strcmp(Name, "cielch"))
01009 return LCH_SPACE;
01010 else if(!strcmp(Name, "cat02lms") || !strcmp(Name, "ciecat02lms"))
01011 return CAT02LMS_SPACE;
01012 else
01013 return UNKNOWN_SPACE;
01014 }
01015
01016
01067 int GetColorTransform(colortransform *Trans, const char *TransformString)
01068 {
01069 int LeftNumChars = 0, RightNumChars = 0, LeftSide = 1, LeftToRight = 0;
01070 int i, j, SrcSpaceId, DestSpaceId;
01071 char LeftSpace[16], RightSpace[16], c;
01072
01073
01074 Trans->NumStages = 0;
01075 Trans->Fun[0] = 0;
01076 Trans->Fun[1] = 0;
01077
01078
01079 while(1)
01080 {
01081 c = *(TransformString++);
01082
01083 if(!c)
01084 break;
01085 else if(c == '<')
01086 {
01087 LeftToRight = 0;
01088 LeftSide = 0;
01089 }
01090 else if(c == '>')
01091 {
01092 LeftToRight = 1;
01093 LeftSide = 0;
01094 }
01095 else if(c != ' ' && c != '-' && c != '=')
01096 {
01097 if(LeftSide)
01098 {
01099 if(LeftNumChars < 15)
01100 LeftSpace[LeftNumChars++] = tolower(c);
01101 }
01102 else
01103 {
01104 if(RightNumChars < 15)
01105 RightSpace[RightNumChars++] = tolower(c);
01106 }
01107 }
01108 }
01109
01110
01111 LeftSpace[LeftNumChars] = 0;
01112 RightSpace[RightNumChars] = 0;
01113
01114
01115 if(LeftToRight)
01116 {
01117 SrcSpaceId = IdFromName(LeftSpace);
01118 DestSpaceId = IdFromName(RightSpace);
01119 }
01120 else
01121 {
01122 SrcSpaceId = IdFromName(RightSpace);
01123 DestSpaceId = IdFromName(LeftSpace);
01124 }
01125
01126
01127 if(SrcSpaceId == UNKNOWN_SPACE || DestSpaceId == UNKNOWN_SPACE)
01128 return 0;
01129
01130
01131 if(SrcSpaceId == DestSpaceId)
01132 return 1;
01133
01134
01135 for(i = 0; i < NUM_TRANSFORM_PAIRS; i++)
01136 {
01137 if(SrcSpaceId == TransformPair[i].Space[0]
01138 && DestSpaceId == TransformPair[i].Space[1])
01139 {
01140 Trans->NumStages = 1;
01141 Trans->Fun[0] = TransformPair[i].Fun[0];
01142 return 1;
01143 }
01144 else if(DestSpaceId == TransformPair[i].Space[0]
01145 && SrcSpaceId == TransformPair[i].Space[1])
01146 {
01147 Trans->NumStages = 1;
01148 Trans->Fun[0] = TransformPair[i].Fun[1];
01149 return 1;
01150 }
01151 }
01152
01153
01154 for(i = 1; i < NUM_TRANSFORM_PAIRS; i++)
01155 if(SrcSpaceId == TransformPair[i].Space[1])
01156 for(j = 0; j < i; j++)
01157 {
01158 if(DestSpaceId == TransformPair[j].Space[1]
01159 && TransformPair[i].Space[0] == TransformPair[j].Space[0])
01160 {
01161 Trans->NumStages = 2;
01162 Trans->Fun[0] = TransformPair[i].Fun[1];
01163 Trans->Fun[1] = TransformPair[j].Fun[0];
01164 return 1;
01165 }
01166 }
01167 else if(DestSpaceId == TransformPair[i].Space[1])
01168 for(j = 0; j < i; j++)
01169 {
01170 if(SrcSpaceId == TransformPair[j].Space[1]
01171 && TransformPair[j].Space[0] == TransformPair[i].Space[0])
01172 {
01173 Trans->NumStages = 2;
01174 Trans->Fun[0] = TransformPair[j].Fun[1];
01175 Trans->Fun[1] = TransformPair[i].Fun[0];
01176 return 1;
01177 }
01178 }
01179
01180 return 0;
01181 }
01182
01183
01191 void ApplyColorTransform(colortransform Trans,
01192 num *D0, num *D1, num *D2, num S0, num S1, num S2)
01193 {
01194 switch(Trans.NumStages)
01195 {
01196 case 1:
01197 Trans.Fun[0](D0, D1, D2, S0, S1, S2);
01198 break;
01199 case 2:
01200 {
01201 num T0, T1, T2;
01202 Trans.Fun[0](&T0, &T1, &T2, S0, S1, S2);
01203 Trans.Fun[1](D0, D1, D2, T0, T1, T2);
01204 }
01205 break;
01206 default:
01207 *D0 = S0;
01208 *D1 = S1;
01209 *D2 = S2;
01210 break;
01211 }
01212 }
01213
01214
01215
01216
01217
01218
01219
01220 #ifdef MATLAB_MEX_FILE
01221
01222 void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray*prhs[])
01223 {
01224 #define S_IN prhs[0]
01225 #define A_IN prhs[1]
01226 #define B_OUT plhs[0]
01227 #define IS_REAL_FULL_DOUBLE(P) (!mxIsComplex(P) \
01228 && !mxIsSparse(P) && mxIsDouble(P))
01229 num *A, *B;
01230 char *SBuf;
01231 const int *Size;
01232 colortransform Trans;
01233 int SBufLen, NumPixels, Channel, Channel2;
01234
01235
01236
01237 if(nrhs != 2)
01238 mexErrMsgTxt("Two input arguments required.");
01239 else if(nlhs > 1)
01240 mexErrMsgTxt("Too many output arguments.");
01241
01242 if(!mxIsChar(S_IN))
01243 mexErrMsgTxt("First argument should be a string.");
01244 if(!IS_REAL_FULL_DOUBLE(A_IN))
01245 mexErrMsgTxt("Second argument should be a real full double array.");
01246
01247 Size = mxGetDimensions(A_IN);
01248
01249 if(mxGetNumberOfDimensions(A_IN) > 3
01250 || Size[mxGetNumberOfDimensions(A_IN) - 1] != 3)
01251 mexErrMsgTxt("Second argument should be an Mx3 or MxNx3 array.");
01252
01253
01254 SBufLen = mxGetNumberOfElements(S_IN)*sizeof(mxChar) + 1;
01255 SBuf = mxMalloc(SBufLen);
01256 mxGetString(S_IN, SBuf, SBufLen);
01257
01258 if(!(GetColorTransform(&Trans, SBuf)))
01259 mexErrMsgTxt("Invalid syntax or unknown color space.");
01260
01261 mxFree(SBuf);
01262
01263 A = (num *)mxGetData(A_IN);
01264 NumPixels = mxGetNumberOfElements(A_IN)/3;
01265
01266
01267 B_OUT = mxCreateDoubleMatrix(0, 0, mxREAL);
01268 mxSetDimensions(B_OUT, Size, mxGetNumberOfDimensions(A_IN));
01269 mxSetData(B_OUT, B = mxMalloc(sizeof(num)*mxGetNumberOfElements(A_IN)));
01270
01271 Channel = NumPixels;
01272 Channel2 = NumPixels*2;
01273
01274
01275 while(NumPixels--)
01276 {
01277 ApplyColorTransform(Trans, B, B + Channel, B + Channel2,
01278 A[0], A[Channel], A[Channel2]);
01279 A++;
01280 B++;
01281 }
01282
01283 return;
01284 }
01285 #endif