RGB24の1677万7216色のうち、YUVが表せる色の数は?
「RGB24の1677万7216色のうち、
8bit-depthのYUVで表せるのは、最大でも440万色程度」
この計算を行ったChikuzen氏のブログ記事に触発され、自分でもちょっと計算してみました。
まず最初にChikuzen氏の記事を読んだうえでご覧になってください。
Ch's barn: ConvertToRGB (Chikuzen氏のブログ記事)
Chikuzen氏の記事では8bit-depthの計算を行っていたので、
こちらではそれに加えて9bit-depthと10bit-depthについても計算をしてみました。
ただし、正直なところ、こんな計算でいいのか不安です。
記事の最後にソースコードも示していますので、間違ってるとこがあればご指摘ください。
プログラミングも初心者レベルです。
さて、まずは計算結果から。
8bit-Rec601: 2955936 8bit-Pc.601: 4262360 8bit-Rec709: 3046424 8bit-PC.709: 4400226 9bit-Rec601: 15831400 9bit-Pc.601: 16713229 9bit-Rec709: 16149193 9bit-PC.709: 16777216 10bit-Rec601: 16777216 10bit-PC.601: 16777216 10bit-Rec709: 16777216 10bit-PC.709: 16777216
■8bit-depthについては、おおまかな数値はChikuzenさんの計算結果と一致しています。
フルレンジでも最大440万色。実際にはTVレンジで扱うことが多いので実質300万色前後というところですね。
■9bit-depthについては、RGB24の全ての色を表現しうるのはPC.709だけという結果となりました。
とはいえ、Rec601でも1583万色を表現できますので実用上はほぼ問題ないレベルでしょうか。
■10bit-depthについては、どのパターンでもRGB24の全ての色を表現できるという結果となりました。
計算に使ったソースコードを以下に示します。表示に「SyntaxHighlighter 3.0」を使っています。
下の「expand source」の部分をクリックするとソースコードが展開表示されます。
ソース部分をダブルクリックすると全選択され、コピーできます。
/* yuvcolor_calc.cpp */
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
#define CLIP_Y(Y) Y = (Y < 0) ? 0.0 : (Y > 1.0) ? 1.0 : Y
#define CLIP_C(C) C = (C < -0.5) ? -0.5 : (C > 0.5) ? 0.5 : C
#define SATURATE(X) X = (X < 0) ? 0 : (X > 255) ? 255 : X
/* RGB24の色数(256*256*256色) */
#define RGB_TABLE_SIZE 16777216
/* H.264のRound()がこんな感じなので */
int myRound(double x)
{
return (x >= 0) ? (int)floor(x + 0.5) : (int)(-floor(abs(x) + 0.5));
}
int main(void)
{
const struct {
char *name; // 色空間の名称
int bitDepth; // ビット深度
int y_min; // 輝度Yの最小値
int y_max; // 輝度Yの最大値
int uv_min; // 色差の最小値
int uv_max; // 色差の最大値
double r_cr; // YUV→RGB変換の係数1
double g_cb; // YUV→RGB変換の係数2
double g_cr; // YUV→RGB変換の係数3
double b_cb; // YUV→RGB変換の係数4
} matrix[] = {
{" 8bit-Rec601", 8, 16, 235, 16, 240, 1.402 , -0.344 , -0.714 , 1.772 },
{" 8bit-Pc.601", 8, 0, 255, 0, 255, 1.402 , -0.344 , -0.714 , 1.772 },
{" 8bit-Rec709", 8, 16, 235, 16, 240, 1.5748, -0.1873, -0.4681, 1.8556},
{" 8bit-PC.709", 8, 0, 255, 0, 255, 1.5748, -0.1873, -0.4681, 1.8556},
{" 9bit-Rec601", 9, 32, 470, 32, 480, 1.402 , -0.344 , -0.714 , 1.772 },
{" 9bit-Pc.601", 9, 0, 511, 0, 511, 1.402 , -0.344 , -0.714 , 1.772 },
{" 9bit-Rec709", 9, 32, 470, 32, 480, 1.5748, -0.1873, -0.4681, 1.8556},
{" 9bit-PC.709", 9, 0, 511, 0, 511, 1.5748, -0.1873, -0.4681, 1.8556},
{"10bit-Rec601", 10, 64, 940, 64, 960, 1.402 , -0.344 , -0.714 , 1.772 },
{"10bit-Pc.601", 10, 0, 1023, 0, 1023, 1.402 , -0.344 , -0.714 , 1.772 },
{"10bit-Rec709", 10, 64, 940, 64, 960, 1.5748, -0.1873, -0.4681, 1.8556},
{"10bit-PC.709", 10, 0, 1023, 0, 1023, 1.5748, -0.1873, -0.4681, 1.8556},
{NULL}
};
bool *rgbTable = (bool *)malloc(RGB_TABLE_SIZE*sizeof(bool));
if(!rgbTable){
fprintf(stderr,"malloc(rgbTable) failed\n");
return -1;
}
double Y_a=0,Cb_a=0,Cr_a=0;
int r=0,g=0,b=0;
int i=0,count=0,num=0;
int rgbNumber;
for(int m=0; m<=11; m++){
printf("%s: ", matrix[m].name);
// rgbTableをクリア(falseにする)
for(i=0;i < RGB_TABLE_SIZE;i++){
rgbTable[i]=false;
}
count=0;
for (int Y = matrix[m].y_min; Y <= matrix[m].y_max; Y++){
for (int Cb = matrix[m].uv_min; Cb <= matrix[m].uv_max; Cb++){
for (int Cr = matrix[m].uv_min; Cr <= matrix[m].uv_max; Cr++) {
// まずはデジタルYCbCr→アナログYCbCr変換
// (Y_a:0.0~1.0、Cb_a,Cr_a:-0.5~0.5)
// "アナログYCbCr"という表現はよろしくないけどスルーの方向で。
// bitDepthをnとすると、H.264で定義されてる量子化式はだいたいこんな感じなので、
// ここから逆算してY_a、Cb_a、Cr_aを求める。
// ●TVレンジ
// Y = ( 1 << (n-8) ) * (219 * Y_a + 16)
// Cb = ( 1 << (n-8) ) * (224 * Cb_a + 128)
// Cr = ( 1 << (n-8) ) * (224 * Cr_a + 128)
// ●フルレンジ
// Y = ( (1 << n) - 1) * Y_a
// Cb = ( (1 << n) - 1) * Cb_a + ( 1 << (n-1) )
// Cr = ( (1 << n) - 1) * Cr_a + ( 1 << (n-1) )
// minとmaxを用意しとけばTVレンジでもフルレンジでも
// 1つの式でいけるので、そのように変形してみた。
Y_a = (Y - matrix[m].y_min) / (double)(matrix[m].y_max - matrix[m].y_min);
Cb_a = (Cb - ( 1 << (matrix[m].bitDepth - 1) ) ) / (double)(matrix[m].uv_max - matrix[m].uv_min);
Cr_a = (Cr - ( 1 << (matrix[m].bitDepth - 1) ) ) / (double)(matrix[m].uv_max - matrix[m].uv_min);
CLIP_Y(Y_a);
CLIP_C(Cb_a);
CLIP_C(Cr_a);
// 続いてアナログYCbCr→デジタルRGB変換
// 基本的には、まるも氏の
// http://www.marumo.ne.jp/db2002_5.htm#15
// の記事を参照。
// ただしこの記事は2002年のものであり、
// BT.709の係数はBT.709-1のものになっている。
// H.264ではBT.709-2以降の係数が使われているので、
// ここではBT.709-2の係数で計算している。
// YUV→RGBのアナログ変換式のみ載せておく。
// (R,G,B,Y:0.0~1.0、U,V:-0.5~0.5)
// ●BT.601
// R = Y + 1.402 × V
// G = Y - 0.344 × U - 0.714 × V
// B = Y + 1.772 × U
// ●BT.709-2
// R = Y + 1.5748 × V
// G = Y - 0.1873 × U - 0.4681 × V
// B = Y + 1.8556 × U
r = myRound(255.0 * (Y_a + matrix[m].r_cr * Cr_a));
g = myRound(255.0 * (Y_a + matrix[m].g_cb * Cb_a + matrix[m].g_cr * Cr_a));
b = myRound(255.0 * (Y_a + matrix[m].b_cb * Cb_a ));
SATURATE(r);
SATURATE(g);
SATURATE(b);
// 再現できた色はtrueにする
rgbNumber = ((r << 16) | (g << 8) | b);
rgbTable[rgbNumber] = true;
}
}
}
// trueになっている色の数をカウントして出力
num = 0;
for (i = 0; i < RGB_TABLE_SIZE; i++){
if (rgbTable[i]){
num++;
}
}
printf("%d\n", num);
}
free(rgbTable);
return 0;
}
| 固定リンク
| コメント (0)
| トラックバック (0)




最近のコメント