calgorithmmathimage-processingcolors

Are there known implementations of the CIEDE2000 or CIE94 Delta-E color difference calculation algorithm?


I need to calculate the Delta-E distance between two colors. The algorithm to do so with two colors in CIELab color space looks like this:

enter image description here

Are there known open-sourced implementations of this algorithm? It's not hard to implement, but from my last attempt of implementing a color-space conversion algorithm I'd prefer to not re-develop the wheel when it's already on the road and tested.

CIEDE2000 would be nice too and more accurate, but might also be overkill on the iPhone. CIE94 would be just fine I guess.


Solution

  • I typed in the equation (for Common Lisp code see at bottom) and ran a few random evaluations. The parameters are listed in this order: L*1 a*1 b*1 L*2 a*2 b*2 DeltaE*

    I'm not perfectly sure that the results are correct. But if your code gives the same results, then it's probably sufficient.

       ((53.0 0.65 0.15 33.0 -0.45 -0.1 20.03112)
        (42.0 -0.3 0.1 74.0 -0.2 -0.15 32.001118)
        (12.0 -1.0 -0.45 32.0 0.3 0.9 20.084782)
        (94.0 -0.1 -0.55 77.0 0.5 0.45 17.03928)
        (75.0 -0.8 0.35 46.0 -0.6 -0.85 29.02483)
        (83.0 -0.65 -0.7 67.0 0.75 0.0 16.074173)
        (70.0 -0.7 0.9 54.0 0.35 -0.95 16.13608)
        (81.0 0.45 -0.8 53.0 -0.35 0.05 28.023375)
        (40.0 -0.2 -0.65 25.0 -1.0 0.8 15.088856)
        (66.0 0.85 -0.7 93.0 0.55 0.15 27.014244)
        (44.0 -0.5 0.5 23.0 -0.9 0.5 21.00363)
        (67.0 0.4 0.25 42.0 -0.25 0.6 25.010727)
        (32.0 0.6 0.55 86.0 0.0 0.25 54.003925)
        (96.0 -0.15 -0.9 87.0 0.25 -0.3 9.027307)
        (100.0 -0.6 0.3 61.0 -0.25 -0.75 39.015385)
        (2.0 -0.2 -0.65 73.0 -0.3 0.65 71.01173)
        (74.0 0.1 -0.65 96.0 -0.5 0.8 22.05474)
        (22.0 -0.3 -0.85 64.0 -0.65 -0.95 42.0015)
        (73.0 -0.35 0.3 38.0 0.25 -1.0 35.02875)
        (91.0 0.6 0.45 82.0 -0.25 0.2 9.042115))
    

    And here is the source code (tested in SBCL):

    ;; http://en.wikipedia.org/wiki/Hypot thats not necessary if numbers
    ;; are not float and even if they are float the values of L*, a* and
    ;; b* are bound to tiny range
    (defun hypot (x y)
      "Compute hypotenuse, prevent overflow."
      (declare (type number x y)
           (values number &optional))
      (let ((ax (abs x))
        (ay (abs y)))
        (if (or (< ax 1e-6) (< ay 1e-6))
        (sqrt (+ (* ax ax) (* ay ay)))
        (if (< ay ax)
            (* ax (sqrt (1+ (expt (/ y x) 2))))
            (* ay (sqrt (1+ (expt (/ x y) 2))))))))
    #+nil
    (list
     (hypot 1 0)
     (hypot 0 1)
     (hypot (sqrt 2) (sqrt 2))
     (hypot 2 10000))
    
    ;; http://www.devmaster.net/forums/archive/index.php/t-12680.html
    (defun hypot3 (x y z)
      (hypot (hypot x y) z))
    
    (defun delta-e*-94 (l1 a1 b1 l2 a2 b2 &key (application :graphic-arts))
      "Distance in CIE L* a* b* color space."
      (declare (type number l1 a1 b1 l2 a2 b2)
           (type (member :graphic-arts :textiles) application)
           (values number &optional))
      (destructuring-bind (kl k1 k2)
          (ecase application
        (:graphic-arts '(1 .045 .015))
        (:textiles '(2 .048 .014)))
       (let* ((delta-l (- l1 l2))
          (c1 (hypot a1 b1))
          (c2 (hypot a2 b2))
          (delta-c (- c1 c2))
          (delta-a (- a1 a2))
          (delta-b (- b1 b2))
          (delta-h (sqrt (+ (expt delta-a 2)
                (expt delta-b 2)
                (* -1 (expt delta-c 2)))))
          (l/k (/ delta-l kl))
          (c/k (/ delta-c (1+ (* k1 c1))))
          (h/k (/ delta-h (1+ (* k2 c1)))))
         (hypot3 l/k c/k h/k))))
    
    
    #+nil ;; some test runs
    (labels ((rL () ;; random number from 0..100 inclusive
           (random 101))
         (r- ()
           (/ (- (random 40) 20) 20))
         (r3 ()
           (list (rL) (r-) (r-))))
      (loop for i below 20 collect
       (destructuring-bind (l a b) (r3)
         (destructuring-bind (ll aa bb) (r3)
           (mapcar #'(lambda (x) (* 1s0 x)) 
               (list l a b ll aa bb (delta-e*-94 l a b ll aa bb))))))) 
    
    #+nil ;; example test run
    ((80.0 0.85 0.35 13.0 0.4 -0.8 67.01107)
     (11.0 0.25 -0.35 66.0 0.45 0.15 55.002594)
     (74.0 -0.55 0.45 98.0 0.7 -0.85 24.066118)
     (37.0 -0.3 0.35 60.0 0.55 -0.3 23.02452)
     (20.0 -0.85 0.5 20.0 -0.25 0.1 0.6907073)
     (23.0 0.25 -0.05 15.0 0.55 -0.8 8.039892)
     (29.0 -0.55 0.05 9.0 -0.2 -0.8 20.020708)
     (11.0 0.55 -0.45 60.0 0.9 -0.15 49.00211)
     (70.0 0.5 -0.15 66.0 -0.8 0.85 4.3169336)
     (18.0 -0.5 0.55 49.0 0.5 -0.25 31.025839)
     (27.0 -0.95 0.3 43.0 -0.1 0.2 16.021187)
     (5.0 -0.4 0.5 70.0 -0.75 -0.75 65.012665)
     (9.0 -1.0 -0.2 66.0 0.4 0.05 57.01702)
     (10.0 0.25 -0.75 13.0 -0.85 -0.75 3.1900785)
     (16.0 -0.65 -0.4 31.0 -0.6 -0.5 15.000405)
     (90.0 0.4 0.1 18.0 -0.6 -0.85 72.01298)
     (92.0 0.4 0.1 31.0 -0.7 0.2 61.009853)
     (99.0 -0.7 -0.5 40.0 -0.9 0.35 59.006287)
     (40.0 0.95 -0.2 62.0 -0.7 -0.25 22.06002)
     (16.0 0.5 0.7 35.0 0.35 -0.45 19.03436))