A certain engineer "COMPLEX"

開発メモ その25 RGBからHSVへの変換パフォーマンス

RGBからHSVを取得する


通常、.NETで扱える色の形式はRGBです。赤、緑、青から成る光の三原色です。
基本の基本ですが、これはこれで不便なところがあります。
例えば、RGB(255,0,0)とRGB(200,0,0)では同じ赤ですが、後者のが暗いです。
では、同じような色であった場合に、どちらが暗いか、といった場合に赤、緑、青の各要素を調べることで判断できるでしょうか?
当然できません。
なぜなら、赤、緑、青の複数の色からなる色の場合、この方法ではどちらが暗いかを判断することはできないからです。

そこで、RGBを色相 (Hue)、彩度 (Saturation)、明度 (Value) の3つの成分からなる色空間に変換することで、同じような色であっても明るさを数値で比較することができます。
詳しい詳細は Wikipedia を見て、と成りますが、この変換を C# で実行してみます。

下はRGBの16777216色を全てHSVに変換し、その速度を表示するサンプルです。


using System;
using System.Diagnostics;

namespace Image2
{
class Program
{
static void Main(string[] args)
{
float h, s, v;
var sw = new Stopwatch();

sw.Start();
for (var r = 0; r <= 255; r++)
for (var g = 0; g <= 255; g++)
for (var b = 0; b <= 255; b++)
FromRgb((byte)r, (byte)g, (byte)b, out h, out s, out v);

sw.Stop();
Console.WriteLine($"{sw.ElapsedMilliseconds} ms");
}

private static void FromRgb(byte r, byte g, byte b, out float h, out float s, out float v)
{
var max = Math.Max(r, Math.Max(g, b));
var min = Math.Min(r, Math.Min(g, b));

var brightness = max / 255f;
float hue, saturation;
if (Math.Abs(max - min) < float.Epsilon)
{
hue = 0f;
saturation = 0f;
}
else
{
float c = max - min;
if (Math.Abs(max - r) < float.Epsilon)
hue = (g - b) / c;
else if (Math.Abs(max - g) < float.Epsilon)
hue = (b - r) / c + 2f;
else
hue = (r - g) / c + 4f;

hue *= 60f;
if (hue < 0f)
hue += 360f;

saturation = c / max;
}

h = hue;
s = saturation;
v = brightness;
}

}
}

32bit vs 64bit

サンプル自体は、何の変哲も無いのですが、テスト中面白いことに気づきました。
プラットフォームターゲットを x86 と x64 に変更し、ビルド実行すると性能に大きな差が発生しました。


D:\Works\Demo\Image2\Image2\bin\Release>Image2.exe
357 ms

D:\Works\Demo\Image2\Image2\bin\Release>Image2.exe
3590 ms

前者が x64、後者が x86 でビルドした結果です。
なお環境は Intel Core i7-2600 3.40GHz です。
実際には、ある程度大きなサイズの画像の、全画素を変換したとしたら、1/8くらいにはなるでしょう。
この差は非常に大きいです。今日日、32bitの環境なんて考えたくもないですが、これだけ性能に差があるなら、機材の選定を担当する人間への説得する材料としては十分でしょう。

Source Code

https://github.com/takuya-takeuchi/Demo/tree/master/Image2

コメントを残す

メールアドレスが公開されることはありません。

%d人のブロガーが「いいね」をつけました。