デジタル画像処理 - Lab、YCbCr、HSV、RGB間の相互変換

研究室

「Lab」画像形式は、通常、Lab 色空間としても知られる CIELAB 色空間を指します。これは人間の視覚の色を記述するために使用されるデバイスに依存しない色空間であり、一般的な RGB および CMYK 色空間とは異なります。CIELAB は、人間の目の色の認識をより正確に表すために、1976 年に国際照明委員会 (CIE) によって定義されました。
CIELAB には、L (輝度)、a (緑から赤の色成分)、b (青から黄の色成分) の 3 つのチャネルが含まれています。この色空間の主な利点は、人間の目が色を認識する方法をシミュレートしようとしており、Lab 空間で近い色は視覚的にもより似ていることです。これにより、Lab 色空間は、画像処理、色補正、カラー マッチングなどの多くの色関連アプリケーションで役立ちます。
ただし、Lab 画像形式自体は JPEG、PNG、GIF などの一般的な画像ファイル形式ではないことに注意することが重要です。対照的に、Lab 色空間は、色補正、色調整、その他の色関連操作を支援するために、画像処理の中間色空間としてよく使用されます。コンピューター上で Lab 色空間を表すには、通常、L、a、b チャネルの値が浮動小数点数を使用して表されます。
ここに画像の説明を挿入

YCbCr

YCbCr は、デジタル画像およびビデオのコーディングに使用される色空間であり、RGB 色空間とは異なります。YCbCr は、人間の目では異なるように知覚される色と明るさの情報を分離する特性があり、視覚的な品質を維持しながらデータ送信量を削減できるため、画像やビデオの圧縮、送信、デジタル メディア処理でよく使用されます。
YCbCr は 3 つのコンポーネントで構成されます。
Y (明るさ): 画像の明るさのコンポーネントを示します。この成分は、人間の目による画像の明るさの知覚に対応します。
Cb および Cr (色差): これら 2 つのコンポーネントは、色情報のクロミナンスまたは色差コンポーネントを表します。Cb は青と明るさの差を表し、Cr は赤と明るさの差を表します。この分離により、色情報を輝度情報から分離できるため、視覚に大きな影響を与えることなく圧縮が可能になります。
YCbCr は、JPEG 画像圧縮、ビデオ コーディング (MPEG や H.264 など)、デジタル テレビ放送などのデジタル メディア テクノロジで広く使用されています。多くの画像およびビデオ形式は、データの保存に YCbCr 色空間を使用します。YCbCr 色空間を使用すると、画質を維持しながら保存および送信されるデータ量が削減されるためです。これらのフォーマットでは、画像の色情報は Cb および Cr チャネルにマッピングされますが、輝度情報は Y チャネルに保持されます。
ここに画像の説明を挿入

HSV

これは人間の視覚システムが色を認識する方法に基づいており、RGB および CMYK 色空間とは異なります。HSV は色相、彩度、明度の略で、色のさまざまな側面を直感的に記述する方法を提供します。
HSV 色空間の 3 つのコンポーネントは次のとおりです。

  1. 色相: 色相は色の基本的な特性を表します。つまり、赤、緑、青など、私たちがよく言う色の名前です。色相の値の範囲は通常 0 ~ 360
    度で、カラー サークル全体をさまざまな色に分割します。
  2. 彩度: 彩度は、色の純度または鮮やかさを示します。彩度が低い色は暗くなったり色褪せたりしますが、彩度が高い色はより鮮やかになります。彩度の値の範囲は通常、0% (グレー) から 100% (完全に飽和) までです。
  3. 明るさ (値): 明るさは、色がどの程度明るいか暗いかを示します。輝度値が高いほど明るい色を示し、低い値は暗い色を示します。通常、明るさの範囲は 0% (黒) から 100% (白) です。
    HSV 色空間は、色の外観をより直感的に制御できるため、画像処理やコンピュータ グラフィックスでよく使用されます。RGB 色空間と比較すると、HSV は、色間の複雑な相互作用を考慮せずに色の彩度と明度を調整するのに適しています。
    ここに画像の説明を挿入

コード

まず、これらの色空間のデータ構造を定義しますが、画像の読み書きを容易にするために、ここではOpenCVを使用して画像を読み込み、読み込み後にBGRをRGBに変換します。

#pragma once
#include <iostream>
#include <algorithm>
#include <opencv2/opencv.hpp>
struct Lab
{
    
    
	float L;
	float a;
	float b;
};

struct YCbCr
{
    
    
    float Y;
    float Cb;
    float Cr;
};

struct HSV
{
    
    
	int h;
	double s;
	double v;
};

