Inter-conversion of image data color spaces
画像データの色空間の相互変換 RGB,XYZ,HSV,Lab,YUV


カラー画像の特徴量抽出をする前処理として、色空間の相互変換が必要になるケースが多々ある。
ここでは、色空間の相互変換に必要となる変換アルゴリズムと、C99を用いた実装を行う。

補足としてXYZ色空間の説明を加える。

XYZ色空間(CIE 1931 XYZ)は、色を表現するために広く用いられている色空間で、CIE(国際照明委員会)
によって定義されました。この色空間は、以下の特徴があります:

特徴

  1. 基準色空間:

    • XYZは、色の測定を標準化するための
      基準色空間です。他の色空間(例えば、RGB、CMYK、Labなど)の基盤となる色空間として使用されます。
  2. 三次元空間:

    • XYZ色空間は、三つの成分(X、Y、Z)で色を表現します。これらは、色の三つの基準的な値であり、
      特定の色を表現するための基準を提供します。
  3. 色の感覚的な特徴:

    • X、Y、Zの値は、人間の色の感覚に基づいて設計されており、広範な色範囲をカバーします。
      特にY成分は、輝度(明るさ)を表すことが多いです。
  4. 標準観測者:

    • XYZ色空間は、標準の光源(例えば、D65)と標準の観測者(10度視野)に基づいています。
      これにより、異なる条件での色の一致が期待できます。

XYZからLabへの変換

Lab色空間はXYZ色空間に基づいており、色の見え方をより直感的に表現するために使用されます。
Lab空間では、L(明度)、a(赤から緑)、b(青から黄)という三つの成分で色を表します。




USER

RGB、HSV、Lab、相互変換アルゴリズムを詳しく説明してください。

AI

もちろんです。RGB、HSV、Lab、XYZ色空間の間での変換アルゴリズムについて詳しく説明します。

1. RGBからHSV

RGBからHSVへの変換は、色の相対的な関係を明確にするために使用されます。以下のアルゴリズムで行います。

  1. 計算する変数:

    • max_val:RGBの最大値
    • min_val:RGBの最小値
    • deltamax_val - min_val
  2. 明度 (Value, V):

    • V = max_val
  3. 彩度 (Saturation, S):

    • S = (max_val == 0) ? 0 : (delta / max_val)
  4. 色相 (Hue, H):

    • delta == 0 の場合は H = 0
    • r == max_val の場合、H = (g - b) / delta
    • g == max_val の場合、H = 2 + (b - r) / delta
    • b == max_val の場合、H = 4 + (r - g) / delta
    • H を度に変換し、負の値は360を加えます。

2. HSVからRGB

HSVからRGBへの変換は、色相、彩度、明度を基にRGB値を計算します。

  1. 計算する変数:

    • i = floor(H / 60)
    • f = (H / 60) - i
    • p = V * (1 - S)
    • q = V * (1 - S * f)
    • t = V * (1 - S * (1 - f))
  2. RGB値の計算:

    • i の値によって以下のケースで分ける:
      • i == 0 : R = V, G = t, B = p
      • i == 1 : R = q, G = V, B = p
      • i == 2 : R = p, G = V, B = t
      • i == 3 : R = p, G = q, B = V
      • i == 4 : R = t, G = p, B = V
      • i == 5 : R = V, G = p, B = q

3. RGBからXYZ

RGBからXYZへの変換は、RGB色空間をCIE XYZ色空間に変換します。

  1. RGBのリニア化:

    • R' = (R > 0.04045) ? pow((R + 0.055) / 1.055, 2.4) : R / 12.92
    • G' = (G > 0.04045) ? pow((G + 0.055) / 1.055, 2.4) : G / 12.92
    • B' = (B > 0.04045) ? pow((B + 0.055) / 1.055, 2.4) : B / 12.92
  2. XYZ値の計算:

    • X = R' * 0.4124564 + G' * 0.3575761 + B' * 0.1804375
    • Y = R' * 0.2126729 + G' * 0.7151522 + B' * 0.0721750
    • Z = R' * 0.0193339 + G' * 0.1191920 + B' * 0.9503041

4. XYZからLab

