سؤال

لقد جعلت هذه الوظيفة لحساب اختلافات الألوان في مساحة CIE Lab Colorspace ، لكنها تفتقر إلى السرعة. نظرًا لأنني لست خبيرًا في Java ، أتساءل عما إذا كان لدى أي معلم Java حوله بعض النصائح التي يمكن أن تحسن السرعة هنا.

يعتمد الرمز على وظيفة 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);
}
هل كانت مفيدة؟

المحلول

cos باهظة الثمن ، وخاصة 4 على التوالي. يبدو أنك تقوم بحساب COS (nA+B) حيث B ثابت و N هو عدد صحيح صغير. هذا يعني أنه يمكنك حساب COS (B) والخطيئة (B) وفي وقت التشغيل فقط COS (HP) و SIN (HP). يمكنك الحصول على cos (nA+B) عن طريق الاستخدام المتكرر لـ

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

سوف تتداول بضعة sinرمل cosS لبعض الضربات والإضافات ، من المؤكد أنها تستحق العناء.

يمكنك أن تفعل أفضل إذا كنت تشعر بالطموح. أنت تحصل hp بشكل غير مباشر من atan2. النمط trig-function(rational-function(inverse-trig-function(x))) يمكن استبدالها في كثير من الأحيان ببعض مزيج من كثير الحدود والجذور التي هي أسرع لتقييم من وظائف المثلثات.

لا أعرف كيف pow يتم تنفيذه في Java ، ولكن إذا كان يستخدم سجلات ، فقد تكون أفضل حالًا Cp7 استخدام Cp2=Cp*Cp;Cp4=Cp2*Cp2;Cp7=Cp4*Cp2*Cp;

تحديث: الحصول على مزيد من المضاربة الآن حيث ليس لدي وقت لإعادة كتابة الرمز بالفعل. إن تحسين الطاقة وتحسين المثلثات هما في الواقع نفس الشيء في تمويه! تحسين TRIG هو إصدار من تحسين الطاقة المطبق على الأرقام المعقدة. ما هو أكثر من ذلك ، الخط

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

هو جزء من عملية الجذر التربيعي المعقدة. هذا يجعلني أعتقد أنه يمكن بالفعل كتابة جزء كبير من هذا الرمز لاستخدام الأرقام المعقدة التي تقضي على جميع وظائف Trig تقريبًا. لا أعرف كيف أن الحساب المعقد الخاص بك هو ...

نصائح أخرى

بشكل عام ، لن يقوم أي نظام ينفذ هذا ولديه مشكلات خطيرة في السرعة بألوان عشوائية. ستقوم بعدة ألوان متميزة. حتى الصورة العملاقة المليئة بالألوان المختلفة لا تحتوي عادة على بضعة آلاف من الألوان. أوصي بشدة بخوارزمية التخزين المؤقت. على الرغم من أن السرعة كانت مصدر قلق ، فيجب أن تدور حولها (تريد البدائية فقط ، السرعة).

ليس هناك الكثير من التحسينات التي يتعين القيام بها مع روتين مسافة اللون الفعلي نفسه ، لكنني كتبت نظام تخزين مؤقت لهذا الشيء واستمر في ترتيب أسرع 100 مرة. انتقل روتين المسافة من العامل السائد الساحق إلى وميض. يجب ألا تسعى إلى تقليل سرعة ذلك. قد تخرج شيئًا. ولكن ، قلل من عدد المرات التي تستدعي فيها الشيء بشكل صحيح.

لديك اثنين من المدخلات المحددة وتنتج مجموعة واحدة ، وتفعل ذلك بعد وقت طويل جدا. 7 زوجي لكل مؤشر التخزين المؤقت. هذا 14 بايت. للحصول على البصمة الذاكرة 14 ميج (أو نحو ذلك ، تجاهل التجزئة أو ما لا ، من المحتمل أننا نتحدث مزدوجة). يمكنك تخزين مليون إدخالات ، وهذا يكفي أنه إذا كان لديك ألوان مختلفة مختلفة ، فستحصل على إصابات ذاكرة التخزين المؤقت بنسبة 90 ٪. يمكنك حتى تقليل هذا الأمر بشكل كبير إذا كنت تقوم بتحويل ألوانك الأولية من RGB إلى المختبر (يجب تخزين هذه التحويلات أيضًا). سترى سرعة إذا وصلت إلى 5 ٪ من الوقت. وستحصل على زيارات من المحتمل 99 ٪ من الوقت (إلا إذا كنت تفعل شيئًا غريبًا مثل مقارنات الألوان العشوائية). من ملاحظاتي ، يجعل Ciede2000 يتخذ نفس الشيء عن وقت RGB الإقليدي.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top