유사성 / 차이 성을 위해 두 가지 색상을 비교하는 방법


171

가변 색상과 더 유사한 5 가지 사전 정의 된 색상과 비율을 평가할 수있는 프로그램을 설계하려고합니다. 문제는 단계별로 수동으로 수행하는 방법을 모른다는 것입니다. 따라서 프로그램을 생각하기가 훨씬 더 어렵습니다.

세부 사항 : 색상은 젤이있는 튜브 사진에서 다른 색상으로 나타납니다. 각기 다른 색상의 5 개의 튜브가 있으며 각 레벨은 5 개 중 1 개입니다. 다른 샘플의 사진을 찍고 컴퓨터에서 색상을 비교하여 해당 샘플이 어느 수준에 속하는지 평가하고 근사 비율을 알고 싶습니다. http://www.colortools.net/color_matcher.html 과 같은 프로그램을 원합니다 .

내가 생각하고 수동으로해야 할 일이더라도 어떤 조치를 취해야하는지 알려주세요. 매우 도움이 될 것입니다.


1
나는 텍스트를 약간 변경하여 포르투갈어 단어를 올바른 영어와 동등한 것으로 바 꾸었습니다 ... 오류가 발생하면 다시 변경하십시오.
Beska

13
색상 차이에 대한 wikipedia 기사가 있습니다. en.wikipedia.org/wiki/Color_difference
Ocaso Protal

4
이것은 흥미 있어야한다 : stevehanov.ca/blog/index.php?id=116 그것은 세 가지 다른 색상 모델의 차이를 계산 탐구한다.
Vlad

@OcasoProtal 님, 공유해 주셔서 감사합니다. 그리고 OP, 흥미로운 질문에.
인식

잠재적 인 사진 변이를 최소화하려고 노력하십시오 ... 자세한 내용은 아래를 참조하십시오.
Beska

답변:


130

올바른 리드에 대해서는 색상 차이 에 관한 Wikipedia의 기사를 참조하십시오 . 기본적으로 일부 다차원 색 공간에서 거리 메트릭을 계산하려고합니다. 그러나 RGB는 "지각 적으로 균일"하지 않으므로 Vadim에서 제안한 유클리드 RGB 거리 측정법은 사람이 인식 한 색상 간 거리와 일치하지 않습니다. 시작을 위해, L a b *는 지각 적으로 균일 한 색 공간이되도록 의도되고, deltaE 메트릭이 일반적으로 사용된다. 그러나 사람의 인식과 일치하는 더 세련된 색상 공간과 더 세련된 deltaE 공식이 있습니다.

변환을 수행하기 위해 색 공간과 광원에 대해 더 배워야합니다. 그러나 유클리드 RGB 메트릭보다 나은 빠른 공식의 경우 다음과 같이하십시오. RGB 값이 sRGB 색상 공간에 있다고 가정하고 sRGB를 L a b * 변환 공식 을 찾은 다음 sRGB 색상을 L a b * 로 변환하십시오 . 두 L a b * 값 사이의 deltaE를 계산 합니다. 계산 비용이 많이 들지 않고 비선형 수식과 곱셈과 덧셈입니다.


11
"deltaE"의 경우 +1이며, 이는 가장 표준화 된 비교 방법이며 다른 사용 사례에 대한 deltaE 공식의 적용이 있습니다.
Martin Hennings

9
당신은 여기에 변환 공식을 찾을 수 있습니다 brucelindbloom.com/index.html?Equations.html
기예르모 구티에레스

4
또는 Ruby에서 작업하는 경우 다른 색상 작업 중에서 deltaE 를 구현 하는 colorgem 을 확인하십시오 .
Mike Jarema

다음은 Javascript에서 위의 구현에 대한 요지입니다. gist.github.com/ryancat/9972419b2a78f329ce3aebb7f1a09152
Ryan.C

46

처음으로 내 생각에 온 아이디어 (어리 석다면 미안합니다). 색상의 3 가지 구성 요소를 점의 3D 좌표로 가정 한 다음 점 사이의 거리를 계산할 수 있습니다.

FE

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)