XYZからLabへの変換は、XYZ色空間をLab色空間に変換します。

  1. XYZの正規化:

    • X' = X / REF_X
    • Y' = Y / REF_Y
    • Z' = Z / REF_Z
  2. 各値の計算:

    • f(X') = (X' > EPSILON) ? pow(X', 1.0 / 3.0) : (X' * KAPPA + 16) / 116
    • f(Y') = (Y' > EPSILON) ? pow(Y', 1.0 / 3.0) : (Y' * KAPPA + 16) / 116
    • f(Z') = (Z' > EPSILON) ? pow(Z', 1.0 / 3.0) : (Z' * KAPPA + 16) / 116
  3. Lab値の計算:

    • L = 116 * f(Y') - 16
    • a = 500 * (f(X') - f(Y'))
    • b = 200 * (f(Y') - f(Z'))

5. LabからXYZ

LabからXYZへの変換は、Lab色空間をXYZ色空間に戻します。

  1. 各値の計算:

    • Y' = (L + 16) / 116
    • X' = a / 500 + Y'
    • Z' = Y' - b / 200
  2. XYZ値の計算:

    • Y = (L > 7.9996) ? pow(Y', 3) : Y' / 903.3
    • X = (X' * X' * X' > EPSILON) ? pow(X', 3) : (X' - 16 / 116) * 903.3 / 100
    • Z = (Z' * Z' * Z' > EPSILON) ? pow(Z', 3) : (Z' - 16 / 116) * 903.3 / 100

6. XYZからRGB

XYZからRGBへの変換は、XYZ色空間をRGB色空間に戻します。

  1. RGB値の計算:

    • R = X * 3.2404542 + Y * -1.5371385 + Z * -0.4985314
    • G = X * -0.9692660 + Y * 1.8760108 + Z * 0.0415560
    • B = X * 0.0556434 + Y * -0.2040259 + Z * 1.0572252
  2. ガンマ補正:

    • R = (R > 0.0031308) ? 1.055 * pow(R, 1.0 / 2.4) - 0.055 : 12.92 * R
    • G = (G > 0.0031308) ? 1.055 * pow(G, 1.0 / 2.4) - 0.055 : 12.92 * G
    • B = (B > 0.0031308) ? 1.055 * pow(B, 1.0 / 2.4) - 0.055 : 12.92 * B

このように、各色空間間の変換は、色の相対的な値を保持しつつ、色の表現方法を異なる形式に変換するために設計されています。

USER

追加でカラー画像を濃淡画像に変換する処理を追加してください

AI

カ ラー画像を濃淡画像(グレースケール画像)に変換する処理を追加する方法について説明します。カラー画像のグレースケール変換は、一般的にRGBからの変 換として実装されます。以下は、RGBカラー画像をグレースケール画像に変換するC99のコードを含むプログラムの例です。

グレースケール変換のアルゴリズム

RGB画像をグレースケール画像に変換する際、通常は以下の方法が用いられます:

  1. 加重平均法(Luminosity Method):

    • この方法では、RGBの各成分に異なる重みを付けて加算し、輝度値(明るさ)を計算します。一般的な重みは以下の通りです:
      • Y = 0.299 * R + 0.587 * G + 0.114 * B
  2. 平均法:

    • RGBの各成分の平均を取ります。
      • Y = (R + G + B) / 3
  3. 最大値法:

    • RGBの最大値を取ります。
      • Y = max(R, G, B)

C99プログラムにおけるグレースケール変換

以下のプログラムは、RGB画像をグレースケール画像に変換するための関数を追加したものです。この例では、RGBからグレースケールへの加重平均法を使用しています。

 c 
#include <stdio.h>
#include <math.h>

// 定数
#define EPSILON 0.008856
#define KAPPA    903.3
#define REF_X     95.047
#define REF_Y    100.000
#define REF_Z    108.883

// RGBからHSVへの変換
void rgb_to_hsv(float r, float g, float b, float *h, float *s, float *v) {
    float min_val, max_val, delta;

    min_val = fminf(fminf(r, g), b);
    max_val = fmaxf(fmaxf(r, g), b);
    *v = max_val;

    delta = max_val - min_val;
    if (max_val != 0) {
        *s = delta / max_val;
    } else {
        *s = 0;
        *h = 0;
        return;
    }

    if (delta == 0) {
        *h = 0;
    } else {
        if (r == max_val) {
            *h = (g - b) / delta;
        } else if (g == max_val) {
            *h = 2 + (b - r) / delta;
        } else {
            *h = 4 + (r - g) / delta;
        }
        *h *= 60;
        if (*h < 0) *h += 360;
    }
}

// HSVからRGBへの変換
void hsv_to_rgb(float h, float s, float v, float *r, float *g, float *b) {
    int i;
    float f, p, q, t;

    if (s == 0) {
        *r = *g = *b = v;
        return;
    }

    h /= 60;
    i = (int)floor(h);
    f = h - i;
    p = v * (1 - s);
    q = v * (1 - s * f);
    t = v * (1 - s * (1 - f));

    switch (i) {
        case 0: *r = v; *g = t; *b = p; break;
        case 1: *r = q; *g = v; *b = p; break;
        case 2: *r = p; *g = v; *b = t; break;
        case 3: *r = p; *g = q; *b = v; break;
        case 4: *r = t; *g = p; *b = v; break;
        case 5: *r = v; *g = p; *b = q; break;
    }
}

// RGBからXYZへの変換
void rgb_to_xyz(float r, float g, float b, float *x, float *y, float *z) {
    r = (r > 0.04045) ? powf((r + 0.055) / 1.055, 2.4) : r / 12.92;
    g = (g > 0.04045) ? powf((g + 0.055) / 1.055, 2.4) : g / 12.92;
    b = (b > 0.04045) ? powf((b + 0.055) / 1.055, 2.4) : b / 12.92;

    r *= 100;
    g *= 100;
    b *= 100;

    *x = r * 0.4124564 + g * 0.3575761 + b * 0.1804375;
    *y = r * 0.2126729 + g * 0.7151522 + b * 0.0721750;
    *z = r * 0.0193339 + g * 0.1191920 + b * 0.9503041;
}

// XYZからLabへの変換
void xyz_to_lab(float x, float y, float z, float *l, float *a, float *b) {
    float fx, fy, fz;

    x /= REF_X;
    y /= REF_Y;
    z /= REF_Z;

    fx = (x > EPSILON) ? powf(x, 1.0 / 3.0) : (x * 903.3 + 16) / 116;
    fy = (y > EPSILON) ? powf(y, 1.0 / 3.0) : (y * 903.3 + 16) / 116;
    fz = (z > EPSILON) ? powf(z, 1.0 / 3.0) : (z * 903.3 + 16) / 116;

    *l = 116 * fy - 16;
    *a = 500 * (fx - fy);
    *b = 200 * (fy - fz);
}

// LabからXYZへの変換
void lab_to_xyz(float l, float a, float b, float *x, float *y, float *z) {
    float fy, fx, fz;

    fy = (l + 16) / 116;
    fx = a / 500 + fy;
    fz = fy - b / 200;

    *y = (l > 7.9996) ? powf((l + 16) / 116, 3) : l / 903.3;
    *x = (fx * fx * fx > EPSILON) ? powf(fx, 3) : (fx - 16 / 116) * 903.3 / 100;
    *z = (fz * fz * fz > EPSILON) ? powf(fz, 3) : (fz - 16 / 116) * 903.3 / 100;

    *x *= REF_X;
    *y *= REF_Y;
    *z *= REF_Z;
}

// XYZからRGBへの変換
void xyz_to_rgb(float x, float y, float z, float *r, float *g, float *b) {
    x /= 100;
    y /= 100;
    z /= 100;

    *r = x * 3.2404542 + y * -1.5371385 + z * -0.4985314;
    *g = x * -0.9692660 + y * 1.8760108 + z * 0.0415560;
    *b = x * 0.0556434 + y * -0.2040259 + z * 1.0572252;

    *r = (*r > 0.0031308) ? 1.055 * powf(*r, 1.0 / 2.4) - 0.055 : 12.92 * *r;
    *g = (*g > 0.0031308) ? 1.055 * powf(*g, 1.0 / 2.4) - 0.055 : 12.92 * *g;
    *b = (*b > 0.0031308) ? 1.055 * powf(*b, 1.0 / 2.4) - 0.055 : 12.92 * *b;

    *r = fminf(fmaxf(*r, 0), 1);
    *g = fminf(fmaxf(*g, 0), 1);
    *b = fminf(fmaxf(*b, 0), 1);
}

// RGBからグレースケールへの変換
void rgb_to_grayscale(float r, float g, float b, float *gray) {
    *gray = 0.299 * r + 0.587 * g + 0.114 * b;
}

int main() {
    // RGBのサンプル
    float r = 0.5, g = 0.4, b = 0.3;
    float h, s, v;
    float x, y, z;
    float l, a, b_lab;
    float gray;

    // RGBからHSV
    rgb_to_hsv(r, g, b, &h, &s, &v);
    printf("RGB(%f, %f, %f) -> HSV(%f, %f, %f)\n", r, g, b, h, s, v);

    // HSVからRGB
    hsv_to_rgb(h, s, v, &r, &g, &b);
    printf("HSV(%f, %f, %f) -> RGB(%f, %f, %f)\n", h, s, v, r, g, b);

    // RGBからXYZ
    rgb_to_xyz(r, g, b, &x, &y, &z);
    printf("RGB(%f, %f, %f) -> XYZ(%f, %f, %f)\n", r, g, b, x, y, z);

    // XYZからLab
    xyz_to_lab(x, y, z, &l, &a, &b_lab);
    printf("XYZ(%f, %f, %f) -> Lab(%f, %f, %f)\n", x, y, z, l, a, b_lab);

    // LabからXYZ
    lab_to_xyz(l, a, b_lab, &x, &y, &z);
    printf("Lab(%f, %f, %f) -> XYZ(%f, %f, %f)\n", l, a, b_lab, x, y, z);

    // XYZからRGB
    xyz_to_rgb(x, y, z, &r, &g, &b);
    printf("XYZ(%f, %f, %f) -> RGB(%f, %f, %f)\n", x, y, z, r, g, b);

    // RGBからグレースケール
    rgb_to_grayscale(r, g, b, &gray);
    printf("RGB(%f, %f, %f) -> グレースケール(%f)\n", r, g, b, gray);

    return 0;
}

説明

  1. RGBからグレースケールへの変換 (rgb_to_grayscale):

    • 変換は加重平均法を用いています。RGBの各成分に対して重みを掛け、その合計をグレースケール値として計算します。
  2. main 関数:

    • 色変換処理のサンプルとして、RGBからHSV、HSVからRGB、RGBからXYZ、XYZからLab、LabからXYZ、XYZからRGB、RGBからグレースケールへの変換を行い、結果を表示します。

このコードは、各色空間の変換を行い、最終的にカラー画像をグレースケール画像に変換する例を示しています。実際の画像処理アプリケーションでは、画像全体に対してこれらの処理を適用するために、ループを使って各ピクセルの変換を行います。


AI の回答は必ずしも正しいとは限りません。重要な情報は確認するようにしてください。


独り言:

色空間の変換だけでは、特徴量にはなりませんが、特徴量を抽出する前処理としては必要な処理です。

RGB <=> YUV の利用が多いと思たのですが、HSV、Lab からの特徴量抽出が多い様なので追加。

RGBとYUVの変換アルゴリズム

1. RGBからYUVへの変換

Y (輝度) Y=0.299R+0.587G+0.114BY=0.299⋅R+0.587⋅G+0.114⋅B
U (青色差): U=0.493(BY)U=0.493⋅(B−Y)
V (赤色差) V=0.877(RY)V=0.877⋅(R−Y)

2. YUVからRGBへの変換

R (赤): R=Y+1.140VR=Y+1.140⋅V
G (緑): G=Y0.395U0.581VG=Y−0.395⋅U−0.581⋅V
B (青) B=Y+2.032UB=Y+2.032⋅U

 C 
// RGBからYUVへの変換<
void rgb_to_yuv(float r, float g, float b, float *y, float *u, float *v) {
    *y = 0.299 * r + 0.587 * g + 0.114 * b;
    *u = 0.493 * (b - *y);
    *v = 0.877 * (r - *y);
}
// YUVからRGBへの変換
void yuv_to_rgb(float y, float u, float v, float *r, float *g, float *b) {
    *r = y + 1.140 * v;
    *g = y - 0.395 * u - 0.581 * v;
    *b = y + 2.032 * u;
}