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

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

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

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



답변

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

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


답변

처음으로 내 생각에 온 아이디어 (어리 석다면 미안합니다). 색상의 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)


답변

실제로 나는 두 달 전에 같은 길을 걸었습니다. 이 질문에 대한 완벽한 대답은 없지만 ( 여기 에 몇 번이나 묻었습니다) 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));
}


답변

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

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

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

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

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

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

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


답변

두 개의 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.


답변

인간의 인식으로 두 가지 색상을 비교하는 가장 좋은 방법 중 하나는 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));
}
}


답변

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

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

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

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