5つの定義済みの色のうち、可変の色に似ている色とその割合を評価するのに役立つプログラムを設計したいと思います。問題は、手動で段階的に行う方法がわからないことです。そのため、プログラムを考えることはさらに困難です。
詳細:色は、異なる色のゲルを含むチューブの写真からのものです。異なる色の5つのチューブがあり、それぞれが5つのレベルの1つを表しています。私は他のサンプルの写真を撮り、コンピューターで色を比較することでそのサンプルがどのレベルに属しているかを評価したいと思います。次のようなことをするプログラムが欲しい: http://www.colortools.net/color_matcher.html
手動で考えて実行することであっても、実行する手順を教えていただけますか。とても助かります。
正しいリードについては、ウィキペディアの 色差 に関する記事を参照してください。基本的に、いくつかの多次元色空間で距離メトリックを計算します。しかし、RGBは「知覚的に均一」ではないため、Vadimが提案するユークリッドRGB距離メトリックは、人間が知覚する色間の距離と一致しません。まず、Lab *は知覚的に均一な色空間にすることを目的としており、deltaEメトリックが一般的に使用されます。しかし、より洗練された色空間とより洗練されたdeltaEフォーミュラがあり、人間の知覚に一致するようになります。
変換を行うには、色空間と光源についてさらに学習する必要があります。しかし、ユークリッドRGBメトリックよりも優れた簡単な数式を作成するには、次のようにします。RGB値がsRGBカラースペースにあると仮定し、sRGBからLab *変換を見つけます数式、sRGBカラーをLab *に変換し、2つのLab *値間のdeltaEを計算します。計算コストは高くありませんが、いくつかの非線形公式と乗算および加算にすぎません。
最初に頭に浮かんだのはアイデアだけです(愚かだったらごめんなさい)。色の3つのコンポーネントをポイントの3D座標と見なすことができ、ポイント間の距離を計算できます。
F.E.
Point1 has R1 G1 B1
Point2 has R2 G2 B2
色間の距離は
d=sqrt((r2-r1)^2+(g2-g1)^2+(b2-b1)^2)
割合は
p=d/sqrt((255)^2+(255)^2+(255)^2)
カラー値には複数のディメンションがあるため、2つのカラーを比較する固有の方法はありません。ユースケースでは、色の意味を判断する必要があり、それによって色を最もよく比較する方法を決定する必要があります。
ほとんどの場合、赤/緑/青の成分とは反対の色の色相、彩度、明度のプロパティを比較する必要があります。どのように比較したいのかわからない場合は、サンプルの色のペアをいくつか取り、それらを精神的に比較し、それらが似ている/異なる理由を正当化/説明しようとします。
比較したい色のプロパティ/コンポーネントがわかったら、色からその情報を抽出する方法を理解する必要があります。
ほとんどの場合、色を一般的なRedGreenBlue表現からHueSaturationLightnessに変換し、次のように計算する必要があります。
avghue = (color1.hue + color2.hue)/2
distance = abs(color1.hue-avghue)
この例では、色のグラデーション/色相がどれだけ離れているかを示す単純なスカラー値を取得します。
WikipediaのHSLおよびHSV を参照してください。
2つのColor
オブジェクトc1
およびc2
がある場合、c1
の各RGB値をc2
のRGB値と比較するだけで済みます。
int diffRed = Math.abs(c1.getRed() - c2.getRed());
int diffGreen = Math.abs(c1.getGreen() - c2.getGreen());
int diffBlue = Math.abs(c1.getBlue() - c2.getBlue());
これらの値は、差の飽和の量(255)で除算することができ、2つの差が得られます。
float pctDiffRed = (float)diffRed / 255;
float pctDiffGreen = (float)diffGreen / 255;
float pctDiffBlue = (float)diffBlue / 255;
その後、パーセンテージで平均色差を見つけることができます。
(pctDiffRed + pctDiffGreen + pctDiffBlue) / 3 * 100
これにより、c1
とc2
の割合が異なります。
実際、私は数ヶ月前に同じ道を歩いた。質問に対する完璧な答えはありません(それは ここ 数回尋ねられました)が、sqrt(rr)などの答えよりも洗練されており、あらゆる種類の代替色空間。私はこの式を見つけました ここ これは非常に複雑な実際の低コストの近似です 式 (色のW3CであるCIEによる、これは完了していないクエストなので、古いシンプルな色差式を見つけることができます)。がんばろう
編集:後世のために、関連するCコードを次に示します。
typedef struct {
unsigned char r, g, b;
} RGB;
double ColourDistance(RGB e1, RGB 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 sqrt((((512+rmean)*r*r)>>8) + 4*g*g + (((767-rmean)*b*b)>>8));
}
人間の知覚で2色を比較する最良の方法の1つはCIE76です。違いはDelta-Eと呼ばれます。 1未満の場合、人間の目は違いを認識できません。
CIE76比較メソッドを含む素晴らしいカラーユーティリティクラスColorUtils(以下のコード)があります。チューリッヒ大学のダニエル・ストレーベルによって書かれています。
ColorUtils.classからメソッドを使用します:
static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)
r1、g1、b1-最初の色のRGB値
r2、g2、b2-比較したい2番目の色のRGB値
Androidを使用している場合、次のような値を取得できます。
r1 = Color.red(pixel);
g1 = Color.green(pixel);
b1 = Color.blue(pixel);
チューリッヒ大学Daniel StrebelによるColorUtils.class:
import Android.graphics.Color;
public class ColorUtil {
public static int argb(int R, int G, int B) {
return argb(Byte.MAX_VALUE, R, G, B);
}
public static int argb(int A, int R, int G, int B) {
byte[] colorByteArr = {(byte) A, (byte) R, (byte) G, (byte) B};
return byteArrToInt(colorByteArr);
}
public static int[] rgb(int argb) {
return new int[]{(argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF};
}
public static int byteArrToInt(byte[] colorByteArr) {
return (colorByteArr[0] << 24) + ((colorByteArr[1] & 0xFF) << 16)
+ ((colorByteArr[2] & 0xFF) << 8) + (colorByteArr[3] & 0xFF);
}
public static int[] rgb2lab(int R, int G, int B) {
//http://www.brucelindbloom.com
float r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
float Ls, as, bs;
float eps = 216.f / 24389.f;
float k = 24389.f / 27.f;
float Xr = 0.964221f; // reference white D50
float Yr = 1.0f;
float Zr = 0.825211f;
// RGB to XYZ
r = R / 255.f; //R 0..1
g = G / 255.f; //G 0..1
b = B / 255.f; //B 0..1
// assuming sRGB (D65)
if (r <= 0.04045)
r = r / 12;
else
r = (float) Math.pow((r + 0.055) / 1.055, 2.4);
if (g <= 0.04045)
g = g / 12;
else
g = (float) Math.pow((g + 0.055) / 1.055, 2.4);
if (b <= 0.04045)
b = b / 12;
else
b = (float) Math.pow((b + 0.055) / 1.055, 2.4);
X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;
// XYZ to Lab
xr = X / Xr;
yr = Y / Yr;
zr = Z / Zr;
if (xr > eps)
fx = (float) Math.pow(xr, 1 / 3.);
else
fx = (float) ((k * xr + 16.) / 116.);
if (yr > eps)
fy = (float) Math.pow(yr, 1 / 3.);
else
fy = (float) ((k * yr + 16.) / 116.);
if (zr > eps)
fz = (float) Math.pow(zr, 1 / 3.);
else
fz = (float) ((k * zr + 16.) / 116);
Ls = (116 * fy) - 16;
as = 500 * (fx - fy);
bs = 200 * (fy - fz);
int[] lab = new int[3];
lab[0] = (int) (2.55 * Ls + .5);
lab[1] = (int) (as + .5);
lab[2] = (int) (bs + .5);
return lab;
}
/**
* Computes the difference between two RGB colors by converting them to the L*a*b scale and
* comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
*/
public static double getColorDifference(int a, int b) {
int r1, g1, b1, r2, g2, b2;
r1 = Color.red(a);
g1 = Color.green(a);
b1 = Color.blue(a);
r2 = Color.red(b);
g2 = Color.green(b);
b2 = Color.blue(b);
int[] lab1 = rgb2lab(r1, g1, b1);
int[] lab2 = rgb2lab(r2, g2, b2);
return Math.sqrt(Math.pow(lab2[0] - lab1[0], 2) + Math.pow(lab2[1] - lab1[1], 2) + Math.pow(lab2[2] - lab1[2], 2));
}
}
ちょうど別の答えですが、それはSuprのそれに似ています-ただ異なる色空間です。
問題は、人間は色の違いを一様ではなく知覚し、RGB色空間はこれを無視しているということです。その結果、RGBカラースペースを使用し、2色間のユークリッド距離を計算するだけで、数学的に完全に正しい差が得られる場合がありますが、人間が言うこととは一致しません。
これは問題ではないかもしれません-違いはそれほど大きくないと思いますが、この「より良い」問題を解決したい場合は、RGBカラーを上記の問題を回避するために特別に設計された色空間に変換する必要があります。以前のモデルからの改善点がいくつかあります(これは人間の知覚に基づいているため、実験データに基づいて「正しい」値を測定する必要があります)。 Lab colorspace があり、これを変換するのは少し複雑ですが、最高だと思います。 CIE XYZ oneの方が簡単です。
これは、異なる色空間間で変換する式をリストするサイトです ですので、少し試してみてください。
以下のすべての方法は、0〜100のスケールになります。
internal static class ColorDifference
{
internal enum Method
{
Binary, // true or false, 0 is false
Square,
Dimensional,
CIE76
}
public static double Calculate(Method method, int argb1, int argb2)
{
int[] c1 = ColorConversion.ArgbToArray(argb1);
int[] c2 = ColorConversion.ArgbToArray(argb2);
return Calculate(method, c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
}
public static double Calculate(Method method, int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
{
switch (method)
{
case Method.Binary:
return (r1 == r2 && g1 == g2 && b1 == b2 && a1 == a2) ? 0 : 100;
case Method.CIE76:
return CalculateCIE76(r1, r2, g1, g2, b1, b2);
case Method.Dimensional:
if (a1 == -1 || a2 == -1) return Calculate3D(r1, r2, g1, g2, b1, b2);
else return Calculate4D(r1, r2, g1, g2, b1, b2, a1, a2);
case Method.Square:
return CalculateSquare(r1, r2, g1, g2, b1, b2, a1, a2);
default:
throw new InvalidOperationException();
}
}
public static double Calculate(Method method, Color c1, Color c2, bool alpha)
{
switch (method)
{
case Method.Binary:
return (c1.R == c2.R && c1.G == c2.G && c1.B == c2.B && (!alpha || c1.A == c2.A)) ? 0 : 100;
case Method.CIE76:
if (alpha) throw new InvalidOperationException();
return CalculateCIE76(c1, c2);
case Method.Dimensional:
if (alpha) return Calculate4D(c1, c2);
else return Calculate3D(c1, c2);
case Method.Square:
if (alpha) return CalculateSquareAlpha(c1, c2);
else return CalculateSquare(c1, c2);
default:
throw new InvalidOperationException();
}
}
// A simple idea, based on on a Square
public static double CalculateSquare(int argb1, int argb2)
{
int[] c1 = ColorConversion.ArgbToArray(argb1);
int[] c2 = ColorConversion.ArgbToArray(argb2);
return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
}
public static double CalculateSquare(Color c1, Color c2)
{
return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
}
public static double CalculateSquareAlpha(int argb1, int argb2)
{
int[] c1 = ColorConversion.ArgbToArray(argb1);
int[] c2 = ColorConversion.ArgbToArray(argb2);
return CalculateSquare(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
}
public static double CalculateSquareAlpha(Color c1, Color c2)
{
return CalculateSquare(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
}
public static double CalculateSquare(int r1, int r2, int g1, int g2, int b1, int b2, int a1 = -1, int a2 = -1)
{
if (a1 == -1 || a2 == -1) return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2)) / 7.65;
else return (Math.Abs(r1 - r2) + Math.Abs(g1 - g2) + Math.Abs(b1 - b2) + Math.Abs(a1 - a2)) / 10.2;
}
// from:http://stackoverflow.com/questions/9018016/how-to-compare-two-colors
public static double Calculate3D(int argb1, int argb2)
{
int[] c1 = ColorConversion.ArgbToArray(argb1);
int[] c2 = ColorConversion.ArgbToArray(argb2);
return Calculate3D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3]);
}
public static double Calculate3D(Color c1, Color c2)
{
return Calculate3D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
}
public static double Calculate3D(int r1, int r2, int g1, int g2, int b1, int b2)
{
return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2)) / 4.41672955930063709849498817084;
}
// Same as above, but made 4D to include alpha channel
public static double Calculate4D(int argb1, int argb2)
{
int[] c1 = ColorConversion.ArgbToArray(argb1);
int[] c2 = ColorConversion.ArgbToArray(argb2);
return Calculate4D(c1[1], c2[1], c1[2], c2[2], c1[3], c2[3], c1[0], c2[0]);
}
public static double Calculate4D(Color c1, Color c2)
{
return Calculate4D(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B, c1.A, c2.A);
}
public static double Calculate4D(int r1, int r2, int g1, int g2, int b1, int b2, int a1, int a2)
{
return Math.Sqrt(Math.Pow(Math.Abs(r1 - r2), 2) + Math.Pow(Math.Abs(g1 - g2), 2) + Math.Pow(Math.Abs(b1 - b2), 2) + Math.Pow(Math.Abs(a1 - a2), 2)) / 5.1;
}
/**
* Computes the difference between two RGB colors by converting them to the L*a*b scale and
* comparing them using the CIE76 algorithm { http://en.wikipedia.org/wiki/Color_difference#CIE76}
*/
public static double CalculateCIE76(int argb1, int argb2)
{
return CalculateCIE76(Color.FromArgb(argb1), Color.FromArgb(argb2));
}
public static double CalculateCIE76(Color c1, Color c2)
{
return CalculateCIE76(c1.R, c2.R, c1.G, c2.G, c1.B, c2.B);
}
public static double CalculateCIE76(int r1, int r2, int g1, int g2, int b1, int b2)
{
int[] lab1 = ColorConversion.ColorToLab(r1, g1, b1);
int[] lab2 = ColorConversion.ColorToLab(r2, g2, b2);
return Math.Sqrt(Math.Pow(lab2[0] - lab1[0], 2) + Math.Pow(lab2[1] - lab1[1], 2) + Math.Pow(lab2[2] - lab1[2], 2)) / 2.55;
}
}
internal static class ColorConversion
{
public static int[] ArgbToArray(int argb)
{
return new int[] { (argb >> 24), (argb >> 16) & 0xFF, (argb >> 8) & 0xFF, argb & 0xFF };
}
public static int[] ColorToLab(int R, int G, int B)
{
// http://www.brucelindbloom.com
double r, g, b, X, Y, Z, fx, fy, fz, xr, yr, zr;
double Ls, fas, fbs;
double eps = 216.0f / 24389.0f;
double k = 24389.0f / 27.0f;
double Xr = 0.964221f; // reference white D50
double Yr = 1.0f;
double Zr = 0.825211f;
// RGB to XYZ
r = R / 255.0f; //R 0..1
g = G / 255.0f; //G 0..1
b = B / 255.0f; //B 0..1
// assuming sRGB (D65)
if (r <= 0.04045) r = r / 12;
else r = (float)Math.Pow((r + 0.055) / 1.055, 2.4);
if (g <= 0.04045) g = g / 12;
else g = (float)Math.Pow((g + 0.055) / 1.055, 2.4);
if (b <= 0.04045) b = b / 12;
else b = (float)Math.Pow((b + 0.055) / 1.055, 2.4);
X = 0.436052025f * r + 0.385081593f * g + 0.143087414f * b;
Y = 0.222491598f * r + 0.71688606f * g + 0.060621486f * b;
Z = 0.013929122f * r + 0.097097002f * g + 0.71418547f * b;
// XYZ to Lab
xr = X / Xr;
yr = Y / Yr;
zr = Z / Zr;
if (xr > eps) fx = (float)Math.Pow(xr, 1 / 3.0);
else fx = (float)((k * xr + 16.0) / 116.0);
if (yr > eps) fy = (float)Math.Pow(yr, 1 / 3.0);
else fy = (float)((k * yr + 16.0) / 116.0);
if (zr > eps) fz = (float)Math.Pow(zr, 1 / 3.0);
else fz = (float)((k * zr + 16.0) / 116);
Ls = (116 * fy) - 16;
fas = 500 * (fx - fy);
fbs = 200 * (fy - fz);
int[] lab = new int[3];
lab[0] = (int)(2.55 * Ls + 0.5);
lab[1] = (int)(fas + 0.5);
lab[2] = (int)(fbs + 0.5);
return lab;
}
}
私はAndroidアップでこれを使用しましたが、RGBスペースは推奨されていませんが、満足できるようです:
public double colourDistance(int red1,int green1, int blue1, int red2, int green2, int blue2)
{
double rmean = ( red1 + red2 )/2;
int r = red1 - red2;
int g = green1 - green2;
int b = blue1 - blue2;
double weightR = 2 + rmean/256;
double weightG = 4.0;
double weightB = 2 + (255-rmean)/256;
return Math.sqrt(weightR*r*r + weightG*g*g + weightB*b*b);
}
次に、以下を使用して類似度の割合を取得しました。
double maxColDist = 764.8339663572415;
double d1 = colourDistance(red1,green1,blue1,red2,green2,blue2);
String s1 = (int) Math.round(((maxColDist-d1)/maxColDist)*100) + "% match";
それは十分に機能します。
最善の方法はdeltaEです。 DeltaEは、色の違いを示す数値です。 deltae <1の場合、人間の目では違いを認識できません。 rgbをlabに変換してからデルタeを計算するためのコードをcanvasとjsで作成しました。この例では、コードは、LAB1として保存した基本色と異なる色のピクセルを認識しています。そして、異なる場合、それらのピクセルを赤にします。増分で色差の感度を増減したり、デルタeの許容範囲を縮小したりできます。この例では、書いた行のdeltaEに10を割り当てました(deltae <= 10):
<script>
var constants = {
canvasWidth: 700, // In pixels.
canvasHeight: 600, // In pixels.
colorMap: new Array()
};
// -----------------------------------------------------------------------------------------------------
function fillcolormap(imageObj1) {
function rgbtoxyz(red1,green1,blue1){ // a converter for converting rgb model to xyz model
var red2 = red1/255;
var green2 = green1/255;
var blue2 = blue1/255;
if(red2>0.04045){
red2 = (red2+0.055)/1.055;
red2 = Math.pow(red2,2.4);
}
else{
red2 = red2/12.92;
}
if(green2>0.04045){
green2 = (green2+0.055)/1.055;
green2 = Math.pow(green2,2.4);
}
else{
green2 = green2/12.92;
}
if(blue2>0.04045){
blue2 = (blue2+0.055)/1.055;
blue2 = Math.pow(blue2,2.4);
}
else{
blue2 = blue2/12.92;
}
red2 = (red2*100);
green2 = (green2*100);
blue2 = (blue2*100);
var x = (red2 * 0.4124) + (green2 * 0.3576) + (blue2 * 0.1805);
var y = (red2 * 0.2126) + (green2 * 0.7152) + (blue2 * 0.0722);
var z = (red2 * 0.0193) + (green2 * 0.1192) + (blue2 * 0.9505);
var xyzresult = new Array();
xyzresult[0] = x;
xyzresult[1] = y;
xyzresult[2] = z;
return(xyzresult);
} //end of rgb_to_xyz function
function xyztolab(xyz){ //a convertor from xyz to lab model
var x = xyz[0];
var y = xyz[1];
var z = xyz[2];
var x2 = x/95.047;
var y2 = y/100;
var z2 = z/108.883;
if(x2>0.008856){
x2 = Math.pow(x2,1/3);
}
else{
x2 = (7.787*x2) + (16/116);
}
if(y2>0.008856){
y2 = Math.pow(y2,1/3);
}
else{
y2 = (7.787*y2) + (16/116);
}
if(z2>0.008856){
z2 = Math.pow(z2,1/3);
}
else{
z2 = (7.787*z2) + (16/116);
}
var l= 116*y2 - 16;
var a= 500*(x2-y2);
var b= 200*(y2-z2);
var labresult = new Array();
labresult[0] = l;
labresult[1] = a;
labresult[2] = b;
return(labresult);
}
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageX = 0;
var imageY = 0;
context.drawImage(imageObj1, imageX, imageY, 240, 140);
var imageData = context.getImageData(0, 0, 240, 140);
var data = imageData.data;
var n = data.length;
// iterate over all pixels
var m = 0;
for (var i = 0; i < n; i += 4) {
var red = data[i];
var green = data[i + 1];
var blue = data[i + 2];
var xyzcolor = new Array();
xyzcolor = rgbtoxyz(red,green,blue);
var lab = new Array();
lab = xyztolab(xyzcolor);
constants.colorMap.Push(lab); //fill up the colormap array with lab colors.
}
}
// ------------------------------------------------ -------------------------------------------------- ---
function colorize(pixqty) {
function deltae94(lab1,lab2){ //calculating Delta E 1994
var c1 = Math.sqrt((lab1[1]*lab1[1])+(lab1[2]*lab1[2]));
var c2 = Math.sqrt((lab2[1]*lab2[1])+(lab2[2]*lab2[2]));
var dc = c1-c2;
var dl = lab1[0]-lab2[0];
var da = lab1[1]-lab2[1];
var db = lab1[2]-lab2[2];
var dh = Math.sqrt((da*da)+(db*db)-(dc*dc));
var first = dl;
var second = dc/(1+(0.045*c1));
var third = dh/(1+(0.015*c1));
var deresult = Math.sqrt((first*first)+(second*second)+(third*third));
return(deresult);
} // end of deltae94 function
var lab11 = new Array("80","-4","21");
var lab12 = new Array();
var k2=0;
var canvas = document.getElementById('myCanvas');
var context = canvas.getContext('2d');
var imageData = context.getImageData(0, 0, 240, 140);
var data = imageData.data;
for (var i=0; i<pixqty; i++) {
lab12 = constants.colorMap[i];
var deltae = deltae94(lab11,lab12);
if (deltae <= 10) {
data[i*4] = 255;
data[(i*4)+1] = 0;
data[(i*4)+2] = 0;
k2++;
} // end of if
} //end of for loop
context.clearRect(0,0,240,140);
alert(k2);
context.putImageData(imageData,0,0);
}
// -----------------------------------------------------------------------------------------------------
$(window).load(function () {
var imageObj = new Image();
imageObj.onload = function() {
fillcolormap(imageObj);
}
imageObj.src = './mixcolor.png';
});
// ---------------------------------------------------------------------------------------------------
var pixno2 = 240*140;
</script>
最後に画像全体を分析したいと思いますか?したがって、アイデンティティカラーマトリックスとの最小/最大差を確認できます。
グラフィックスを処理するためのほとんどの数学演算は行列を使用します。これを使用する可能性のあるアルゴリズムは、従来の点ごとの距離および比較計算よりも高速であることが多いためです。 (例:DirectX、OpenGLなどを使用する操作の場合)
だから、ここから始めるべきだと思う:
http://en.wikipedia.org/wiki/Identity_matrix
http://en.wikipedia.org/wiki/Matrix_difference_equation
...そして、ベスカがすでに上記でコメントしたように:
これは最良の「目に見える」違いを与えないかもしれません...
これは、画像を処理する場合、アルゴリズムが「類似」の定義に依存することも意味します。
RGBのみを使用する簡単な方法は
cR=R1-R2
cG=G1-G2
cB=B1-B2
uR=R1+R2
distance=cR*cR*(2+uR/256) + cG*cG*4 + cB*cB*(2+(255-uR)/256)
私はこれをしばらく使用しましたが、ほとんどの目的には十分に機能します。
早くて汚いために、あなたはできる
import Java.awt.Color;
private Color dropPrecision(Color c,int threshold){
return new Color((c.getRed()/threshold),
(c.getGreen()/threshold),
(c.getBlue()/threshold));
}
public boolean inThreshold(Color _1,Color _2,int threshold){
return dropPrecision(_1,threshold)==dropPrecision(_2,threshold);
}
整数除算を使用して色を量子化します。
色を比較する唯一の「正しい」方法は、CIELabまたはCIELuvでdeltaEを使用して比較することです。
しかし、多くのアプリケーションにとって、これは十分な近似値だと思います。
distance = 3 * |dR| + 4 * |dG| + 3 * |dB|
色を比較するとき、重み付きのマンハッタン距離がはるかに理にかなっていると思います。色の原色は頭の中だけにあることを忘れないでください。物理的な意味はありません。 CIELabとCIELuvは、色の知覚から統計的にモデル化されています。
LABカラースペース、HSV比較などのさまざまな方法を試しましたが、この目的には輝度が非常にうまく機能することがわかりました。
これはPythonバージョンです
def lum(c):
def factor(component):
component = component / 255;
if (component <= 0.03928):
component = component / 12.92;
else:
component = math.pow(((component + 0.055) / 1.055), 2.4);
return component
components = [factor(ci) for ci in c]
return (components[0] * 0.2126 + components[1] * 0.7152 + components[2] * 0.0722) + 0.05;
def color_distance(c1, c2):
l1 = lum(c1)
l2 = lum(c2)
higher = max(l1, l2)
lower = min(l1, l2)
return (higher - lower) / higher
c1 = ImageColor.getrgb('white')
c2 = ImageColor.getrgb('yellow')
print(color_distance(c1, c2))
あげます
0.0687619047619048