2010-06-15 12 views
12

मैं CIE लैब colorspace में रंग अंतर की गणना करने के लिए इस समारोह बना दिया है, लेकिन यह गति का अभाव है। चूंकि मैं जावा विशेषज्ञ नहीं हूं, मुझे आश्चर्य है कि किसी भी जावा गुरु के पास कुछ युक्तियां हैं जो गति को बेहतर बना सकती हैं।मैं इस रंग अंतर फ़ंक्शन को और अनुकूलित कैसे कर सकता हूं?

कोड टिप्पणी ब्लॉक में उल्लेख किया matlab समारोह पर आधारित है।

/** 
* Compute the CIEDE2000 color-difference between the sample color with 
* CIELab coordinates 'sample' and a standard color with CIELab coordinates 
* 'std' 
* 
* Based on the article: 
* "The CIEDE2000 Color-Difference Formula: Implementation Notes, 
* Supplementary Test Data, and Mathematical Observations,", G. Sharma, 
* W. Wu, E. N. Dalal, submitted to Color Research and Application, 
* January 2004. 
* available at http://www.ece.rochester.edu/~gsharma/ciede2000/ 
*/ 
public static double deltaE2000(double[] lab1, double[] lab2) 
{ 
    double L1 = lab1[0]; 
    double a1 = lab1[1]; 
    double b1 = lab1[2]; 

    double L2 = lab2[0]; 
    double a2 = lab2[1]; 
    double b2 = lab2[2]; 

    // Cab = sqrt(a^2 + b^2) 
    double Cab1 = Math.sqrt(a1 * a1 + b1 * b1); 
    double Cab2 = Math.sqrt(a2 * a2 + b2 * b2); 

    // CabAvg = (Cab1 + Cab2)/2 
    double CabAvg = (Cab1 + Cab2)/2; 

    // G = 1 + (1 - sqrt((CabAvg^7)/(CabAvg^7 + 25^7)))/2 
    double CabAvg7 = Math.pow(CabAvg, 7); 
    double G = 1 + (1 - Math.sqrt(CabAvg7/(CabAvg7 + 6103515625.0)))/2; 

    // ap = G * a 
    double ap1 = G * a1; 
    double ap2 = G * a2; 

    // Cp = sqrt(ap^2 + b^2) 
    double Cp1 = Math.sqrt(ap1 * ap1 + b1 * b1); 
    double Cp2 = Math.sqrt(ap2 * ap2 + b2 * b2); 

    // CpProd = (Cp1 * Cp2) 
    double CpProd = Cp1 * Cp2; 

    // hp1 = atan2(b1, ap1) 
    double hp1 = Math.atan2(b1, ap1); 
    // ensure hue is between 0 and 2pi 
    if (hp1 < 0) { 
     // hp1 = hp1 + 2pi 
     hp1 += 6.283185307179586476925286766559; 
    } 

    // hp2 = atan2(b2, ap2) 
    double hp2 = Math.atan2(b2, ap2); 
    // ensure hue is between 0 and 2pi 
    if (hp2 < 0) { 
     // hp2 = hp2 + 2pi 
     hp2 += 6.283185307179586476925286766559; 
    } 

    // dL = L2 - L1 
    double dL = L2 - L1; 

    // dC = Cp2 - Cp1 
    double dC = Cp2 - Cp1; 

    // computation of hue difference 
    double dhp = 0.0; 
    // set hue difference to zero if the product of chromas is zero 
    if (CpProd != 0) { 
     // dhp = hp2 - hp1 
     dhp = hp2 - hp1; 
     if (dhp > Math.PI) { 
      // dhp = dhp - 2pi 
      dhp -= 6.283185307179586476925286766559; 
     } else if (dhp < -Math.PI) { 
      // dhp = dhp + 2pi 
      dhp += 6.283185307179586476925286766559; 
     } 
    } 

    // dH = 2 * sqrt(CpProd) * sin(dhp/2) 
    double dH = 2 * Math.sqrt(CpProd) * Math.sin(dhp/2); 

    // weighting functions 
    // Lp = (L1 + L2)/2 - 50 
    double Lp = (L1 + L2)/2 - 50; 

    // Cp = (Cp1 + Cp2)/2 
    double Cp = (Cp1 + Cp2)/2; 

    // average hue computation 
    // hp = (hp1 + hp2)/2 
    double hp = (hp1 + hp2)/2; 

    // identify positions for which abs hue diff exceeds 180 degrees 
    if (Math.abs(hp1 - hp2) > Math.PI) { 
     // hp = hp - pi 
     hp -= Math.PI; 
    } 
    // ensure hue is between 0 and 2pi 
    if (hp < 0) { 
     // hp = hp + 2pi 
     hp += 6.283185307179586476925286766559; 
    } 

    // LpSqr = Lp^2 
    double LpSqr = Lp * Lp; 

    // Sl = 1 + 0.015 * LpSqr/sqrt(20 + LpSqr) 
    double Sl = 1 + 0.015 * LpSqr/Math.sqrt(20 + LpSqr); 

    // Sc = 1 + 0.045 * Cp 
    double Sc = 1 + 0.045 * Cp; 

    // T = 1 - 0.17 * cos(hp - pi/6) + 
    //  + 0.24 * cos(2 * hp) + 
    //  + 0.32 * cos(3 * hp + pi/30) - 
    //  - 0.20 * cos(4 * hp - 63 * pi/180) 
    double hphp = hp + hp; 
    double T = 1 - 0.17 * Math.cos(hp - 0.52359877559829887307710723054658) 
      + 0.24 * Math.cos(hphp) 
      + 0.32 * Math.cos(hphp + hp + 0.10471975511965977461542144610932) 
      - 0.20 * Math.cos(hphp + hphp - 1.0995574287564276334619251841478); 

    // Sh = 1 + 0.015 * Cp * T 
    double Sh = 1 + 0.015 * Cp * T; 

    // deltaThetaRad = (pi/3) * e^-(36/(5 * pi) * hp - 11)^2 
    double powerBase = hp - 4.799655442984406; 
    double deltaThetaRad = 1.0471975511965977461542144610932 * Math.exp(-5.25249016001879 * powerBase * powerBase); 

    // Rc = 2 * sqrt((Cp^7)/(Cp^7 + 25^7)) 
    double Cp7 = Math.pow(Cp, 7); 
    double Rc = 2 * Math.sqrt(Cp7/(Cp7 + 6103515625.0)); 

    // RT = -sin(delthetarad) * Rc 
    double RT = -Math.sin(deltaThetaRad) * Rc; 

    // de00 = sqrt((dL/Sl)^2 + (dC/Sc)^2 + (dH/Sh)^2 + RT * (dC/Sc) * (dH/Sh)) 
    double dLSl = dL/Sl; 
    double dCSc = dC/Sc; 
    double dHSh = dH/Sh; 
    return Math.sqrt(dLSl * dLSl + dCSc * dCSc + dHSh * dHSh + RT * dCSc * dHSh); 
} 
+0

