GLSLに限らず画像処理やエフェクトを書いていると、RGB座標系だけで考えていると限界があります。
別の色空間に変換して処理することで出来ることが増えたり、処理が楽になったりします。特に色合いと色の強度を分離できると多くの場面で役立ちます。
普段よく使うYUV色空間とHSV色空間をGLSLでも使ってみます。
YUV
YUV(YCbCr、YPbPr )は輝度Yと、青・赤の色差によって表現する色空間で動画などで多く用いられます。
映像規格ITU-R BT.709に基づいて変換してみます。
単純な行列を使った線形変換です。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
//ITU-R BT.709 precision highp float; varying vec2 uv; uniform sampler2D t; uniform vec2 resolution; void main(){ mat3 rgb2yuv=mat3( .2126,.7152,.0722, -.114572,-.385428,.5, .5,-.454153,-.045847 ); mat3 yuv2rgb=mat3( 1.,0.,1.5748, 1.,-.187324,-.468124, 1.,1.8556,0. ); vec3 rgb=texture2D(t,uv).rgb; vec3 yuv=rgb*rgb2yuv; //輝度Y yuv.x+=0.1;//0 ~ 1 //色差(Cr, Cb) yuv.y=.5;//-0.5 ~ 0.5 yuv.z=-.5;//-0.5 ~ 0.5 gl_FragColor=vec4(yuv*yuv2rgb,1); } |
行列の掛け算が逆じゃない?って思った方は以前の投稿を参照してください。
この変換では輝度を少し増やして、色相を固定しています。

余談ですが、この変換の輝度YをそのままRGBに適応すると同規格のグレースケール変換になります。
HSV
HSVは色相(Hue)と彩度(Saturation)、明度(Value)で表す色空間です。
色相環はペイントソフト等でもよく使いますね。
非線形変換で多少複雑な計算になります。
色環を[0~2π]、0を赤として円錐モデルで変換します。
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
precision highp float; varying vec2 uv; uniform sampler2D t; uniform vec2 resolution; float tau=acos(-1.)*2.; void main(){ vec3 rgb=texture2D(t,uv).rgb; //rgb->hsv 計算 float ma=max(max(rgb.r,rgb.g),rgb.b); float mi=min(min(rgb.r,rgb.g),rgb.b); float s=ma-mi,v=ma; float h=ma==rgb.r?(rgb.g-rgb.b)/s:ma==rgb.g?(rgb.b-rgb.r)/s+tau/3.:(rgb.r-rgb.g)/s+2.*tau/3.; //色相をx座標に合わせてずらす h=mod(h+uv.x*tau,tau); //彩度をいじる s+=.5; //明度をいじる v=.9; //hsv->rgb 計算 float r,g,b; float unit=tau/6.; ma=v; mi=ma-s*ma; if(h<=unit){ r=ma; g=h/unit*s+mi; b=mi; }else if(h<2.*unit){ r=(2.*unit-h)/unit*s+mi; g=ma; b=mi; }else if(h<3.*unit){ r=mi; g=ma; b=(h-2.*unit)/unit*s+mi; }else if(h<4.*unit){ r=mi; g=(4.*unit-h)/unit*s+mi; b=ma; }else if(h<5.*unit){ r=(h-4.*unit)/unit*s+mi; g=mi; b=ma; }else if(h<6.*unit){ r=ma; g=mi; b=(6.*unit-h)/unit*s+mi;; } gl_FragColor=vec4(r,g,b,1); } |
hsv->rgbの変換が特にめんどくさいですね。
RGBがすべて同じ場合の処理は無視(赤として処理)してます。

また余談ですが彩度がSaturationなのにどうしても違和感があります。photometricな世界だと飽和のほうで使われるので。
HSVでは特に明るさに関わらない色そのものに対して処理できます。
照明の当たり方の異なる同じ物体に対して彩度、明度を固定する(色相のみの情報にする)とこうなります。


R=G=Bの情報が落ちてますが、明るさに関わらず処理できることがわかります。