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