क्या आप वाकई सरल CIELAB अंतर के बजाय ciede2000 की आवश्यकता है? गणना करना महंगा है और आपको केवल "वैज्ञानिक रूप से" देखने योग्य अंतर देता है। अधिकांश छवि प्रसंस्करण कार्यों के लिए सरल Euclidean दूरी CIELAB रंग घटकों से दूरी पर्याप्त है। – Ross

उत्तर

12

cos महंगा है, खासकर 4 पंक्ति में। आप कंप्यूटिंग जा करने के लिए क्योंकि दिखाई (एन a + b) ख एक निरंतर है और n एक छोटे पूर्णांक है जहां। इसका मतलब है कि आप कोस (बी) और पाप (बी) और रनटाइम गणना पर cos (एचपी) और पाप (एचपी) precompute कर सकते हैं। आप

cos(a+b) = cos(a)*cos(b)-sin(a)*sin(b) 

आप कुछ गुणा और परिवर्धन के लिए sin और cos रों के एक जोड़े व्यापार हो जाएगा का बार-बार उपयोग करके क्योंकि (एन a + b) मिलता है, लगभग निश्चित रूप से सार्थक कर सकते हैं।

यदि आप महत्वाकांक्षी महसूस कर रहे हैं आप बेहतर कर सकते हैं। आपको पर अप्रत्यक्ष रूप से hp मिल रहा है। पैटर्न trig-function(rational-function(inverse-trig-function(x))) को अक्सर बहुपदों और जड़ों के कुछ संयोजन द्वारा प्रतिस्थापित किया जा सकता है जो ट्रिगर कार्यों की तुलना में मूल्यांकन करने के लिए तेज़ होते हैं।

मैं कैसे pow जावा में कार्यान्वित किया जाता है पता नहीं है, लेकिन यह लॉग का उपयोग करता है, तो आप का उपयोग कर Cp2=Cp*Cp;Cp4=Cp2*Cp2;Cp7=Cp4*Cp2*Cp;