struct BGR
{
    
    
	float b;
	float g;
	float r;
};

実装コード

void BGR_YCbCr(BGR &bgr, YCbCr& y)
{
    
    
    y.Y = 0.257 * bgr.r + 0.564 * bgr.g + 0.098 * bgr.b + 16;
    y.Cb = -0.148 * bgr.r - 0.291 * bgr.g + 0.439 * bgr.b + 128;
    y.Cr = 0.439 * bgr.r - 0.368 * bgr.g - 0.071 * bgr.b + 128;
}

void BGR_Lab(BGR &bgr, Lab& lab)
{
    
    
    double X, Y, Z;
    double Fx = 0, Fy = 0, Fz = 0;
    double b = bgr.b / 255.00;
    double g = bgr.g / 255.00;
    double r = bgr.r / 255.00;


    // gamma 2.2
    if (r > 0.04045)
        r = pow((r + 0.055) / 1.055, 2.4);
    else
        r = r / 12.92;
    if (g > 0.04045)
        g = pow((g + 0.055) / 1.055, 2.4);
    else
        g = g / 12.92;
    if (b > 0.04045)
        b = pow((b + 0.055) / 1.055, 2.4);
    else
        b = b / 12.92;
    // sRGB
    X = r * 0.436052025 + g * 0.385081593 + b * 0.143087414;
    Y = r * 0.222491598 + g * 0.716886060 + b * 0.060621486;
    Z = r * 0.013929122 + g * 0.097097002 + b * 0.714185470;
    // XYZ range: 0~100
    X = X * 100.000;
    Y = Y * 100.000;
    Z = Z * 100.000;
    // Reference White Point
    //2度视场 D50光源三刺激值
    double ref_X = 96.4221;
    double ref_Y = 100.000;
    double ref_Z = 82.5211;


    X = X / ref_X;
    Y = Y / ref_Y;
    Z = Z / ref_Z;


    // Lab
    if (X > 0.008856)
        Fx = pow(X, 1 / 3.000);
    else
        Fx = (7.787 * X) + (16 / 116.000);
    if (Z > 0.008856)
        Fz = pow(Z, 1 / 3.000);
    else
        Fz = (7.787 * Z) + (16 / 116.000);
    if (Y > 0.008856)
    {
    
    
        Fy = pow(Y, 1 / 3.000);
        lab.L = (116.000 * Fy) - 16.0 + 0.5;
    }
    else
    {
    
    
        Fy = (7.787 * Y) + (16 / 116.000);
        lab.L = 903.3 * Y;
    }

    lab.a = 500.000 * (Fx - Fy) + 0.5;
    lab.b = 200.000 * (Fy - Fz) + 0.5;
}

bool IsEquals(double val1, double val2)
{
    
    
	return fabs(val1 - val2) < 0.001;
}

void BGR_HSV(BGR& bgr, HSV& hsv)
{
    
    
	double b, g, r;
	double h, s, v;
	double min, max;
	double delta;

	b = bgr.b / 255.0;
	g = bgr.g / 255.0;
	r = bgr.r / 255.0;

	if (r > g)
	{
    
    
		max = std::max(r, b);
		min = std::min(g, b);
	}
	else
	{
    
    
		max = std::max(g, b);
		min = std::min(r, b);
	}

	v = max;
	delta = max - min;

	if (IsEquals(max, 0))
		s = 0.0;
	else
		s = delta / max;

	if (max == min)
		h = 0.0;
	else
	{
    
    
		if (IsEquals(r, max) && g >= b)
		{
    
    
			h = 60 * (g - b) / delta + 0;
		}
		else if (IsEquals(r, max) && g < b)
		{
    
    
			h = 60 * (g - b) / delta + 360;
		}
		else if (IsEquals(g, max))
		{
    
    
			h = 60 * (b - r) / delta + 120;
		}
		else if (IsEquals(b, max))
		{
    
    
			h = 60 * (r - g) / delta + 240;
		}
	}

	hsv.h = (int)(h + 0.5);
	hsv.h = (hsv.h > 359) ? (hsv.h - 360) : hsv.h;
	hsv.h = (hsv.h < 0) ? (hsv.h + 360) : hsv.h;
	hsv.s = s;
	hsv.v = v;
}

BGR BGR_value(cv::Mat& cv_src)
{
    
    
    cv::Scalar s = cv::mean(cv_src);
    BGR bgr;
    bgr.b = s[0];
    bgr.g = s[1];
    bgr.r = s[2];

    return bgr;
}

おすすめ

転載: blog.csdn.net/matt45m/article/details/132423065