第2章颜色空间变换 (征求意见稿) 清华大学计算机科学与技术系 智能技术与系统国家重点实验室 林福宗 2001年10月20日 附录:部分颜色空间转换参考程序 1.RGB和HSV 2.HLS/HSB和RGB 3.HSI和RGB 4. CIE XYZ和 CIELAB 5. CIE XYZ和RGB 1.RGB和HSV RGB→HsV ①执行RGB→HSⅤ( Travis)算法的C++参考程序 本客幸客水凇涂*称水客水客水水客 s Written by: Christopher Aagaard Course: CIS 540-Software Engineering Project I This is an alternate RGB to hsv conversion function ightly different algor *http://www.realtime.ru/wwwboard/messages/120.html * (note that if s=0, H is undefined and set to O) #include /*here for compilation purposes only */ / here for compilation purposes only*/ int main(void)(retum 0 double*rgb2hsvALT(double *rgb)i double *hsy= new double double R, G, B double H, s, v 1
1 第 2 章 颜色空间变换 (征求意见稿) 清华大学计算机科学与技术系 智能技术与系统国家重点实验室 林福宗 2001 年 10 月 20 日 附录:部分颜色空间转换参考程序 1. RGB 和 HSV 2. HLS/HSB 和 RGB 3. HSI 和 RGB 4. CIE XYZ 和 CIELAB 5. CIE XYZ 和 RGB --------------------------------------------------------- 1. RGB 和 HSV (1) RGB→HSV ① 执行 RGB→HSV(Travis)算法的 C++参考程序 /************************************************* * Written by: Christopher Aagaard * Course: CIS 540 - Software Engineering Project 1 * * This is an alternate RGB to HSV conversion function. * It uses a slightly different algorithm from: * http://www.realtime.ru/wwwboard/messages/120.html * (Travis) * (note that if S=0, H is undefined and set to 0) */ #include /*here for compilation purposes only*/ int main(void){return 0;} /* here for compilation purposes only*/ int main(void){return 0;} double* rgb2hsvALT(double *rgb) { double *hsv = new double[3]; double R, G, B; double R1, G1, B1; double H, S, V;
R=rgb[0 G=rgb(1: B-rgb[21 if( maxG)(min=; if(min>B)(min=B j if( max! =0)(S=delta/max; i if(S==0)(H=0; /*H is undefined"/ if(delta!=0)( RI=( GI=(max-G)/delta Bl=(max-B)/delta else(RI=Gl=bl=0; if(r==max & G==min)(H=5+Bl else if(R==max & Gl=min)(HI-Gl else if(G-max & B=min)(H=RI+; else if (G==max & B!=min)(H=3-Bl else if(R==max)(H3+GI else(H=5-Rl; /*converts to degrees so S and V are on the range [0, 1] *and H is on the range [0, 360]. */ HH*60 hsv[o=H hsv[l]=S; hsv[2]=V; return hsy. ②执行RGB→HSⅤ( Foley and vanDam)算法的C++参考程序 /*****本**本****幸********家***幸****亲幸本 Converts a rgb value to a hsv value Takes an array of length 3 containing RGB values s Returns an array of lenght 3 containing the converted HSV values 2
2 double max, min, delta; R=rgb[0]; G=rgb[1]; B=rgb[2]; max=R; if(maxG) {min=G;} if(min>B) {min=B;} delta=max-min; V=max; if(max!=0) {S=delta/max;} else{S=0;} if(S==0) {H=0;} /*H is undefined*/ else { if(delta!=0) { R1=(max-R)/delta; G1=(max-G)/delta; B1=(max-B)/delta; } else{R1=G1=B1=0;} } if(R==max && G==min) {H=5+B1;} else if (R==max && G!=min) {H=1-G1;} else if (G==max && B==min) {H=R1+1;} else if (G==max && B!=min) {H=3-B1;} else if (R==max) {H=3+G1;} else {H=5-R1;} /*converts to degrees so S and V are on the range [0,1] *and H is on the range [0,360].*/ H=H*60; hsv[0]=H; hsv[1]=S; hsv[2]=V; return hsv; } ② 执行 RGB→HSV (Foley and VanDam)算法的 C++参考程序 /********************************************************** * Converts a RGB value to a HSV value. * Takes an array of length 3 containing RGB values. * Returns an array of lenght 3 containing the converted HSV values
*H- between 0 and 360 (if s=0, H is undefined) * v- between 0 and 1 Algorithm translated to c++ from http://www.realtime.ru/wwwboard/messages/120.html * Foley and VanDam #include rgb2hsw( double *rgb)( double * hsv new double 31 double H,S, V double max; /*max of RGB* double min: /min of rGB* double delta:/ R=rgb[0]: G=rgb[1]: B-rgb(2] R if( B max)(max=B n=R: if(G<min)(min=G if( B<min)(min=B; j if( max I=0)(S=(max-min)/max, i if(S==0)(H=0; /undefined* if(max=R)(H(G-B)/delta, 3 if( max=G)(H2+(B-R)/delta if( max-B)(H4+(R-G)/delta, H=H60 ifH<0){HH360;} v[]=H; hsv[l]=S; hsv(2]=V, return hsy: (引自:htp/www.cis.ksuedu/-steam200
3 * H - between 0 and 360 (if S=0, H is undefined) * S - between 0 and 1 * V - between 0 and 1 * * Algorithm translated to C++ from: * http://www.realtime.ru/wwwboard/messages/120.html * (Foley and VanDam) */ #include double* rgb2hsv(double *rgb) { double R, G, B; double *hsv = new double[3]; double H, S, V; double max; /*max of RGB*/ double min; /*min of RGB*/ double delta; /*max-min*/ R=rgb[0]; G=rgb[1]; B=rgb[2]; max=R; if(G>max) {max=G;} if(B>max) {max=B;} min=R; if(G<min) {min=G;} if(B<min) {min=B;} V=max; if(max != 0) {S=(max-min)/max;} else {S=0;} if(S == 0) {H=0;} /*undefined*/ else { delta=max-min; if(max==R) {H=(G-B)/delta;} if(max==G) {H=2+(B-R)/delta;} if(max==B) {H=4+(R-G)/delta;} } H=H*60; if(H<0) {H=H+360;} hsv[0]=H; hsv[1]=S; hsv[2]=V; return hsv; } (引自:http://www.cis.ksu.edu/~seteam20/)
(2)HsV→RGB ①执行HSV→RGB( Travis)算法的C++参考程序 /****幸**幸春本****幸本本***春春本本***春本本春率本***幸 This is an alternate conversion of a hsv value to a rgb value s Takes an array of length 3 containing HsV values Returns an array of lenght 3 containing the converted RGB values Algorithm translated to C++ from *http://www.realtime.ru/wwwboard/messages/120.html double* hsv2rgbalT(double * hsv)i double* rgb= new double[31 double H s, v double hex. main colour. sub color double varl. var 2. var3 Hhsvlol: S=hsv[l: V=hsv(21 hex=H/360: /*convert h degrees to a hexagon section * main colour=(int hex sub colour=hex-main colour varl=(l-S)"V var2=(1-(S*sub colour))*V, var3=(1-(S*(l colour)))* if( main colour=0)(R=V, G=var 3: B-var1 if( main colour=1)(R=var 2 G=V B-var1 if( main colour=2)(R=varl; G=V B-var3 if( main colour=3)(R=varl; G=var2, B-V;) main colour- :4)(R=var 3: G=var1; B-V, 3 if( main colour=5)(R=V G=varl: B-var 2: 1 rgb[0]=R; rgb[1=G; rgb[2]=B, return rgb, ②执行HSⅤ→RGB( Foley and VanDam)算法的C++参考程序 称水客客客水客水客*客水*客水***水水客水水*客*客*容水*客水客水客水凇客水客 Converts a hSv value to a rgB value Takes an array of length 3 containing HSV values Returns an array of lenght 3 containing the converted RGB values
4 (2) HSV→RGB ① 执行 HSV→RGB(Travis)算法的 C++参考程序 /************************************************************* * This is an alternate conversion of a HSV value to a RGB value. * Takes an array of length 3 containing HSV values. * Returns an array of lenght 3 containing the converted RGB values. * * Algorithm translated to C++ from: * http://www.realtime.ru/wwwboard/messages/120.html * (Travis) */ double* hsv2rgbALT(double *hsv) { double* rgb = new double[3]; double H, S, V; double R, G, B; double hex, main_colour, sub_colour; double var1, var2, var3; H=hsv[0]; S=hsv[1]; V=hsv[2]; hex=H/360; /*convert H degrees to a hexagon section*/ main_colour=(int)hex; sub_colour=hex-main_colour; var1=(1-S)*V; var2=(1-(S*sub_colour))*V; var3=(1-(S*(1-sub_colour)))*V; if(main_colour==0) {R=V; G=var3; B=var1;} if(main_colour==1) {R=var2; G=V; B=var1;} if(main_colour==2) {R=var1; G=V; B=var3;} if(main_colour==3) {R=var1; G=var2; B=V; } if(main_colour==4) {R=var3; G=var1; B=V; } if(main_colour==5) {R=V; G=var1; B=var2;} rgb[0]=R; rgb[1]=G; rgb[2]=B; return rgb; } ② 执行 HSV→RGB (Foley and VanDam)算法的 C++参考程序 /**************************************************** * Converts a HSV value to a RGB value. * Takes an array of length 3 containing HSV values. * Returns an array of lenght 3 containing the converted RGB values
Algorithm translated to C++ from s/120 htr double rgb= new double[31 double r, g, B, double H s, v ouble i f, p, g, t if(s==0 & H=0)(R=G=B-V; )/*if S=0 and H is undefined*/ ifH=360){H=0; oor(h) p=V(1-S) if(F=0)(R=V, G=t; B-p; i 珉F=1){R=q,G=V,Bp;} 珉F=2){R=p,G=V,B=t} if(F=)(R=p: G=q: B-V, if(F-4)(R=t; G=p: B-V;; if(F=5)(R=V, G=p: B-q) 2.HLS/HSB和RGB **称*客水*客水*客客水水客水*水*水*水*客水**客客水*涂客水水*客*水*客水客水**水客水*水客水*客水*宗*客水农水 The hsl model is in some fashion a boosted hsv model. Even if it's based on the Ostwald system, created around 1930(not sure: maybe it was 1931). It forms a s dodecahedron formed by two Hexcone base to base, with one sharp point black, and s with the other white. IT has some disadvantages since the purity of color not at max value but at its half (=0.5). It makes it a little harder to use with the common 3 axis(sliders if you use Mac or Windows)H, L, S. By the way: H is for Hue, L for lightness. Lightness of 1=white, 0=black and S is still *涂*水*客水容水**水容水*客水*涂**水**客**水*客***客***水水*客**水*水***客水*****幸 function value(nl, n2, hue real): real
5 * Algorithm translated to C++ from: * http://www.realtime.ru/wwwboard/messages/120.html * (Foley and VanDam) */ double* hsv2rgb(double *hsv) { double *rgb = new double[3]; double R, G, B; double H, S, V; double i, f, p, q, t; H=hsv[0]; S=hsv[1]; V=hsv[2]; if(S==0 && H==0) {R=G=B=V;} /*if S=0 and H is undefined*/ if(H==360) {H=0;} H=H/60; i=floor(H); f=H-i; p=V*(1-S); q=V*(1-(S*f)); t=V*(1-(S*(1-f))); if(i==0) {R=V; G=t; B=p;} if(i==1) {R=q; G=V; B=p;} if(i==2) {R=p; G=V; B=t;} if(i==3) {R=p; G=q; B=V;} if(i==4) {R=t; G=p; B=V;} if(i==5) {R=V; G=p; B=q;} rgb[0]=R; rgb[1]=G; rgb[2]=B; return rgb; } 2. HLS/HSB 和 RGB ********************************************************************* * The HSL model is in some fashion a boosted HSV model. Even if it's based on the * Ostwald system, created around 1930 (not sure: maybe it was 1931). It forms a * dodecahedron formed by two Hexcone base to base, with one sharp point black, and * with the other white. IT has some disadvantages since the purity of color is * not at max value but at its half ( = 0.5). It makes it a little harder to use * with the common 3 axis (sliders if you use Mac or Windows) H,L,S. By the way: H * is for Hue, L for lightness. Lightness of 1=white, 0=black and S is still * saturation. ********************************************************************* function value(n1,n2,hue :real) : real;
if hue > 360 then if hue =240 then result =nl if hue<240 then result: =n1+(n2-n1)*(240-hue )60 if hue< 180 then resu ult: =n1+(n2-n1)*hue/60 end procedure rgb2hsl(r,g, b: integer; var h, S, I real); cl c2 c3, delta, kmin, kmax: real minmax: array[1.3] of double cl=r/255; c2:=g/255 2]}= minmax[3]: =c3 kmax:=maxvalue(minmax) H Evaluate luminosity j 1: =(kmaxkmin)/2 Evaluate saturation if kr kmin then 0 if1<=0.5 then S: =(kmax-kmin (kmax+kmin) else 6
6 begin if hue >= 360 then hue := hue-360 else if hue =240 then result := n1; if hue<240 then result := n1+(n2-n1)*(240-hue)/60; if hue<180 then result := n2; if hue < 60 then result := n1+(n2-n1)*hue/60; end; ************************************* procedure rgb2hsl (r,g,b :integer ;var h, s, l :real); var c1,c2,c3,delta,kmin,kmax :real; minmax:array[1..3] of double; begin c1:=r/255; c2:=g/255; c3:=b/255; minmax[1]:=c1; minmax[2]:=c2; minmax[3]:=c3; kmin:= minvalue(minmax); kmax:=maxvalue(minmax); {Evaluate luminosity } l := (kmax+kmin)/2; {Evaluate saturation} if kmax = kmin then begin s := 0; h:= 0; end else begin if l <= 0.5 then s := (kmax-kmin)/(kmax+kmin) else
S:=(kmax-kmin )/(2-kmax-kmin) Evaluate Hue) delta kmax-kmin if kmax = cl then h: =(c2-c3)delta if kmax c2 then h: =2+(c3-cl)delta if kmax = c3 then h: =4+(cl-c2)delta h:=h*60 if h<o then h:=h+360 end end procedure hsl2rgb(h, S, I: real var r,g, b: integer ) cl c2c3. m1 m2: real if K<=0.5 then m2:=1*(1+ m2:=|+s*(1-1), ml:=2*}-m2 cl: valore(ml, m2, h+120) c2: =valore(ml, m2, h) c3: = valore(ml, m2, h-120) if(s=0)and(h=0)then c2s l; l; r:=round(cl*255) round(c2*255) b: =round(c3*255) 3.HSI和RGB (1)执行RGB→HS转换的参考程序 /*****幸本*家家*****事容***容本*家*家本********亲*本春水* Converts a rgb value to a hsi value 7
7 s := (kmax-kmin)/(2-kmax-kmin) ; {Evaluate Hue} delta := kmax-kmin ; if kmax = c1 then h := (c2-c3)/delta; if kmax = c2 then h := 2+(c3-c1)/delta; if kmax = c3 then h := 4+(c1-c2)/delta ; h := h*60; if h<0 then h := h+360; end; end; ************************************* procedure hsl2rgb (h, s, l : real ;var r,g,b : integer); var c1,c2,c3,m1,m2 : real; begin if l<=0.5 then m2 := l*(1+s) else m2 := l+s*(1-l); m1 := 2*l-m2; c1 := valore(m1,m2,h+120); c2 := valore(m1,m2,h); c3 := valore(m1,m2,h-120); if (s = 0) and (h = 0) then begin c1 := l; c2 := l; c3 := l; end; r:=round(c1*255); g:=round(c2*255); b:=round(c3*255); end; 3. HSI 和 RGB (1) 执行 RGB→HIS 转换的参考程序 /**************************************************************** * Converts a RGB value to a HSI value
s Takes an array of length 3 containing RGB values s Returns an array of lenght 3 containing the converted HSI values *(If S=0, H is meaningless and set to O) Algorithm translated to C++ fro http://www.cosy.sbg.ac.at/-mliedl/tutors/colorconv.html #include double* rgb2hsi( double *rgb)( double*hsi=new double[3] ole r, g, B, double min R=rgb[0]: G=rgb[1]: B-=rgb[2]: min=R: if( min >G)(min=G; l=(1/3)*(R+G+B) S=1-(3/(R+G+B)*min; H-acos((((R-G)/2)+(R-B)/(sqrt(pow(R-G, 2)+(R-B)(G-B)))) if(S==0)(H0; /if S=0, H is if(BD)>(G/I){H=360-H} /*since H is an angle. we then normalize to 0.1 with H=H/360* HH360; hsi[0=H, hsi[l]=S; hsi[2=I return hsI (2)执行HSI→RGB转换的参考程序 Converts a hsi value to a rgb value Takes an array of length 3 containing HSI values of lenght 3 containing the converted rgb value *(If s=0, H is meaningless and set to o) *http://www.cosy.sbgac.at/--mliedl/tutors/colorconv.html #include double* hsi2rgb( double *hsi)i e[3] ouble H S, I R G, B
8 * Takes an array of length 3 containing RGB values. * Returns an array of lenght 3 containing the converted HSI values. * (If S=0, H is meaningless and set to 0) * * Algorithm translated to C++ from: * http://www.cosy.sbg.ac.at/~mliedl/tutors/Colorconv.html *****************************************************************/ #include double* rgb2hsi(double *rgb) { double *hsi = new double[3]; double H, S, I; double R, G, B; double min; R=rgb[0]; G=rgb[1]; B=rgb[2]; min=R; if(min>G) {min=G;} if(min>B) {min=B;} I=(1/3)*(R+G+B); S=1-(3/(R+G+B))*min; H=acos( (((R-G)/2)+(R-B))/(sqrt(pow(R-G,2)+(R-B)*(G-B))) ); if(S==0) {H=0;} /*if S=0, H is meaningless*/ if((B/I)>(G/I)) {H=360-H;} /*since H is an angle, we then normalize to 0,1 with H=H/360*/ H=H/360; hsi[0]=H; hsi[1]=S; hsi[2]=I; return hsi; } (2) 执行 HSI→RGB 转换的参考程序 /******************************************************* * Converts a HSI value to a RGB value. * Takes an array of length 3 containing HSI values. * Returns an array of lenght 3 containing the converted RGB values. * (If S=0, H is meaningless and set to 0) * * Algorithm translated to C++ from: * http://www.cosy.sbg.ac.at/~mliedl/tutors/Colorconv.html */ #include double* hsi2rgb(double *hsi) { double *rgb = new double[3]; double H, S, I; double R, G, B;
H-hsi0]: S=hsi[l]: 1=hsi[2] HH*360: /restore H to degrees*/ ifF>0&&H240&&H<=360){ H=H240 G=(1-S)/3 B=(1+(S*cos(H)(cos(60-H)/3 R=1-(G+B) return rgb, 4. CIE XYZ和 CIELAB /******本本**本本*****本**亲*本**亲*本*亲***** File: XYZSet java Description: Conversion between RGB, XYZ and CIELAB color spaces Author: Gene Vishnevsky Oct 15, 1997 This class implements conversions between RGB, CIE XYZ and CIELAB color public class XYZSet f float L aa bb: / current ClE Lab coords float,Y, Z; //CIE XYZ coords int r, g, b ∥/ RGB coords float rf, gf, bf; /[0, 1]RGB x color matching function tabulated at 20-nm intervals (10-degree 1964 CIE suppl. std observer) static float Px[=1
9 H=hsi[0]; S=hsi[1]; I=hsi[2]; H=H*360; /*restore H to degrees*/ if(H>0 && H120 && H240 && H<=360) { H=H-240; G=(1-S)/3; B=(1+(S*cos(H))/(cos(60-H)))/3; R=1-(G+B); } rgb[0]=R; rgb[1]=G; rgb[2]=B; return rgb; } 4. CIE XYZ 和 CIELAB /************************************************* * File: XYZSet.java * Description: Conversion between RGB, XYZ and CIELAB color spaces. * Author: Gene Vishnevsky Oct. 15, 1997 *************************************************/ /** * This class implements conversions between RGB, CIE XYZ and CIELAB color * spaces. */ public class XYZSet { float L, aa, bb; // current CIE Lab coords float X, Y, Z; // CIE XYZ coords int r, g, b; // RGB coords float rf, gf, bf; // [0,1] RGB /** * x color matching function tabulated at 20-nm intervals. * (10-degree 1964 CIE suppl. std. observer) */ static float Px[] = {
0.00327f,0.03505f,0.06577f,0.05182f, 0.01380f.0.00065f0.02017f0.06458f 0.12087f,0.1738410.19266f,0.14677f, 0.07398f0.026l6f0.0070lf0.00165f s y color matching function tabulated at 20-nm intervals (10-degree 1964 CIE suppl. std observer) static float Py=1 0.00034f,0.00367f,0.01064f,0.02197f, 0.04347f,0.07898f,0.13058f,0.16489f, 0.17094f,0.14893f,0.11284f,0.06824f1 0.03082f,0.01034f,0.00273f,0.00062f s z color matching function tabulated at 20-nm intervals *(10-degree 1964 CIE suppl. std. observer) static float Pz=i 001474f,0.16669f,0.33720f,0.29917f, 0.13234f,0.03745f,0.01040f,0.00235f, ofofofofofof. of of 4 Constructs a converter with no arguments public XYZSeto; i s Constructs a converter with an argument @param rgb RGB components that are used to compute initial XYZ and LAb values * @see RGBCoord public XYZSet( RGBCoord rgb)( convert FromRGB( rgb Converts from RGB to xyZ and LAB
10 0.00327f, 0.03505f, 0.06577f, 0.05182f, 0.01380f, 0.00065f, 0.02017f, 0.06458f, 0.12087f, 0.17384f, 0.19266f, 0.14677f, 0.07398f, 0.02616f, 0.00701f, 0.00165f }; /** * y color matching function tabulated at 20-nm intervals. * (10-degree 1964 CIE suppl. std. observer) */ static float Py[] = { 0.00034f, 0.00367f, 0.01064f, 0.02197f, 0.04347f, 0.07898f, 0.13058f, 0.16489f, 0.17094f, 0.14893f, 0.11284f, 0.06824f, 0.03082f, 0.01034f, 0.00273f, 0.00062f }; /** * z color matching function tabulated at 20-nm intervals. * (10-degree 1964 CIE suppl. std. observer) */ static float Pz[] = { 0.01474f, 0.16669f, 0.33720f, 0.29917f, 0.13234f, 0.03745f, 0.01040f, 0.00235f, 0f, 0f, 0f, 0f, 0f, 0f, 0f, 0f }; /** * Constructs a converter with no arguments. */ public XYZSet() { ; } /** * Constructs a converter with an argument. * @param rgb RGB components that are used to compute initial XYZ and LAB values. * @see RGBCoord */ public XYZSet( RGBCoord rgb ) { convertFromRGB( rgb ); } /** * Converts from RGB to XYZ and LAB