2つの色を比較して、どれだけ似ているかを調べる方法を見つけようとしています。このテーマに関するリソースが見つからないようですので、ここでいくつかの指針を得たいと思っています。
理想的には、それらがどれだけ似ているかを示すスコアを取得したいと思います。たとえば、0から100の場合、100は等しく、0は完全に異なります。
ありがとう!
編集:
答えから色についてもう少し知ることは、私の質問が少し曖昧であったことを理解しています。私はこれが何のために必要だったかを説明しようとします。
アプリケーションウィンドウのピクセルデータ(場所と色)が800x600サイズであるため、すべてのx間隔をチェックすることで、特定のウィンドウが開いているかどうかを確認できます。
ただし、このメソッドは、アプリケーションのサイズが変更されるとすぐに失敗します(コンテンツは拡大縮小され、移動されません)。ピクセルが移動する場所を計算できますが、丸めとアンチエイリアシングのため、色がわずかに異なる場合があります。
この場合、Pieterのソリューションは私にとって十分でしたが、他のすべての応答も非常に役に立ちました。そのため、私は全員に賛成しました。 ColorEyeの答えは、これを専門的な方法で見ると最も正確だと思うので、私はそれを答えとしてマークしました。
あなたが探しているものはDelta-E
と呼ばれています。
http://www.colorwiki.com/wiki/Delta_E:_The_Color_Difference
これは、LAB色空間における2つの色の間の距離です。人間の目は1DeltaE未満の色を区別できないと言われています(私の目は1 DeltaE未満の色の違いを見つけることができ、人によって異なります)。
「色差」には4つの式があります。
このサイトの数学のリンクを確認してください。
したがって、適切な答えは、指定された式を使用してRGBをLABに変換し、DeltaE1976を使用して色の「違い」を判断することです。結果が0の場合、同じ色を示します。 0より大きい値は、「1以下のデルタeはほとんどの人にとって区別がつかない」というルールによって判断できます。
これを簡単に実行できるオープンソースの.netライブラリがあります: https://github.com/THEjoezack/ColorMine
色を比較するための最も一般的な方法は CIE76 :です。
var a = new Rgb { R = 149, G = 13, B = 12 }
var b = new Rgb { R = 255, G = 13, B = 12 }
var deltaE = a.Compare(b,new Cie1976Comparison());
色には、人間の目に影響を与えるさまざまな重みがあります。したがって、計算された重みを使用して、色をグレースケールに変換します。
灰色= .11 * B + .59 * G + .30 * R
そして、あなたの違いは(GrayColor1-GrayColor2)* 100.0 /256.0になります
これは実際に一般的に使用されており、画像処理で画像の違いを計算するために使用される非常に単純なアプローチです。
-編集これは非常にシンプルでありながら使用可能な式です-商用アプリケーションでも。深く掘り下げたい場合は、CIE1976、CIE1994、CIE2000、CMCと呼ばれる色差の方法を確認する必要があります。ここでいくつかの詳細情報を見つけることができます: http://en.wikipedia.org/wiki/Color_difference
RGBカラーをHSLカラースペースに変換すると、多くの場合、良好な結果が得られます。変換式についてはウィキペディアを確認してください。 H、色、S、色の「深さ」、L、明るさの違いに重みを割り当てるのはあなた次第です。
このようなもの:
public static int CompareColors(Color a, Color b)
{
return 100 * (int)(
1.0 - ((double)(
Math.Abs(a.R - b.R) +
Math.Abs(a.G - b.G) +
Math.Abs(a.B - b.B)
) / (256.0 * 3))
);
}
色覚は多くの要因に依存し、類似性はさまざまな方法で測定できます。 R、G、Bコンポーネントが一般的にどれほど類似しているかを比較するだけで、人間が同意しない結果が得られます。
いくつかの ウィキペディアの色比較に関する一般的な資料 、および この質問 のC#で 自然な色空間 を操作する方法があります。
I foundカラーメトリックと呼ばれる興味深いアプローチをC#に適合させました
public static double ColourDistance(Color e1, Color e2)
{
long rmean = ((long)e1.R + (long)e2.R) / 2;
long r = (long)e1.R - (long)e2.R;
long g = (long)e1.G - (long)e2.G;
long b = (long)e1.B - (long)e2.B;
return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8));
}
BruceLindbloomのページにあるDeltaE2000のコードをCに翻訳しました。
ここに:
//
// deltae2000.c
//
// Translated by Dr Cube on 10/1/16.
// Translated to C from this javascript code written by Bruce LindBloom:
// http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html
// http://www.brucelindbloom.com/javascript/ColorDiff.js
#include <stdio.h>
#include <math.h>
#define Lab2k struct Lab2kStruct
Lab2k
{
float L;
float a;
float b;
};
// function expects Lab where: 0 >= L <=100.0 , -100 >=a <= 100.0 and -100 >= b <= 100.0
float
DeltaE2000(Lab2k Lab1,Lab2k Lab2)
{
float kL = 1.0;
float kC = 1.0;
float kH = 1.0;
float lBarPrime = 0.5 * (Lab1.L + Lab2.L);
float c1 = sqrtf(Lab1.a * Lab1.a + Lab1.b * Lab1.b);
float c2 = sqrtf(Lab2.a * Lab2.a + Lab2.b * Lab2.b);
float cBar = 0.5 * (c1 + c2);
float cBar7 = cBar * cBar * cBar * cBar * cBar * cBar * cBar;
float g = 0.5 * (1.0 - sqrtf(cBar7 / (cBar7 + 6103515625.0))); /* 6103515625 = 25^7 */
float a1Prime = Lab1.a * (1.0 + g);
float a2Prime = Lab2.a * (1.0 + g);
float c1Prime = sqrtf(a1Prime * a1Prime + Lab1.b * Lab1.b);
float c2Prime = sqrtf(a2Prime * a2Prime + Lab2.b * Lab2.b);
float cBarPrime = 0.5 * (c1Prime + c2Prime);
float h1Prime = (atan2f(Lab1.b, a1Prime) * 180.0) / M_PI;
float dhPrime; // not initialized on purpose
if (h1Prime < 0.0)
h1Prime += 360.0;
float h2Prime = (atan2f(Lab2.b, a2Prime) * 180.0) / M_PI;
if (h2Prime < 0.0)
h2Prime += 360.0;
float hBarPrime = (fabsf(h1Prime - h2Prime) > 180.0) ? (0.5 * (h1Prime + h2Prime + 360.0)) : (0.5 * (h1Prime + h2Prime));
float t = 1.0 -
0.17 * cosf(M_PI * ( hBarPrime - 30.0) / 180.0) +
0.24 * cosf(M_PI * (2.0 * hBarPrime ) / 180.0) +
0.32 * cosf(M_PI * (3.0 * hBarPrime + 6.0) / 180.0) -
0.20 * cosf(M_PI * (4.0 * hBarPrime - 63.0) / 180.0);
if (fabsf(h2Prime - h1Prime) <= 180.0)
dhPrime = h2Prime - h1Prime;
else
dhPrime = (h2Prime <= h1Prime) ? (h2Prime - h1Prime + 360.0) : (h2Prime - h1Prime - 360.0);
float dLPrime = Lab2.L - Lab1.L;
float dCPrime = c2Prime - c1Prime;
float dHPrime = 2.0 * sqrtf(c1Prime * c2Prime) * sinf(M_PI * (0.5 * dhPrime) / 180.0);
float sL = 1.0 + ((0.015 * (lBarPrime - 50.0) * (lBarPrime - 50.0)) / sqrtf(20.0 + (lBarPrime - 50.0) * (lBarPrime - 50.0)));
float sC = 1.0 + 0.045 * cBarPrime;
float sH = 1.0 + 0.015 * cBarPrime * t;
float dTheta = 30.0 * expf(-((hBarPrime - 275.0) / 25.0) * ((hBarPrime - 275.0) / 25.0));
float cBarPrime7 = cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime;
float rC = sqrtf(cBarPrime7 / (cBarPrime7 + 6103515625.0));
float rT = -2.0 * rC * sinf(M_PI * (2.0 * dTheta) / 180.0);
return(sqrtf(
(dLPrime / (kL * sL)) * (dLPrime / (kL * sL)) +
(dCPrime / (kC * sC)) * (dCPrime / (kC * sC)) +
(dHPrime / (kH * sH)) * (dHPrime / (kH * sH)) +
(dCPrime / (kC * sC)) * (dHPrime / (kH * sH)) * rT
)
);
}