28
RGB 색상 공간을 사용하는 경우 두 색상의 차이는 사람 이 차이를 인식 하는 방법 과 다릅니다. 그러나 그렇습니다. 기본 아이디어는 모든 곳에서 동일합니다. 우리는 다른 색 공간으로 매핑해야합니다.
Voo

6
@Voo : HSV / HSL / LAB가 거리 기반 유사성 매칭에서 (s) RGB보다 훨씬 더 나은 색 공간 일 것입니다.
Jon Purdy

4
이것은 두 가지 색이 얼마나 다른지를 알려주는 좋은 방법이지만, 어떻게 다른 색이 인식되는지는 잘 알지 못합니다. 인간의 눈은 완벽하지 않습니다. 우리는 빨강이나 파랑보다 녹색에 더 민감합니다. 우리의 밝기 인식은 대수적입니다. OP는 결코 원하는 것을 지정하지 않았습니다. 그러나 인간의 시력에 맞게 특별히 설계된 알고리즘 은 여기참조하십시오 .
BlueRaja-대니 Pflughoeft

+ 나의 첫 아이디어이기도합니다.
ST3 2016.

9
여기서 또 다른 문제는 255, 0, 0은 0, 255, 0과 0, 0, 255와 같은 거리입니다.

27

실제로 나는 두 달 전에 같은 길을 걸었습니다. 이 질문에 대한 완벽한 대답은 없지만 ( 여기 에 몇 번이나 묻었습니다) sqrt (rr) 등의 대답보다 더 정교하고 모든 종류의 대체 색상 공간으로 이동하지 않고 RGB로 직접 영향을 받기가 더 쉽습니다. 나는이 공식을 발견 여기에 꽤 복잡 실제의 저렴한 비용으로 근사 (이 완성되지 탐구이기 때문에, 나이가 간단 색상 차이 방정식이를 찾을 수 있습니다, 색상의 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));
}

이 방법은 저에게 효과적이었습니다. 색상 이름 목록에서 가장 가까운 색상을 찾는 데 도움이되었습니다.
faisalbhagat

23

색상 값은 하나 이상의 차원을 가지므로 두 색상을 비교하는 본질적인 방법은 없습니다. 유스 케이스에 대해 색상의 의미와이를 가장 잘 비교하는 방법을 결정해야합니다.

빨강 / 녹색 / 파랑 구성 요소와 반대로 색상의 색조, 채도 및 / 또는 명도 속성을 비교하려고합니다. 어떻게 비교하고 싶은지 알아내는 데 어려움이 있다면 몇 가지 샘플 색상 쌍을 가져 와서 정신적으로 비교 한 다음 왜 비슷한 지 / 다른지 자신을 정당화하거나 설명하십시오.

비교하려는 색상의 속성 / 구성 요소를 알고 나면 색상에서 해당 정보를 추출하는 방법을 찾아야합니다.

대부분의 경우 일반적인 RedGreenBlue 표현에서 HueSaturationLightness로 색상을 변환 한 다음 다음과 같은 것을 계산하면됩니다.

avghue = (color1.hue + color2.hue)/2
distance = abs(color1.hue-avghue)

이 예제는 색상의 그라디언트 / 색조가 얼마나 멀리 떨어져 있는지를 나타내는 간단한 스칼라 값을 제공합니다.

Wikipedia의 HSL 및 HSV를 참조하십시오 .


2
이러한 것들에 대한 강의에서 기억하는 것들에서 이미지를 HSV / HSL이 아닌 Lab 색상 공간으로 변환 할 것입니다. 그 중 하나를 고른 이유가 있습니까?
Voo

아니. RGB와 HSL이 가장 익숙한 것이므로 "기본"RGB가 유일한 옵션이 아니라는 사실을 강조하기 위해 HSL을 선택했습니다. 실제로 응용 프로그램에 따라 다릅니다. Lab 색상 공간에 대해 알려 주셔서 감사합니다.
Supr

1
어쨌든 나는 당신에게 +1을주었습니다. 왜냐하면 기본 원리는 "올바른"답입니다 (인식 된 차이를 균일하게 처리하는 색상 공간으로 변환 한 다음 비교를 수행하십시오). 어떤 공간이 가장 좋은지 잘 모르겠습니다.이 모든 다른 색상 공간은 hell imo와 혼동됩니다.)
Voo

