समानता / अंतर के लिए दो रंगों की तुलना कैसे करें


171

मैं एक कार्यक्रम डिजाइन करना चाहता हूं जो मुझे 5 पूर्व-परिभाषित रंगों के बीच का आकलन करने में मदद कर सकता है जो एक चर रंग के समान है, और कितने प्रतिशत के साथ। बात यह है कि मैं नहीं जानता कि कैसे मैन्युअल रूप से कदम से कदम है। इसलिए एक कार्यक्रम के बारे में सोचना और भी मुश्किल है।

अधिक विवरण: रंग जेल के साथ ट्यूबों की तस्वीरों से होते हैं जो विभिन्न रंगों के रूप में होते हैं। मेरे पास अलग-अलग रंगों के साथ 5 ट्यूब हैं प्रत्येक प्रत्येक 5 स्तरों में से 1 का प्रतिनिधि है। मैं अन्य नमूनों की तस्वीरें लेना चाहता हूं और कंप्यूटर पर यह आकलन करता हूं कि रंगों की तुलना करके नमूना किस स्तर का है, और मैं यह जानना चाहता हूं कि एक प्रतिशत भी अनुमानित है। मुझे ऐसा प्रोग्राम चाहिए जो कुछ इस तरह से हो: http://www.colortools.net/color_matcher.html

यदि आप मुझे बता सकते हैं कि क्या कदम उठाना है, भले ही वे मेरे लिए सोचने और मैन्युअल रूप से करने की चीजें हों। यह बहुत मददगार होगा।


1
मैंने पाठ में एक मामूली बदलाव किया, एक पुर्तगाली शब्द को जो मुझे लगता है कि सही अंग्रेजी समकक्ष है ... को बदल दिया, अगर मैं मिटाता हूं तो इसे वापस बदल दें।
बेसका

13
रंग अंतर के बारे में विकिपीडिया लेख है: en.wikipedia.org/wiki/Color_difference
Ocaso Protal

4
यह दिलचस्प होना चाहिए: stevehanov.ca/blog/index.php?id=116 यह तीन अलग-अलग रंग मॉडल में अंतर की गणना करता है।
व्लाद

अरे @ ओकासोप्रोटल, यह साझा करने के लिए एक महान लिंक धन्यवाद है। और ओपी के लिए, दिलचस्प सवाल।
परसेप्शन

किसी भी संभावित फोटोग्राफिक विविधता को कम से कम करने की कोशिश करें ... नीचे दिए गए उत्तर में अधिक विवरण।
बैस्का

जवाबों:


130

सही अंतर के लिए रंग अंतर पर विकिपीडिया का लेख देखें । मूल रूप से, आप कुछ बहुआयामी कलरस्पेस में एक दूरी मीट्रिक की गणना करना चाहते हैं। लेकिन RGB "अवधारणात्मक रूप से समान" नहीं है, इसलिए वादिम द्वारा सुझाई गई आपकी यूक्लिडियन RGB दूरी मीट्रिक रंगों के बीच मानव-कथित दूरी से मेल नहीं खाएगी। एक शुरुआत के लिए, एल एक बी * का उद्देश्य एक समान रूप से एक समान रंग स्थान होना है, और डेल्टा मेट्रिक का आमतौर पर उपयोग किया जाता है। लेकिन अधिक परिष्कृत रंग स्थान और अधिक परिष्कृत डेल्टा फार्मूले हैं जो मानव धारणा से मेल खाते हैं।

रूपांतरण करने के लिए आपको कलरस्पेस और रोशनी के बारे में अधिक सीखना होगा। लेकिन एक त्वरित सूत्र कि इयूक्लिडियन आरजीबी मीट्रिक से बेहतर है के लिए, बस ऐसा करते हैं: मान लेते हैं कि अपने आरजीबी मूल्यों sRGB कलरस्पेस में हैं, एल sRGB लगता है एक , ख * रूपांतरण सूत्र एल करने के लिए अपने sRGB रंग परिवर्तित एक ख *, और अपने दो एल एक बी * मूल्यों के बीच डेल्टा गणना करें । यह कम्प्यूटेशनल रूप से महंगा नहीं है, यह सिर्फ कुछ nonlinear सूत्र और कुछ गुणन और जोड़ता है।


