Palette Procedures


; +------------------------+------------------------------------------
; | Palette-Based Encoding |
; +------------------------+

;;; Procedure:
;;;   palette-encode-color
;;; Parameters:
;;;   palette, a nonempty list of RGB colors
;;;   color, an RGB color
;;; Purpose:
;;;   Determine a number that appropriately encodes color using
;;;   the given palette.
;;; Produces:
;;;   encoding, an integer
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   0 <= encoding < (length palette)
;;;   (rgb-distance color (list-ref palette encoding)) <=
;;;     (rgb-distance color (list-ref palette i))
;;;     for all i, 0 <= i < (length palette)
(define palette-encode-color
  (lambda (palette color)
    (list-index-of palette (rgb-closest color palette))))
 

; +-------------------------+-----------------------------------------
; | Miscellaneous Utilities |
; +-------------------------+

;;; Procedure:
;;;   rgb-distance
;;; Parameters:
;;;   c1, an RGB color
;;;   c2, an RGB color
;;; Purpose:
;;;   Compute a "distance" between c1 and c2 that tells us how
;;;   well c1 estimates c2 (or vice versa).
;;; Produces:
;;;   distance, a real number
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   For any color c,
;;;     (rgb-distance c c) is 0 
;;;   If d is likely to be perceived as closer to c than e is to c, then
;;;     (rgb-distance c d) < (rgb-distance c e)
(define rgb-distance
  (lambda (c1 c2)
    (+ (square (- (rgb-red c1) (rgb-red c2)))
       (square (- (rgb-green c1) (rgb-green c2)))
       (square (- (rgb-blue c1) (rgb-blue c2))))))

;;; Procedure:
;;;   rgb-closer
;;; Parameters:
;;;   color, an RGB color
;;;   estimate1, an RGB color
;;;   estimate2, an RGB color
;;; Purpose:
;;;   Determines which of estimate1 and estimate2 is closer to color.
;;; Produces:
;;;   closer, an RGB color
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   closer is either estimate1 or estimate2
;;;   (rgb-distance color closer) <= (rgb-distance color estimate1)
;;;   (rgb-distance color closer) <= (rgb-distance color estimate2)
(define rgb-closer
  (lambda (color estimate1 estimate2)
    (if (<= (rgb-distance color estimate1) (rgb-distance color estimate2))
        estimate1
        estimate2)))

;;; Procedure:
;;;   rgb-closest
;;; Parameters:
;;;   color, an RGB color
;;;   colors, a list of RGB colors
;;; Purpose:
;;;   Determine the element of colors that is closest to
;;;   color
;;; Produces:
;;;   closest, an RGB color
;;; Preconditions:
;;;   colors is nonempty.
;;; Postconditions:
;;;   closest is an element of colors.
;;;   (rgb-distance color closest) <= (rgb-distance color c)
;;;     for all c in colors
(define rgb-closest
  (lambda (color colors)
    (let kernel ((remaining-colors (cdr colors))
                 (closest-so-far (car colors)))
      (if (null? remaining-colors)
          closest-so-far
          (kernel (cdr remaining-colors)
                  (rgb-closer color closest-so-far (car remaining-colors)))))))

;;; Procedure:
;;;   list-index-of
;;; Parameters:
;;;   lst, a list of values
;;;   val, a value
;;; Purpose:
;;;   Find an index of val in lst.
;;; Produces:
;;;   index, a number (or #f)
;;; Preconditions:
;;;   [No additional]
;;; Postconditions:
;;;   If there exists a value in lst equal to val, then
;;;     (list-ref lst index) equals val
;;;   If no such value exists, then
;;;     index is #f
(define list-index-of
  (lambda (lst val)
    (cond
      ((null? lst)
       #f)
      ((equal? val (car lst))
       0)
      (else
       (+ 1 (list-index-of (cdr lst) val))))))



Jerod Weinman