21

두 개의 Color객체 가있는 경우 c1c2각 RGB 값을의 RGB 값 c1과 비교할 수 있습니다 c2.

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)으로 나눌 수 있으며 두 값의 차이를 얻게됩니다.

float pctDiffRed   = (float)diffRed   / 255;
float pctDiffGreen = (float)diffGreen / 255;
float pctDiffBlue   = (float)diffBlue  / 255;

그 후에는 평균 색상 차이를 백분율로 찾을 수 있습니다.

(pctDiffRed + pctDiffGreen + pctDiffBlue) / 3 * 100

c1와 사이의 비율 차이를 줄 수 있습니다 c2.


2 가지 사소한 것들 : <b> 1 </ b> pctDiffRed = diffRed / 255;은 어딘가에 뜨지 않는 한 0을 줄 것입니다. <b> 2 </ b> 백분율을 얻으려면 어딘가에 100을 곱해야합니다.
vaughandroid

18
사람의 눈은 색 변화를 다르게 인식하기 때문에 이것은 "가시적 인"최상의 차이를 나타내지 않을 수 있습니다. 즉, 나는 이것이 그녀가 찾고있는 것이라고 추측하고 있습니다. 왜냐하면 그녀는 아마도 인식 된 차이가 아니라 동등하게 계량 가능한 차이를 찾고 있기 때문입니다. 여기에 관련이있을 경우 고려해야 할 것으로 생각했습니다.
Beska

14

인간의 인식으로 두 가지 색상을 비교하는 가장 좋은 방법 중 하나는 CIE76입니다. 차이점을 델타 -E라고합니다. 1보다 작 으면 육안으로 차이를 인식 할 수 없습니다.

CIE76 비교 방법을 포함하는 멋진 색상 유틸리티 클래스 ColorUtils (아래 코드)가 있습니다. 그것은 취리히 대학 Daniel Strebel에 의해 작성되었습니다.

ColorUtils.class에서 나는 방법을 사용합니다 :

static double colorDifference(int r1, int g1, int b1, int r2, int g2, int b2)

r1, g1, b1-첫 번째 색상의 RGB 값

r2, g2, b2-비교하려는 두 번째 색상의 RGB 값

Android로 작업하면 다음과 같은 값을 얻을 수 있습니다.

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);


ColorUtils.class by Daniel Strebel, 취리히 대학교 :

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));
}
}

위의 코드는 rgb2lab에 오류가 있습니다. r, g 및 b 변환에서 12로 나누기는 12.92로 나누어야합니다. 그렇지 않으면 기능은 r = 0.04045에서 연속적이지 않습니다
John Smith

10

다른 답변이지만 Supr의 것과 비슷하지만 다른 색상 공간입니다.

문제는 인간이 색의 차이를 균일하게 인식하지 못하고 RGB 색 공간이이를 무시한다는 것입니다. 결과적으로 RGB 색상 공간을 사용하고 두 색상 사이의 유클리드 거리를 계산하면 수학적으로는 정확한 차이가 있지만 인간이 말한 것과 일치하지 않는 차이가 발생할 수 있습니다.

이것은 문제가되지 않을 수도 있습니다. 차이점은 그렇게 큰 것이 아니라고 생각하지만,이 "더 나은"문제를 해결하려면 RGB 색상을 위의 문제를 피하기 위해 특별히 설계된 색상 공간으로 변환해야합니다. 이전 모델의 개선 사항이 몇 가지 있습니다 (이는 인간의 인식에 기초하기 때문에 실험 데이터를 기반으로 "올바른"값을 측정해야 함). 있다 실험실 색 공간 내가 조금로 변환 복잡하지만 가장 좋은 것 같아요. CIE XYZ 가 더 간단합니다 .

여기에 다른 색 공간 사이를 변환하는 공식을 나열하여 약간의 실험을 할 수 있는 사이트가 있습니다.


3

아래의 모든 방법은 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;
    }
}

2

