• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** Copyright (C) 1989, 1991 by Jef Poskanzer.
3 ** Copyright (C) 1997, 2000, 2002 by Greg Roelofs; based on an idea by
4 **                                Stefan Schneider.
5 ** © 2009-2013 by Kornel Lesinski.
6 **
7 ** Permission to use, copy, modify, and distribute this software and its
8 ** documentation for any purpose and without fee is hereby granted, provided
9 ** that the above copyright notice appear in all copies and that both that
10 ** copyright notice and this permission notice appear in supporting
11 ** documentation.  This software is provided "as is" without express or
12 ** implied warranty.
13 */
14 
15 #include <stdlib.h>
16 #include <stddef.h>
17 
18 #include "libimagequant.h"
19 #include "pam.h"
20 #include "mediancut.h"
21 
22 #define index_of_channel(ch) (offsetof(f_pixel,ch)/sizeof(float))
23 
24 static f_pixel averagepixels (unsigned int clrs, const hist_item achv[],
25     float min_opaque_val, const f_pixel center);
26 
27 struct box
28 {
29   f_pixel color;
30   f_pixel variance;
31   double sum, total_error, max_error;
32   unsigned int ind;
33   unsigned int colors;
34 };
35 
36 ALWAYS_INLINE static double variance_diff (double val,
37     const double good_enough);
38 inline static double
variance_diff(double val,const double good_enough)39 variance_diff (double val, const double good_enough)
40 {
41   val *= val;
42   if (val < good_enough * good_enough)
43     return val * 0.25;
44   return val;
45 }
46 
47 /** Weighted per-channel variance of the box. It's used to decide which channel to split by */
48 static f_pixel
box_variance(const hist_item achv[],const struct box * box)49 box_variance (const hist_item achv[], const struct box *box)
50 {
51   f_pixel mean = box->color;
52   double variancea = 0, variancer = 0, varianceg = 0, varianceb = 0;
53 
54   for (unsigned int i = 0; i < box->colors; ++i) {
55     f_pixel px = achv[box->ind + i].acolor;
56     double weight = achv[box->ind + i].adjusted_weight;
57     variancea += variance_diff (mean.a - px.a, 2.0 / 256.0) * weight;
58     variancer += variance_diff (mean.r - px.r, 1.0 / 256.0) * weight;
59     varianceg += variance_diff (mean.g - px.g, 1.0 / 256.0) * weight;
60     varianceb += variance_diff (mean.b - px.b, 1.0 / 256.0) * weight;
61   }
62 
63   return (f_pixel) {
64   .a = variancea * (4.0 / 16.0),.r = variancer * (7.0 / 16.0),.g =
65         varianceg * (9.0 / 16.0),.b = varianceb * (5.0 / 16.0),};
66 }
67 
68 static double
box_max_error(const hist_item achv[],const struct box * box)69 box_max_error (const hist_item achv[], const struct box *box)
70 {
71   f_pixel mean = box->color;
72   double max_error = 0;
73   unsigned int i;
74 
75   for (i = 0; i < box->colors; ++i) {
76     const double diff = colordifference (mean, achv[box->ind + i].acolor);
77     if (diff > max_error) {
78       max_error = diff;
79     }
80   }
81   return max_error;
82 }
83 
84 ALWAYS_INLINE static double color_weight (f_pixel median, hist_item h);
85 
86 static inline void
hist_item_swap(hist_item * l,hist_item * r)87 hist_item_swap (hist_item * l, hist_item * r)
88 {
89   if (l != r) {
90     hist_item t = *l;
91     *l = *r;
92     *r = t;
93   }
94 }
95 
96 ALWAYS_INLINE static unsigned int qsort_pivot (const hist_item * const base,
97     const unsigned int len);
98 inline static unsigned int
qsort_pivot(const hist_item * const base,const unsigned int len)99 qsort_pivot (const hist_item * const base, const unsigned int len)
100 {
101   if (len < 32) {
102     return len / 2;
103   }
104 
105   {
106     const unsigned int aidx = 8, bidx = len / 2, cidx = len - 1;
107     const unsigned int a = base[aidx].tmp.sort_value, b =
108         base[bidx].tmp.sort_value, c = base[cidx].tmp.sort_value;
109     return (a < b) ? ((b < c) ? bidx : ((a < c) ? cidx : aidx))
110         : ((b > c) ? bidx : ((a < c) ? aidx : cidx));
111   }
112 }
113 
114 ALWAYS_INLINE static unsigned int qsort_partition (hist_item * const base,
115     const unsigned int len);
116 inline static unsigned int
qsort_partition(hist_item * const base,const unsigned int len)117 qsort_partition (hist_item * const base, const unsigned int len)
118 {
119   unsigned int l = 1, r = len;
120   if (len >= 8) {
121     hist_item_swap (&base[0], &base[qsort_pivot (base, len)]);
122   }
123 
124   {
125     const unsigned int pivot_value = base[0].tmp.sort_value;
126     while (l < r) {
127       if (base[l].tmp.sort_value >= pivot_value) {
128         l++;
129       } else {
130         while (l < --r && base[r].tmp.sort_value <= pivot_value) {
131         }
132         hist_item_swap (&base[l], &base[r]);
133       }
134     }
135     l--;
136     hist_item_swap (&base[0], &base[l]);
137   }
138 
139   return l;
140 }
141 
142 /** quick select algorithm */
143 static void
hist_item_sort_range(hist_item * base,unsigned int len,unsigned int sort_start)144 hist_item_sort_range (hist_item * base, unsigned int len,
145     unsigned int sort_start)
146 {
147   for (;;) {
148     const unsigned int l = qsort_partition (base, len), r = l + 1;
149 
150     if (l > 0 && sort_start < l) {
151       len = l;
152     } else if (r < len && sort_start > r) {
153       base += r;
154       len -= r;
155       sort_start -= r;
156     } else
157       break;
158   }
159 }
160 
161 /** sorts array to make sum of weights lower than halfvar one side, returns edge between <halfvar and >halfvar parts of the set */
162 static hist_item *
hist_item_sort_halfvar(hist_item * base,unsigned int len,double * const lowervar,const double halfvar)163 hist_item_sort_halfvar (hist_item * base, unsigned int len,
164     double *const lowervar, const double halfvar)
165 {
166   do {
167     const unsigned int l = qsort_partition (base, len), r = l + 1;
168 
169     // check if sum of left side is smaller than half,
170     // if it is, then it doesn't need to be sorted
171     unsigned int t = 0;
172     double tmpsum = *lowervar;
173     while (t <= l && tmpsum < halfvar)
174       tmpsum += base[t++].color_weight;
175 
176     if (tmpsum < halfvar) {
177       *lowervar = tmpsum;
178     } else {
179       if (l > 0) {
180         hist_item *res = hist_item_sort_halfvar (base, l, lowervar, halfvar);
181         if (res)
182           return res;
183       } else {
184         // End of left recursion. This will be executed in order from the first element.
185         *lowervar += base[0].color_weight;
186         if (*lowervar > halfvar)
187           return &base[0];
188       }
189     }
190 
191     if (len > r) {
192       base += r;
193       len -= r;                 // tail-recursive "call"
194     } else {
195       *lowervar += base[r].color_weight;
196       return (*lowervar > halfvar) ? &base[r] : NULL;
197     }
198   } while (1);
199 }
200 
201 static f_pixel get_median (const struct box *b, hist_item achv[]);
202 
203 typedef struct
204 {
205   unsigned int chan;
206   float variance;
207 } channelvariance;
208 
209 static int
comparevariance(const void * ch1,const void * ch2)210 comparevariance (const void *ch1, const void *ch2)
211 {
212   return ((const channelvariance *) ch1)->variance >
213       ((const channelvariance *) ch2)->variance ? -1 : (((const channelvariance
214               *) ch1)->variance <
215       ((const channelvariance *) ch2)->variance ? 1 : 0);
216 }
217 
218 /** Finds which channels need to be sorted first and preproceses achv for fast sort */
219 static double
prepare_sort(struct box * b,hist_item achv[])220 prepare_sort (struct box *b, hist_item achv[])
221 {
222   /*
223    ** Sort dimensions by their variance, and then sort colors first by dimension with highest variance
224    */
225   double totalvar = 0;
226   channelvariance channels[4] = {
227     {index_of_channel (r), b->variance.r},
228     {index_of_channel (g), b->variance.g},
229     {index_of_channel (b), b->variance.b},
230     {index_of_channel (a), b->variance.a},
231   };
232 
233   qsort (channels, 4, sizeof (channels[0]), comparevariance);
234 
235   for (unsigned int i = 0; i < b->colors; i++) {
236     const float *chans = (const float *) &achv[b->ind + i].acolor;
237     // Only the first channel really matters. When trying median cut many times
238     // with different histogram weights, I don't want sort randomness to influence outcome.
239     achv[b->ind + i].tmp.sort_value =
240         ((unsigned int) (chans[channels[0].chan] *
241             65535.0) << 16) | (unsigned int) ((chans[channels[2].chan] +
242             chans[channels[1].chan] / 2.0 +
243             chans[channels[3].chan] / 4.0) * 65535.0);
244   }
245 
246   {
247     const f_pixel median = get_median (b, achv);
248 
249     // box will be split to make color_weight of each side even
250     const unsigned int ind = b->ind, end = ind + b->colors;
251     for (unsigned int j = ind; j < end; j++)
252       totalvar += (achv[j].color_weight = color_weight (median, achv[j]));
253   }
254   return totalvar / 2.0;
255 }
256 
257 /** finds median in unsorted set by sorting only minimum required */
258 static f_pixel
get_median(const struct box * b,hist_item achv[])259 get_median (const struct box *b, hist_item achv[])
260 {
261   const unsigned int median_start = (b->colors - 1) / 2;
262 
263   hist_item_sort_range (&(achv[b->ind]), b->colors, median_start);
264 
265   if (b->colors & 1)
266     return achv[b->ind + median_start].acolor;
267 
268   // technically the second color is not guaranteed to be sorted correctly
269   // but most of the time it is good enough to be useful
270   return averagepixels (2, &achv[b->ind + median_start], 1.0, (f_pixel) {
271       0.5, 0.5, 0.5, 0.5}
272   );
273 }
274 
275 /*
276  ** Find the best splittable box. -1 if no boxes are splittable.
277  */
278 static int
best_splittable_box(struct box * bv,unsigned int boxes,const double max_mse)279 best_splittable_box (struct box *bv, unsigned int boxes, const double max_mse)
280 {
281   int bi = -1;
282   double maxsum = 0;
283   unsigned int i;
284 
285   for (i = 0; i < boxes; i++) {
286     if (bv[i].colors < 2) {
287       continue;
288     }
289     // looks only at max variance, because it's only going to split by it
290     {
291       const double cv =
292           MAX (bv[i].variance.r, MAX (bv[i].variance.g, bv[i].variance.b));
293       double thissum = bv[i].sum * MAX (bv[i].variance.a, cv);
294 
295       if (bv[i].max_error > max_mse) {
296         thissum = thissum * bv[i].max_error / max_mse;
297       }
298 
299       if (thissum > maxsum) {
300         maxsum = thissum;
301         bi = i;
302       }
303     }
304   }
305   return bi;
306 }
307 
308 inline static double
color_weight(f_pixel median,hist_item h)309 color_weight (f_pixel median, hist_item h)
310 {
311   float diff = colordifference (median, h.acolor);
312   // if color is "good enough", don't split further
313   if (diff < 2.f / 256.f / 256.f)
314     diff /= 2.f;
315   return sqrt (diff) * (sqrt (1.0 + h.adjusted_weight) - 1.0);
316 }
317 
318 static void set_colormap_from_boxes (colormap * map, struct box *bv,
319     unsigned int boxes, hist_item * achv);
320 static void adjust_histogram (hist_item * achv, const colormap * map,
321     const struct box *bv, unsigned int boxes);
322 
323 static double
box_error(const struct box * box,const hist_item achv[])324 box_error (const struct box *box, const hist_item achv[])
325 {
326   f_pixel avg = box->color;
327   unsigned int i;
328   double total_error = 0;
329 
330   for (i = 0; i < box->colors; ++i) {
331     total_error +=
332         colordifference (avg,
333         achv[box->ind + i].acolor) * achv[box->ind + i].perceptual_weight;
334   }
335 
336   return total_error;
337 }
338 
339 
340 static bool
total_box_error_below_target(double target_mse,struct box bv[],unsigned int boxes,const histogram * hist)341 total_box_error_below_target (double target_mse, struct box bv[],
342     unsigned int boxes, const histogram * hist)
343 {
344   double total_error = 0;
345   unsigned int i;
346 
347   target_mse *= hist->total_perceptual_weight;
348 
349   for (i = 0; i < boxes; i++) {
350     // error is (re)calculated lazily
351     if (bv[i].total_error >= 0) {
352       total_error += bv[i].total_error;
353     }
354     if (total_error > target_mse)
355       return false;
356   }
357 
358   for (i = 0; i < boxes; i++) {
359     if (bv[i].total_error < 0) {
360       bv[i].total_error = box_error (&bv[i], hist->achv);
361       total_error += bv[i].total_error;
362     }
363     if (total_error > target_mse)
364       return false;
365   }
366 
367   return true;
368 }
369 
370 /*
371  ** Here is the fun part, the median-cut colormap generator.  This is based
372  ** on Paul Heckbert's paper, "Color Image Quantization for Frame Buffer
373  ** Display," SIGGRAPH 1982 Proceedings, page 297.
374  */
375 LIQ_PRIVATE colormap *
mediancut(histogram * hist,const float min_opaque_val,unsigned int newcolors,const double target_mse,const double max_mse,void * (* malloc)(size_t),void (* free)(void *))376 mediancut (histogram * hist, const float min_opaque_val, unsigned int newcolors,
377     const double target_mse, const double max_mse, void *(*malloc) (size_t),
378     void (*free) (void *))
379 {
380   hist_item *achv = hist->achv;
381   struct box *bv = g_alloca (sizeof (struct box) * newcolors);
382   unsigned int i, boxes, subset_size;
383   colormap *representative_subset = NULL;
384   colormap *map;
385 
386   /*
387    ** Set up the initial box.
388    */
389   bv[0].ind = 0;
390   bv[0].colors = hist->size;
391   bv[0].color =
392       averagepixels (bv[0].colors, &achv[bv[0].ind], min_opaque_val, (f_pixel) {
393       0.5, 0.5, 0.5, 0.5});
394   bv[0].variance = box_variance (achv, &bv[0]);
395   bv[0].max_error = box_max_error (achv, &bv[0]);
396   bv[0].sum = 0;
397   bv[0].total_error = -1;
398   for (i = 0; i < bv[0].colors; i++)
399     bv[0].sum += achv[i].adjusted_weight;
400 
401   boxes = 1;
402 
403   // remember smaller palette for fast searching
404   subset_size = ceilf (powf (newcolors, 0.7f));
405 
406   /*
407    ** Main loop: split boxes until we have enough.
408    */
409   while (boxes < newcolors) {
410     unsigned int indx, clrs;
411     unsigned int break_at, i;
412     double lowervar = 0, halfvar, current_max_mse;
413     hist_item *break_p;
414     double sm, lowersum;
415     int bi;
416     f_pixel previous_center;
417 
418     if (boxes == subset_size) {
419       representative_subset = pam_colormap (boxes, malloc, free);
420       set_colormap_from_boxes (representative_subset, bv, boxes, achv);
421     }
422     // first splits boxes that exceed quality limit (to have colors for things like odd green pixel),
423     // later raises the limit to allow large smooth areas/gradients get colors.
424     current_max_mse = max_mse + (boxes / (double) newcolors) * 16.0 * max_mse;
425     bi = best_splittable_box (bv, boxes, current_max_mse);
426     if (bi < 0)
427       break;                    /* ran out of colors! */
428 
429     indx = bv[bi].ind;
430     clrs = bv[bi].colors;
431 
432     /*
433        Classic implementation tries to get even number of colors or pixels in each subdivision.
434 
435        Here, instead of popularity I use (sqrt(popularity)*variance) metric.
436        Each subdivision balances number of pixels (popular colors) and low variance -
437        boxes can be large if they have similar colors. Later boxes with high variance
438        will be more likely to be split.
439 
440        Median used as expected value gives much better results than mean.
441      */
442     halfvar = prepare_sort (&bv[bi], achv);
443 
444     // hist_item_sort_halfvar sorts and sums lowervar at the same time
445     // returns item to break at …minus one, which does smell like an off-by-one error.
446     break_p = hist_item_sort_halfvar (&achv[indx], clrs, &lowervar, halfvar);
447     break_at = MIN (clrs - 1, break_p - &achv[indx] + 1);
448 
449     /*
450      ** Split the box.
451      */
452     sm = bv[bi].sum;
453     lowersum = 0;
454     for (i = 0; i < break_at; i++)
455       lowersum += achv[indx + i].adjusted_weight;
456 
457     previous_center = bv[bi].color;
458     bv[bi].colors = break_at;
459     bv[bi].sum = lowersum;
460     bv[bi].color =
461         averagepixels (bv[bi].colors, &achv[bv[bi].ind], min_opaque_val,
462         previous_center);
463     bv[bi].total_error = -1;
464     bv[bi].variance = box_variance (achv, &bv[bi]);
465     bv[bi].max_error = box_max_error (achv, &bv[bi]);
466     bv[boxes].ind = indx + break_at;
467     bv[boxes].colors = clrs - break_at;
468     bv[boxes].sum = sm - lowersum;
469     bv[boxes].color =
470         averagepixels (bv[boxes].colors, &achv[bv[boxes].ind], min_opaque_val,
471         previous_center);
472     bv[boxes].total_error = -1;
473     bv[boxes].variance = box_variance (achv, &bv[boxes]);
474     bv[boxes].max_error = box_max_error (achv, &bv[boxes]);
475 
476     ++boxes;
477 
478     if (total_box_error_below_target (target_mse, bv, boxes, hist)) {
479       break;
480     }
481   }
482 
483   map = pam_colormap (boxes, malloc, free);
484   set_colormap_from_boxes (map, bv, boxes, achv);
485 
486   map->subset_palette = representative_subset;
487   adjust_histogram (achv, map, bv, boxes);
488 
489   return map;
490 }
491 
492 static void
set_colormap_from_boxes(colormap * map,struct box * bv,unsigned int boxes,hist_item * achv)493 set_colormap_from_boxes (colormap * map, struct box *bv, unsigned int boxes,
494     hist_item * achv)
495 {
496   /*
497    ** Ok, we've got enough boxes.  Now choose a representative color for
498    ** each box.  There are a number of possible ways to make this choice.
499    ** One would be to choose the center of the box; this ignores any structure
500    ** within the boxes.  Another method would be to average all the colors in
501    ** the box - this is the method specified in Heckbert's paper.
502    */
503 
504   for (unsigned int bi = 0; bi < boxes; ++bi) {
505     map->palette[bi].acolor = bv[bi].color;
506 
507     /* store total color popularity (perceptual_weight is approximation of it) */
508     map->palette[bi].popularity = 0;
509     for (unsigned int i = bv[bi].ind; i < bv[bi].ind + bv[bi].colors; i++) {
510       map->palette[bi].popularity += achv[i].perceptual_weight;
511     }
512   }
513 }
514 
515 /* increase histogram popularity by difference from the final color (this is used as part of feedback loop) */
516 static void
adjust_histogram(hist_item * achv,const colormap * map,const struct box * bv,unsigned int boxes)517 adjust_histogram (hist_item * achv, const colormap * map, const struct box *bv,
518     unsigned int boxes)
519 {
520   for (unsigned int bi = 0; bi < boxes; ++bi) {
521     for (unsigned int i = bv[bi].ind; i < bv[bi].ind + bv[bi].colors; i++) {
522       achv[i].adjusted_weight *=
523           sqrt (1.0 + colordifference (map->palette[bi].acolor,
524               achv[i].acolor) / 4.0);
525       achv[i].tmp.likely_colormap_index = bi;
526     }
527   }
528 }
529 
530 static f_pixel
averagepixels(unsigned int clrs,const hist_item achv[],const float min_opaque_val,const f_pixel center)531 averagepixels (unsigned int clrs, const hist_item achv[],
532     const float min_opaque_val, const f_pixel center)
533 {
534   double r = 0, g = 0, b = 0, a = 0, new_a = 0, sum = 0;
535   float maxa = 0;
536 
537   // first find final opacity in order to blend colors at that opacity
538   for (unsigned int i = 0; i < clrs; ++i) {
539     const f_pixel px = achv[i].acolor;
540     new_a += px.a * achv[i].adjusted_weight;
541     sum += achv[i].adjusted_weight;
542 
543     /* find if there are opaque colors, in case we're supposed to preserve opacity exactly (ie_bug) */
544     if (px.a > maxa)
545       maxa = px.a;
546   }
547 
548   if (sum)
549     new_a /= sum;
550 
551     /** if there was at least one completely opaque color, "round" final color to opaque */
552   if (new_a >= min_opaque_val && maxa >= (255.0 / 256.0))
553     new_a = 1;
554 
555   sum = 0;
556   // reverse iteration for cache locality with previous loop
557   for (int i = clrs - 1; i >= 0; i--) {
558     double tmp, weight = 1.0f;
559     f_pixel px = achv[i].acolor;
560 
561     /* give more weight to colors that are further away from average
562        this is intended to prevent desaturation of images and fading of whites
563      */
564     tmp = (center.r - px.r);
565     weight += tmp * tmp;
566     tmp = (center.g - px.g);
567     weight += tmp * tmp;
568     tmp = (center.b - px.b);
569     weight += tmp * tmp;
570 
571     weight *= achv[i].adjusted_weight;
572     sum += weight;
573 
574     if (px.a) {
575       px.r /= px.a;
576       px.g /= px.a;
577       px.b /= px.a;
578     }
579 
580     r += px.r * new_a * weight;
581     g += px.g * new_a * weight;
582     b += px.b * new_a * weight;
583     a += new_a * weight;
584   }
585 
586   if (sum) {
587     a /= sum;
588     r /= sum;
589     g /= sum;
590     b /= sum;
591   }
592 
593   assert (!isnan (r) && !isnan (g) && !isnan (b) && !isnan (a));
594 
595   return (f_pixel) {
596   .r = r,.g = g,.b = b,.a = a};
597 }
598