11
"डेल्टा" के लिए +1, वह सबसे मानकीकृत तुलना पद्धति है और विभिन्न उपयोग के मामलों के लिए डेल्टा सूत्र के अनुकूलन हैं।
मार्टिन हेनिंग्स

9
: आप यहाँ रूपांतरण सूत्र पा सकते हैं brucelindbloom.com/index.html?Equations.html
गिलर्मो Gutiérrez

4
या, यदि आप रूबी में काम कर रहे हैं, तो उस colorरत्न की जांच करें जो अन्य रंग संचालन में डेल्टा को लागू करता है
माइक जेरेमा

यहाँ जावास्क्रिप्ट gist.github.com/ryancat/9972419b2a78f329ce3aebb7f1a09152
उपरोक्त

46

बस एक विचार जो पहले मेरे दिमाग में आया था (क्षमा करें यदि मूर्ख)। रंगों के तीन घटकों को अंकों के 3 डी निर्देशांक माना जा सकता है और फिर आप अंकों के बीच की दूरी की गणना कर सकते हैं।

एफई

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 रंगों का उपयोग कर रहे हैं, तो 2 रंगों के बीच का अंतर वैसा नहीं है, जैसा कि मनुष्यों को हालांकि अंतर का अनुभव है। लेकिन हाँ मूल विचार हर जगह एक जैसा है - हमें बस इसे दूसरे रंग के स्थान पर मैप करना होगा (लैब मैं
सोचूंगा

6
@Voo: मैं मानता हूं, एचएसवी / एचएसएल / एलएबी (एस) आरजीबी से दूरी-आधारित समानता मिलान की तुलना में बेहतर रंग स्थान होगा।
जॉन पूर्डी

4
यह आपको यह बताने का एक अच्छा तरीका है कि दो रंग कितने अलग हैं, लेकिन क्या आपको यह बताने का घटिया काम है कि वे कितने अलग होंगे। मानव आंखें एकदम सही हैं: हम लाल या नीले रंग की तुलना में हरे रंग के प्रति अधिक संवेदनशील हैं, हमारी चमक धारणा तार्किक है, आदि। ओपी ने कभी निर्दिष्ट नहीं किया है कि वह कौन चाहता है; लेकिन एक एल्गोरिथ्म के लिए यहां देखें विशेष रूप से मानव दृष्टि के लिए।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

+ यह मेरा पहला विचार है।
ST3

9
एक अन्य समस्या यहाँ 255 है, 0, 0 0 से समान दूरी, 255, 0 यह है के रूप में 0, 0, 255

27

वास्तव में मैं एक महीने पहले उसी रास्ते से चला था। प्रश्न का कोई सटीक उत्तर नहीं है (जो कि यहां कुछ समय के लिए पूछा गया था ) लेकिन एक और अधिक परिष्कृत है तो sqrt (rr) आदि उत्तर और अधिक आसान आरजीबी के साथ सभी प्रकार के वैकल्पिक रंग स्थानों पर जाने के बिना सीधे निहित है। मुझे यह सूत्र यहां मिला जो कि काफी जटिल वास्तविक सूत्र का कम लागत का अनुमान है (CIE द्वारा जो कि रंग का W3C है, क्योंकि यह एक समाप्त खोज नहीं है, आप वहां पुराने और सरल रंग अंतर समीकरण पा सकते हैं)। सौभाग्य

संपादित करें: पोस्टीरिटी के लिए, यहां प्रासंगिक 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));
}

इस विधि ने मेरे लिए काम किया। इसने मुझे रंग नामों की सूची से निकटतम रंग खोजने में मदद की।
फैसलभगत