가장 좋은 방법은 델타 E입니다. DeltaE는 색상의 차이를 나타내는 숫자입니다. deltae <1 인 경우 차이는 사람의 눈으로 인식 할 수 없습니다. rgb를 lab으로 변환 한 다음 델타 e를 계산하기 위해 캔버스와 js에 코드를 작성했습니다. 이 예제에서 코드는 LAB1으로 저장 한 기본 색상과 다른 색상의 픽셀을 인식합니다. 다른 경우 픽셀이 빨간색이됩니다. 증분으로 색차의 감도를 높이거나 낮추고 허용 가능한 델타 e 범위를 줄일 수 있습니다. 이 예에서는 필자가 작성한 줄에 deltaE에 10을 할당했습니다 (델타 <= 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>

1
정수 부분이 약간 걱정됩니다. 1/3그리고 16/116둘 다로 평가합니다 0. 거의 확실하지 않습니다. 아마도 알고리즘은 정확하지만 코드는 확실하지 않습니다.
다우드 이븐 카림

CIE-LAB dE94를 설명하고 있습니다. 델타 E는 유클리드의 변화를 의미합니다. 즉, 표준 실험실 색상 공간에서 매우 표준적인 유클리드 거리 공식으로 주어진 유클리드 거리입니다. 델타 E의 수정, 즉 76, 94, 2000 (직물 등에 사용되는 델타 E, CMC도 있음)은 랩 색 공간 내의 위치들 사이의 다른 거리 공식이다. 랩 코드는 각각 동일하지만 색상 차이 코드는 다릅니다. . 간단히 말해, 델타 E는 그렇게 불리는 것이 아닙니다.
Tatarize

2

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)

나는 이것을 잠시 동안 사용해 왔으며 대부분의 목적을 위해 충분히 잘 작동합니다.


상기 화학식 사용 거리 값의 범위는 무엇
아만 가르 왈

이것은 유클리드 색상 차이 근사치에 매우 가깝습니다. 계산 속도를 높이기 위해 루트 구성 요소를 건너 뛰고 있다고 추측하므로 0에서 100 ^ 3 사이의 범위입니다. 100으로 정규화하려면 동력의 거리를 두십시오1/3
Daniel

2

내 안드로이드에서 이것을 사용했으며 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";

충분히 잘 작동합니다.


2

LAB 색 공간, HSV 비교와 같은 다양한 방법을 시도했지만 광도가이 목적에 매우 효과적이라는 것을 알았습니다.

여기 파이썬 버전이 있습니다

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

기원은 ImageColor무엇입니까? 내가 찾은 편집from PIL import ImageColor
ademar111190

광도가 색상의 밝기가 아닙니까? 따라서이 경우 녹색, 파란색 및 빨간색은 밝기가 동일하다면 다른 것으로보고되지 않습니까?
Peter B.

1

마지막에 전체 이미지를 분석하고 싶습니까? 따라서 식별 색상 매트릭스와의 최소 / 최고 차이를 확인할 수 있습니다.

그래픽 처리를위한 대부분의 수학 연산은 행렬을 사용합니다. 그래픽을 사용하는 가능한 알고리즘은 종종 포인트 단위 거리 및 비교 계산보다 고전적입니다. (예 : DirectX, OpenGL 등을 사용하는 작업의 경우)

그래서 여기서 시작해야한다고 생각합니다.

http://en.wikipedia.org/wiki/Identity_matrix

http://en.wikipedia.org/wiki/Matrix_difference_equation

... Beska가 이미 위에서 언급했듯이 :

이것은 가장 "가시적 인"차이를 제공하지 않을 수 있습니다 ...

이는 이미지를 처리하는 경우 알고리즘이 "유사"정의에 의존한다는 것을 의미합니다.


1

얼마나 많은 비율을 일치시키고 싶은 Kotlin 버전.

퍼센트 선택적 인수를 사용한 메소드 호출

isMatchingColor(intColor1, intColor2, 95) // should match color if 95% similar

분석법 본문

private fun isMatchingColor(intColor1: Int, intColor2: Int, percent: Int = 90): Boolean {
    val threadSold = 255 - (255 / 100f * percent)

    val diffAlpha = abs(Color.alpha(intColor1) - Color.alpha(intColor2))
    val diffRed = abs(Color.red(intColor1) - Color.red(intColor2))
    val diffGreen = abs(Color.green(intColor1) - Color.green(intColor2))
    val diffBlue = abs(Color.blue(intColor1) - Color.blue(intColor2))

    if (diffAlpha > threadSold) {
        return false
    }

    if (diffRed > threadSold) {
        return false
    }

    if (diffGreen > threadSold) {
        return false
    }

    if (diffBlue > threadSold) {
        return false
    }

    return true
}