अपडेट हो रही Cp7 से बेहतर हो सकता है: अभी थोड़ा और सट्टा हो रही है मेरे पास नहीं है के रूप में वास्तव में कोड को फिर से लिखने का समय। पावर ऑप्टिमाइज़ेशन और ट्रिगर ऑप्टिमाइज़ेशन वास्तव में छिपाने में एक ही चीज़ है! ट्रिगर ऑप्टिमाइज़ेशन जटिल संख्याओं पर लागू पावर ऑप्टिमाइज़ेशन का एक संस्करण है। और भी, लाइन

double dH = 2 * Math.sqrt(CpProd) * Math.sin(dhp/2); 

एक जटिल संख्या वर्ग रूट ऑपरेशन का हिस्सा है। इससे मुझे लगता है कि इस कोड का एक बड़ा हिस्सा वास्तव में लगभग सभी ट्रिगर कार्यों को समाप्त करने वाली जटिल संख्याओं का उपयोग करने के लिए लिखा जा सकता है। मैं नहीं जानता कि कैसे अपने जटिल संख्या गणित हालांकि है ...

+0

मैंने पावर ऑप्टिमाइज़ेशन जोड़ा है और फ़ंक्शन अब 1.5 गुना तेज है। अब मुझे कागज़ की चादर पकड़नी है और अब कुछ ट्रिग गणित का मसौदा तैयार करना है। (: – aLfa

+0

कोसाइन विस्तार ने थोड़ा सा मदद की, लेकिन मेरा जटिल अंकगणित कभी अच्छा नहीं था और मुझे डर है कि यह कभी नहीं होगा।): – aLfa

1

आम तौर पर किसी भी प्रणाली है जो इस को लागू करता है और गंभीर गति संबंधी समस्याएं हो सकती यादृच्छिक रंग कर रही करने के लिए नहीं जा रहा है। यह कई अलग-अलग रंग होने जा रहा है। यहां तक ​​कि विभिन्न रंगों से भरा एक विशाल छवि आमतौर पर केवल कुछ हज़ार रंग होने जा रही है। मैं बहुत कैशिंग एल्गोरिदम की अत्यधिक अनुशंसा करता हूं। यद्यपि यदि गति एक चिंता है तो आपको अपना खुद का रोल करना चाहिए (आप केवल प्राइमेटिव चाहते हैं, गति)।

ज्यादा वास्तविक रंग दूरी दिनचर्या के साथ ही किया जाना के अनुकूलन नहीं है, लेकिन मैं इस बात के लिए एक कैशिंग प्रणाली लिखा था और यह एक 100 गुना तेजी के आदेश पर चला गया। दूरी की नियमितता भारी प्रभावशाली कारक से एक ब्लाइंड तक चली गई। आपको इसकी गति को कम करने की तलाश नहीं करनी चाहिए। आप कुछ खा सकते हैं। लेकिन, आप जिस चीज को सही तरीके से बुलाते हैं उसे कम करें।

आप दो सेट आदानों है और यह तो एक बहुत बहुत लंबे समय के बाद एक सेट उत्पादन पैदा करता है, और करता है। 7 डबल्स प्रति कैशिंग इंडेक्स। वह 14 बाइट्स है। 14 मेगापिक्सल मेमोरी पदचिह्न के लिए (या तो, हैश को अनदेखा करना या क्या नहीं, संभवतः हम दो बार बात कर रहे हैं)। आप एक लाख प्रविष्टियों को स्टोर कर सकते हैं और यह पर्याप्त है कि यदि आपके पास 1k विशिष्ट भिन्न रंग हैं तो आपको 90% से अधिक कैश हिट मिलेगी। यदि आप आरजीबी से लैब तक अपने प्रारंभिक रंगों को परिवर्तित कर रहे हैं तो भी आप इसे बहुत कम कर सकते हैं (उन रूपांतरणों को भी कैश किया जाना चाहिए)। यदि आप 5% समय की तरह हिट करते हैं तो आप एक गति देखेंगे। और आपको 99% समय की हिट मिल जाएगी (जब तक कि आप यादृच्छिक रंग तुलना की तरह अजीब कुछ नहीं कर रहे हों)।मेरे अवलोकनों से यह CIEDE2000 को यूक्लिडियन आरजीबी के रूप में काफी समय लगता है।

संबंधित मुद्दे

 संबंधित मुद्दे