HSV
HSVについては以下を参照。
画像処理ソリューション「色相、彩度、明度の計算方法」
http://imagingsolution.blog.fc2.com/blog-entry-247.html
この6角形を見ていてふと思いついた計算法について記載します。
本アイデア(立方体切り出し)
R,G,Bを軸とする立方体を考える。0 <= R <= 255, 0 <= G <= 255, 0 <= B <= 255 とする。
ここでR=Gの場合について考える。
R=Gの場合、以下の図の赤で囲った面上の色になる。
R+n=Gの場合は以下になる。(0 < n <= 255)
R+n=G(0 < n <= 255)
R+m=G(-255 < m < 0)
で囲うと以下のようになる。
2つのは以下のように変形できる。
R - G = n
R - G = m
つまり、上記の囲われた範囲の色は
m < R-G < n
である。
ここで以下図のように、RGBが(0,0,0)から(255,255,255)を結ぶ線上から見た視点に変えると、以下のように6角形に見える。
(0,0,0)と(255,255,255)を結んだ直線と、先ほどの
R - G = n
R - G = m
の平面は平行であるので、先ほどの2つの平面をこの図上に描くと2つの直線に見える。
m < R-G < nは以下の斜線の範囲になる。
ところで、(0,0,0)と(255,255,255)を1直線に結んだ線上から見た6角形の図というのが
HSVの六角推を上から見た彩度と色相だけの図になるらしい。
これをG-B、B-Rにも同様に適用すると
彩度と色相だけなら、以下の計算で識別できる。
min1 < R-G < max1
min2 < G-B < max2
min3 < B-R < max3
ほんとに????
計算式 HSVとの比較
変換
HSVの場合の彩度と色相算出
//とある画素ループの中
float max = Math.max(R, G, B);
float min = Math.min(R, G, B);
float H;
float S;
if (max == min) {
continue;
}
// S彩度
S = (max - min) / max;
//H色相
if (max == R)
{
H = ((60 * (G - B)) / (max-min));
}
if (max == G)
{
H = ((60 * (B - R)) / (max-min)) + 120;
}
if (max == B)
{
H = ((60 * (R - G)) / (max-min)) + 240;
}
//・・・
本手法
//とある画素ループの中
float R_G = R-G;
float G_B = G-B;
float B_R = B-R;
//・・・
色識別
以下の範囲を識別対象とする。
※これまでの図とRとBが逆になっています。直すの面倒なのでこのままにします。
HSVの場合の彩度と色相算出
//とある画素ループの中
// S彩度、H色相の判定
if((Smin < S) && (Smax > S) &&
((Hmin < H) && (Hmax > H))
{
//目的の色
}
//・・・
本手法
//とある画素ループの中
// 色の判定
if((R_Gmin < R_G) && (R_Gmax > R_G) &&
((G_Bmin < G_B) && (G_Bmax > G_B) &&
((B_Rmin < B_R) && (B_Rmax > B_R))
{
//目的の色
}
//・・・
本手法では、囲いの範囲の色を判定するので、一部上限、下限をなくすこともできる。
例えば以下のような感じ
//とある画素ループの中
// 色の判定
if((R_Gmin < R_G) && (R_Gmax > R_G) &&
/*((G_Bmin < G_B) && (G_Bmax > G_B) &&*/
((B_Rmin < B_R)/* && (B_Rmax > B_R)*/)
{
//目的の色
}
//・・・
上記本手法による判定処理で選択できる範囲のイメージは以下。
YUVからの変換
映像ではYUVの値で画像を扱っているらしい。
HSVの場合は、一度RGBに変換してからHSVへ変換する。
しかし、本手法では、直接変換できる。
参考
YUVフォーマット及び YUV<->RGB変換
https://vision.kuee.kyoto-u.ac.jp/~hiroaki/firewire/yuv.html
YUVからの変換を含んだHSVの場合の彩度と色相算出
//とある画素ループの中
float R = Y + 1.402*V;
float G = Y - 0.344*U - 0.714*V;
float B = Y + 1.772*U;
//以下は上記と同じ
float max = Math.max(R, G, B);
float min = Math.min(R, G, B);
float H;
float S;
if (max == min) {
continue;
}
// S彩度
S = (max - min) / max;
//H色相
if (max == R)
{
H = ((60 * (G - B)) / (max-min));
}
if (max == G)
{
H = ((60 * (B - R)) / (max-min)) + 120;
}
if (max == B)
{
H = ((60 * (R - G)) / (max-min)) + 240;
}
//・・・
YUVからの変換を含んだ本手法
//とある画素ループの中
//float R = Y + 1.402*V
//float G = Y - 0.344*U - 0.714*V
//float B = Y + 1.772*U
//R-G = (Y + 1.402*V) - (Y - 0.344*U - 0.714*V)
//G-B = (Y - 0.344*U - 0.714*V) - (Y + 1.772*U)
//B-R = (Y + 1.772*U) - (Y + 1.402*V)
float R_G = 0.344*U + 2.116*V;
float G_B = -1.428*U - 0.714*V;
float B_R = 1.772*U - 1.402*V;
//・・・
さらに、YUVはY0,Y1,U,V のようにYが2つある場合がある。
HSVの場合は、Y0の時とY1の時を計算しなければならないが、
本手法では、Yは計算上使わない(消える)ので計算は1度で済む。つまりYが2つある場合、HSVよりも計算する画素が半減する。
明度
「彩度と色相だけなら~」と上述したが、YUVからの変換なら、Y値をそのまま明度として使えるかも???
最後に
雑な図やコードですいません。
画像認識についてはそこまで詳しくはないのですが、ふと思いついたこのアイデアが既知か否か、または正誤についてネットで調べてみたのですが、見つかりませんでした。
素人発想なので、そもそもの考え方が間違っていて話にならないのかもしれませんが。
既知 or 間違っているなど、何かお分かりになる方ご教示お願いします。