23

एक रंग मूल्य में एक से अधिक आयाम हैं, इसलिए दो रंगों की तुलना करने का कोई आंतरिक तरीका नहीं है। आपको अपने उपयोग के मामले में रंगों का अर्थ निर्धारित करना होगा और इस तरह उनकी तुलना सबसे अच्छी तरह से करनी होगी।

सबसे अधिक संभावना है कि आप रंगों, रंगों की संतृप्ति और / या हल्केपन गुणों की तुलना लाल / हरे / नीले घटकों के लिए करते हैं। यदि आपको यह पता लगाने में समस्या हो रही है कि आप उनकी तुलना कैसे करना चाहते हैं, तो कुछ रंगों के नमूने लें और मानसिक रूप से उनकी तुलना करें, फिर अपने आप को यह बताने का प्रयास करें कि वे समान / भिन्न क्यों हैं।

एक बार जब आप जान लेते हैं कि रंगों के कौन से गुण / घटक आप तुलना करना चाहते हैं, तो आपको यह पता लगाना होगा कि किसी रंग से उस जानकारी को कैसे निकालना है।

सबसे अधिक संभावना है कि आपको रंग को आम RedGreenBlue प्रतिनिधित्व से ह्युसेटेशन लाईटनेस में बदलने की आवश्यकता होगी, और फिर कुछ इस तरह की गणना करें

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

यह उदाहरण आपको एक सरल स्केलर मान देगा जो यह दर्शाता है कि रंगों का ढाल / ह्यू एक दूसरे से कितनी दूर है।

विकिपीडिया पर एचएसएल और एचएसवी देखें ।


2
इन चीजों के बारे में मुझे अपने व्याख्यान से याद आया सामान से मैं इमेज को लैब कलर स्पेस में बदलूंगा और एचएसवी / एचएसएल से नहीं। उस एक को लेने का कोई तर्क?
वू

नहीं। RGB और HSL वे हैं जिनसे मैं सबसे अधिक परिचित हूं, इसलिए मैंने HSL को सिर्फ इस विचार को रेखांकित करने के लिए चुना कि "डिफ़ॉल्ट" RGB एकमात्र विकल्प नहीं है - यह वास्तव में एप्लिकेशन पर निर्भर करता है। मुझे लैब रंग स्थान के बारे में बताने के लिए धन्यवाद।
सुपर

1
मैंने आपको किसी भी तरह से +1 दिया क्योंकि यहां मूल सिद्धांत "सही" उत्तर है (रंग स्थान में कनवर्ट करें जो कथित अंतर को समान रूप से संभालता है, फिर तुलना करें)। मुझे यकीन नहीं है कि कौन सा स्थान सबसे अच्छा होगा - ये सभी अलग-अलग रंग रिक्त स्थान नरक इमो के रूप में भ्रमित कर रहे हैं;)
वू

21

यदि आपके पास दो Colorऑब्जेक्ट हैं c1और c2, आप बस उसी के साथ प्रत्येक 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 से गुणा करना होगा।
वॉनथॉन्ड्रोइड

18
यह सबसे अच्छा "दृश्यमान" अंतर नहीं दे सकता है, क्योंकि मानव आंख अलग-अलग रंगों में बदलाव को मानती है। यह कहा जा रहा है, मैं यह अनुमान लगा रहा हूं कि वह वास्तव में क्या देख रहा है, क्योंकि वह शायद एक विकृत अंतर के बजाय समान रूप से मात्रात्मक अंतर की तलाश कर रहा है। बस सोचा था कि मैं इसे यहाँ से बाहर निकाल दूंगा क्योंकि यह प्रासंगिक है।
बस्का

14

मानव धारणा द्वारा दो रंगों की तुलना करने के सर्वोत्तम तरीकों में से एक CIE76 है। अंतर को डेल्टा-ई कहा जाता है। जब यह 1 से कम है, तो मानव आंख अंतर को नहीं पहचान सकती है।

