LoginSignup
6
5

More than 5 years have passed since last update.

ピクセルと表色系の関係

Last updated at Posted at 2017-03-02

はじめに

画像を色調補正やフィルタリングなどの操作するには,表色系について知っておく必要があるので,ピクセルと色についてまとめた記事になります.
この記事で上げた表色系(色空間)以外にもたくさんありますが,良く使いそうな表色系を取り上げてます.
RGBとの変換処理はC/C++でのサンプルソース付きです.

表色系の種類

RGB表色系

ディスプレイで表示するときに必要.
各値は0~255の範囲で表現されている.

{\begin{align}
Color&=(r,g,b)\\
\\
White&=(255,255,255)\\
Black&=(0,0,0)\\
\\
Red&=(255,0,0)\\
Green&=(0,255,0)\\
Blue&=(0,0,255)\\
Yellow&=(255,255,0)\\
Cyan&=(0,255,255)\\
Magenta&=(255,0,255)\\
\end{align}
}

ピクセルを再掲

HSV表色系

RGB表色系より感覚的に値を設定できる.
Hは0.0~360.0,SとVは0.0~1.0が取りうる範囲.
さらにHは角度を表してるため,360を超えている場合は,H-360と計算して範囲内に収めることが可能.

// ------------------------------------------------
// rgb2hsv
// rgb[] : R,G,Bの順番に値が格納されている
// hsv[] : H,S,Vの順番に値が格納される
void rgb2hsv(int rgb[3], double hsv[3]) {
 int x = max(rgb[0], max(rgb[1], rgb[2]));
 int n = min(rgb[0], min(rgb[1], rgb[2]));
 hsv[2] = (double)x/255.0;
 if(hsv[2]==0.0) {
  hsv[1]=0.0;
  hsv[0]=0.0;
  return;
 }
 hsv[1] = (double)(x-n)/x;
 if(hsv[1]==0.0) {
  hsv[0]=0.0;
  return;
 }
 double h = 0.0;
 if(x==rgb[0])      h = 60.0*(rgb[1]-rgb[2])/(x-n);
 else if(x==rgb[1]) h = 120.0+60.0*(rgb[2]-rgb[0])/(x-n);
 else if(x==rgb[2]) h = 240.0+60.0*(rgb[0]-rgb[1])/(x-n);

 if(h<0.0) h+=360.0;
 if(h>360.0) h-=360.0;
 hsv[0]=h;
}

// ------------------------------------------------
// hsv2rgb
// hsv[] : H,S,Vの順番
// rgb[] : R,G,Bの順番
void hsv2rgb(double hsv[3], int rgb[3]) {
 double H = hsv[0];
 double S = hsv[1];
 double V = hsv[2];

 if(H>=360.0) H-=360.0;
 if(H<0.0) H+=360.0;

 S = max(0.0, min(S, 1.0));
 V = max(0.0, min(V, 1.0));
 int h = ((int)floor(H/60.0));
 double f = H/60.0 - (double)h;

 if(!(h&1)) f=1-f;

 double p = V*(1.0-S);
 double q = V*(1.0-f*S);
 double r=0.0, g=0.0, b=0.0;

 // switch文でもOK
 if(h==0)   { r=V; g=q; b=p; }
 else if(h==1)  { r=q; g=V; b=p; }
 else if(h==2)  { r=p; g=V; b=q; }
 else if(h==3)  { r=p; g=q; b=V; }
 else if(h==4)  { r=q; g=p; b=V; }
 else if(h==5)  { r=V; g=p; b=q; }
 rgb[0] = (int)(r*255);
 rgb[1] = (int)(g*255);
 rgb[2] = (int)(b*255);
}

YCbCr表色系

JPEGの圧縮時にこの表色系を使用する.
CbとCrのチャンネルは少し削って(間引き)劣化させても,人間の目は劣化したと認識されにくいため,圧縮時に利用.
Y値はグレースケール値として使用することが多い.(安定かつ手軽で良い)
似たものに,YUV表色系やYPbPr表色系があり,厳密な切り分けがない模様.
SDTVではYCbCr表色系,HDTVではYPbPr表色系を使っているようだ.(YPbPr表色系は後述)
Cb値とCr値は負数もとるため,ディスプレイ表示させたいときは128のオフセット値を足しておく.

// ------------------------------------------------
// rgb2ycbcr
// rgb[] : R,G,Bの順番に値が格納されている
// ycbcr[] : Y,Cb,Crの順番に値が格納される
void rgb2ycbcr(int rgb[3], double ycbcr[3], double offset = 128.0) {
 ycbcr[0] = 0.299 * rgb[0] + 0.587 * rgb[1] + 0.114 * rgb[2];
 ycbcr[1] =-0.169 * rgb[0] - 0.332 * rgb[1] + 0.500 * rgb[2] + offset;
 ycbcr[2] = 0.500 * rgb[0] - 0.419 * rgb[1] - 0.081 * rgb[2] + offset;
}

// ------------------------------------------------
// ycbcr2rgb
// ycbcr[] : Y,Cb,Crの順番
// rgb[] : R,G,Bの順番
void ycbcr2rgb(double ycbcr[3], int rgb[3], double offset = 128.0) {
 double cb = ycbcr[1] - 128.0;
 double cr = ycbcr[2] - 128.0;
 int r = (int)(ycbcr[0]              + 1.402 * cr);
 int g = (int)(ycbcr[0] - 0.344 * cb - 0.714 * cr);
 int b = (int)(ycbcr[0] + 1.772 * cb);
 rgb[0] = max(0, min(r, 255));
 rgb[1] = max(0, min(g, 255));
 rgb[2] = max(0, min(b, 255));
}

YPbPr表色系

こちらはHDTV向け.
変換方法はYCbCr表色系と同じで係数が違うだけ.

// ------------------------------------------------
// rgb2ypbpr
// rgb[] : R,G,Bの順番に値が格納されている
// ypbpr[] : Y,Pb,Prの順番に値が格納される
void rgb2ypbpr(int rgb[3], double ypbpr[3], double offset = 128.0) {
 ypbpr[0] = 0.213 * rgb[0] + 0.715 * rgb[1] + 0.072 * rgb[2];
 ypbpr[1] =-0.115 * rgb[0] - 0.385 * rgb[1] + 0.500 * rgb[2] + offset;
 ypbpr[2] = 0.500 * rgb[0] - 0.454 * rgb[1] - 0.046 * rgb[2] + offset;
}

// ------------------------------------------------
// ypbpr2rgb
// ypbpr[] : Y,Pb,Prの順番
// rgb[] : R,G,Bの順番
void ypbpr2rgb(double ypbpr[3], int rgb[3], double offset = 128.0) {
 double pb = ypbpr[1] - 128.0;
 double pr = ypbpr[2] - 128.0;
 int r = (int)(ypbpr[0]              + 1.579 * pr);
 int g = (int)(ypbpr[0] - 0.187 * pb - 0.468 * pr);
 int b = (int)(ypbpr[0] + 1.856 * pb);
 rgb[0] = max(0, min(r, 255));
 rgb[1] = max(0, min(g, 255));
 rgb[2] = max(0, min(b, 255));
}

その他の表色系

XYZ表色系やLa*b*表色系などもある.

終わりに

以前良く使っていたRGBとHSV,輝度値Yなどの変換式を記載しました.
XYZ表色系やLa*b*表色系はそのうち…

6
5
1

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
5