0

사람이 보는 방식으로 색상을 비교하려면 RGB 색상을 Lab 색상 공간으로 변환해야합니다. 그렇지 않으면 매우 이상한 방식으로 '일치하는'RGB 색상이 표시됩니다.

색상 차이 에 대한 위키 백과 링크 는 수년에 걸쳐 정의 된 다양한 Lab 색상 공간 차이 알고리즘에 대한 소개를 제공합니다. 두 가지 실험실 색상의 유클리드 거리를 확인하는 가장 간단한 방법은 작동하지만 몇 가지 결함이 있습니다.

OpenIMAJ 프로젝트 에는보다 정교한 CIEDE2000 알고리즘의 Java 구현이 편리 합니다. 두 세트의 Lab 색상을 제공하면 단일 거리 값을 다시 얻을 수 있습니다.


0

색상을 비교하는 유일한 "올바른"방법은 CIELab 또는 CIELuv에서 deltaE를 사용하는 것입니다.

그러나 많은 응용 프로그램의 경우 이것이 충분하다고 생각합니다.

distance = 3 * |dR| + 4 * |dG| + 3 * |dB|

가중 맨해튼 거리는 색상을 비교할 때 훨씬 더 의미가 있다고 생각합니다. 색상 기본은 우리 머리에만 있다는 것을 기억하십시오. 그들은 물리적으로 중요하지 않습니다. CIELab과 CIELuv는 색상에 대한 우리의 인식으로 통계적으로 모델링되었습니다.


0

빠르고 더러운 경우에는 할 수 있습니다

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);
}

정수 나누기를 사용하여 색상을 양자화합니다.


0

스위프트 5 답변

이 질문의 Swift 버전이 필요했기 때문에이 스레드를 찾았습니다. 아무도 해결책에 대해 대답하지 않았으므로 여기에 내 것이 있습니다.

extension UIColor {

    var rgba: (red: CGFloat, green: CGFloat, blue: CGFloat, alpha: CGFloat) {
        var red: CGFloat = 0
        var green: CGFloat = 0
        var blue: CGFloat = 0
        var alpha: CGFloat = 0
        getRed(&red, green: &green, blue: &blue, alpha: &alpha)

        return (red, green, blue, alpha)
    }

    func isSimilar(to colorB: UIColor) -> Bool {
        let rgbA = self.rgba
        let rgbB = colorB.rgba

        let diffRed = abs(CGFloat(rgbA.red) - CGFloat(rgbB.red))
        let diffGreen = abs(rgbA.green - rgbB.green)
        let diffBlue = abs(rgbA.blue - rgbB.blue)

        let pctRed = diffRed
        let pctGreen = diffGreen
        let pctBlue = diffBlue

        let pct = (pctRed + pctGreen + pctBlue) / 3 * 100

        return pct < 10 ? true : false
    }
}

용법:

let black: UIColor = UIColor.black
let white: UIColor = UIColor.white

let similar: Bool = black.isSimilar(to: white)

비슷한 색상을 반환하기 위해 10 % 미만의 차이를 설정했지만 직접 사용자 지정할 수 있습니다.


0

안드로이드 ColorUtils API RGBToHSL을 위해 : 나는이 개 있었다 INT ARGB 색상 (색 1, COLOR2를) 나는 두 색상 사이의 거리 / 차이를 얻고 싶었다. 여기 내가 한 일이 있습니다.

private float getHue(int color) {
    int R = (color >> 16) & 0xff;
    int G = (color >>  8) & 0xff;
    int B = (color      ) & 0xff;
    float[] colorHue = new float[3];
    ColorUtils.RGBToHSL(R, G, B, colorHue);
    return colorHue[0];
}

그런 다음 아래 코드를 사용하여 두 색상 사이의 거리를 찾았습니다.

private float getDistance(getHue(color1), getHue(color2)) {
    float avgHue = (hue1 + hue2)/2;
    return Math.abs(hue1 - avgHue);
}
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.