अद्भुत रंग उपयोगिताओं वर्ग ColorUtils (नीचे कोड) है, जिसमें CIE76 तुलना के तरीके शामिल हैं। इसे डैनियल स्ट्रेबेल, ज्यूरिख विश्वविद्यालय द्वारा लिखा गया है।

ColorUtils.class से मैं इस विधि का उपयोग करता हूं:

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

आर 1, जी 1, बी 1 - पहले रंग के आरजीबी मूल्य

r2, g2, b2 - RGB मान दूसरा रंग है जिसकी आप तुलना करना चाहेंगे

यदि आप Android के साथ काम करते हैं, तो आप इन मूल्यों को इस तरह प्राप्त कर सकते हैं:

r1 = Color.red(pixel);

g1 = Color.green(pixel);

b1 = Color.blue(pixel);


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

ऊपर दिए गए कोड में rgb2lab में एक त्रुटि है: 12 द्वारा विभाजन को r, g और b रूपांतरण में 12.92 से विभाजन द्वारा प्रतिस्थापित किया जाना चाहिए। अन्यथा फ़ंक्शन r = 0.04045
जॉन स्मिथ

10

बस एक और जवाब है, हालांकि यह सुपर के एक के समान है - बस एक अलग रंग स्थान।

बात यह है: मनुष्य रंग में अंतर को समान रूप से अनुभव करता है और आरजीबी रंग स्थान इसे अनदेखा कर रहा है। परिणामस्वरूप यदि आप RGB रंग स्थान का उपयोग करते हैं और सिर्फ 2 रंगों के बीच यूक्लिडियन दूरी की गणना करते हैं, तो आपको एक ऐसा अंतर मिल सकता है जो गणितीय रूप से बिल्कुल सही है, लेकिन मानव आपके द्वारा बताए जाने के साथ मेल नहीं खाता।

यह एक समस्या नहीं हो सकती है - अंतर इतना बड़ा नहीं है जितना मुझे लगता है, लेकिन यदि आप इस "बेहतर" को हल करना चाहते हैं, तो आपको अपने आरजीबी रंगों को एक रंग स्थान में बदलना चाहिए जो विशेष रूप से उपरोक्त समस्या से बचने के लिए डिज़ाइन किया गया था। कई मॉडल हैं, पहले के मॉडल से सुधार (चूंकि यह मानवीय धारणा पर आधारित है इसलिए हमें प्रयोगात्मक डेटा के आधार पर "सही" मूल्यों को मापने की आवश्यकता है)। वहाँ लैब colorpace जो मुझे लगता है कि सबसे अच्छा होगा, हालांकि इसे बदलने के लिए थोड़ा जटिल। सरल 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

सबसे अच्छा तरीका डेल्टा है। DeltaE एक संख्या है जो रंगों के अंतर को दिखाती है। यदि डेल्टा <1 तो अंतर मानव आंखों से नहीं पहचाना जा सकता है। मैंने आरजीबी को प्रयोगशाला में परिवर्तित करने और फिर डेल्टा ई की गणना के लिए कैनवास और जेएस में एक कोड लिखा। इस उदाहरण पर कोड उन पिक्सल्स को पहचान रहा है जिनका बेस कलर के साथ अलग रंग है जिसे मैंने LAB1 के रूप में सहेजा है। और फिर अगर यह अलग है तो उन पिक्सेल को लाल कर देता है। आप LGE के साथ रंग अंतर की संवेदनशीलता को बढ़ा या कम कर सकते हैं या डेल्टा ई की स्वीकार्य सीमा को कम कर सकते हैं। इस उदाहरण में मैंने उस लाइन में डेल्टा के लिए 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 का वर्णन कर रहे हैं। डेल्टा ई का अर्थ यूक्लिडियन में परिवर्तन है। जिसे मानक लैब रंग स्थान में कहना है, आपके बहुत मानक यूक्लिडियन दूरी सूत्र द्वारा दी गई यूक्लिडियन दूरी। जबकि डेल्टा ई के संशोधनों, अर्थात् 76, 94, 2000 (वहाँ भी डेल्टा ई, सीएमसी है जो वस्त्रों के लिए उपयोग किया जाता है और इसी तरह) लैब कलरस्पेस के पदों के बीच अलग-अलग दूरी के सूत्र हैं। लैब के लिए कोड प्रत्येक में समान है, रंग अंतर के लिए कोड नहीं है। । संक्षेप में, डेल्टा ई, वह नहीं है जिसे कहा जाता है।
तांत्रिक करें

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
डैनियल

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

एक रंग की चमक चमक नहीं है? तो इस मामले में हरे, नीले और लाल रंग को अलग-अलग होने की सूचना नहीं दी जाएगी, क्योंकि चमक समान है?
पीटर बी।

1

मुझे उम्मीद है कि आप अंत में एक पूरी छवि का विश्लेषण करना चाहते हैं, है न? इसलिए आप पहचान रंग मैट्रिक्स में सबसे छोटे / उच्चतम अंतर के लिए जाँच कर सकते हैं।

ग्राफिक्स के प्रसंस्करण के लिए अधिकांश गणित ऑपरेशन मैट्रिस का उपयोग करते हैं, क्योंकि उनका उपयोग करने वाले संभावित एल्गोरिदम अक्सर बिंदु दूरी और तुलनात्मक गणना से शास्त्रीय बिंदु से तेज होते हैं। (जैसे DirectX, OpenGL, ... का उपयोग करके संचालन के लिए)

इसलिए मुझे लगता है कि आपको यहां शुरू करना चाहिए:

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

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

... और जैसा कि बैस्का ने पहले ही ऊपर टिप्पणी की थी:

यह सबसे अच्छा "दृश्यमान" अंतर नहीं दे सकता है ...

जिसका अर्थ यह भी है कि यदि आप छवियों को संसाधित कर रहे हैं तो आपका एल्गोरिथ्म "समान" की आपकी निश्चितता पर निर्भर करता है।


1

कोटलिन संस्करण कितना प्रतिशत आप मैच करना चाहते हैं।

विधि वैकल्पिक वैकल्पिक तर्क के साथ कॉल करें

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 रंगों को लैब कलर स्पेस में बदलने की आवश्यकता होगी, ताकि वे जिस तरह से मनुष्यों को देख सकें, उनकी तुलना कर सकें। अन्यथा आपको आरजीबी रंग मिलेंगे जो कुछ बहुत ही अजीब तरीकों से 'मैच' करते हैं।

कलर डिफरेंसेस पर विकिपीडिया लिंक आपको विभिन्न लैब रंग अंतरिक्ष अंतर एल्गोरिदम में एक परिचय देता है जो वर्षों से परिभाषित किया गया है। सबसे सरल जो सिर्फ दो लैब रंगों की यूक्लिडियन दूरी की जांच करता है, काम करता है लेकिन कुछ खामियां हैं।

आसानी से OpenIMAJ परियोजना में अधिक परिष्कृत CIEDE2000 एल्गोरिथ्म का जावा कार्यान्वयन है । इसे लैब रंगों के अपने दो सेट प्रदान करें और यह आपको सिंगल दूरी का मान वापस दिलाएगा।


0

रंगों की तुलना करने का एकमात्र "सही" तरीका यह है कि सीटेल या CIELuv में डेल्टा के साथ किया जाए।

लेकिन बहुत सारे अनुप्रयोगों के लिए मुझे लगता है कि यह एक अच्छा पर्याप्त सन्निकटन है:

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 उत्तर

मुझे यह धागा मिला क्योंकि मुझे इस प्रश्न का एक स्विफ्ट संस्करण चाहिए था। जैसा कि किसी ने समाधान के साथ उत्तर नहीं दिया है, यहां मेरा है:

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 के लिए Android: मेरे पास दो int argb रंग (color1, 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);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.