Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(449)

Side by Side Diff: third_party/libwebp/enc/histogram.c

Issue 2149863002: libwebp: update to v0.5.1 (Closed) Base URL: https://chromium.googlesource.com/chromium/src.git@master
Patch Set: Created 4 years, 5 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « third_party/libwebp/enc/filter.c ('k') | third_party/libwebp/enc/near_lossless.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright 2012 Google Inc. All Rights Reserved. 1 // Copyright 2012 Google Inc. All Rights Reserved.
2 // 2 //
3 // Use of this source code is governed by a BSD-style license 3 // Use of this source code is governed by a BSD-style license
4 // that can be found in the COPYING file in the root of the source 4 // that can be found in the COPYING file in the root of the source
5 // tree. An additional intellectual property rights grant can be found 5 // tree. An additional intellectual property rights grant can be found
6 // in the file PATENTS. All contributing project authors may 6 // in the file PATENTS. All contributing project authors may
7 // be found in the AUTHORS file in the root of the source tree. 7 // be found in the AUTHORS file in the root of the source tree.
8 // ----------------------------------------------------------------------------- 8 // -----------------------------------------------------------------------------
9 // 9 //
10 // Author: Jyrki Alakuijala (jyrki@google.com) 10 // Author: Jyrki Alakuijala (jyrki@google.com)
(...skipping 368 matching lines...) Expand 10 before | Expand all | Expand 10 after
379 alpha_cost + distance_cost; 379 alpha_cost + distance_cost;
380 if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) { 380 if ((alpha_sym | red_sym | blue_sym) == VP8L_NON_TRIVIAL_SYM) {
381 h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM; 381 h->trivial_symbol_ = VP8L_NON_TRIVIAL_SYM;
382 } else { 382 } else {
383 h->trivial_symbol_ = 383 h->trivial_symbol_ =
384 ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0); 384 ((uint32_t)alpha_sym << 24) | (red_sym << 16) | (blue_sym << 0);
385 } 385 }
386 } 386 }
387 387
388 static int GetBinIdForEntropy(double min, double max, double val) { 388 static int GetBinIdForEntropy(double min, double max, double val) {
389 const double range = max - min + 1e-6; 389 const double range = max - min;
390 const double delta = val - min; 390 if (range > 0.) {
391 return (int)(NUM_PARTITIONS * delta / range); 391 const double delta = val - min;
392 return (int)((NUM_PARTITIONS - 1e-6) * delta / range);
393 } else {
394 return 0;
395 }
392 } 396 }
393 397
394 static int GetHistoBinIndexLowEffort( 398 static int GetHistoBinIndex(const VP8LHistogram* const h,
395 const VP8LHistogram* const h, const DominantCostRange* const c) { 399 const DominantCostRange* const c, int low_effort) {
396 const int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_, 400 int bin_id = GetBinIdForEntropy(c->literal_min_, c->literal_max_,
397 h->literal_cost_); 401 h->literal_cost_);
398 assert(bin_id < NUM_PARTITIONS); 402 assert(bin_id < NUM_PARTITIONS);
403 if (!low_effort) {
404 bin_id = bin_id * NUM_PARTITIONS
405 + GetBinIdForEntropy(c->red_min_, c->red_max_, h->red_cost_);
406 bin_id = bin_id * NUM_PARTITIONS
407 + GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_);
408 assert(bin_id < BIN_SIZE);
409 }
399 return bin_id; 410 return bin_id;
400 } 411 }
401 412
402 static int GetHistoBinIndex(
403 const VP8LHistogram* const h, const DominantCostRange* const c) {
404 const int bin_id =
405 GetBinIdForEntropy(c->blue_min_, c->blue_max_, h->blue_cost_) +
406 NUM_PARTITIONS * GetBinIdForEntropy(c->red_min_, c->red_max_,
407 h->red_cost_) +
408 NUM_PARTITIONS * NUM_PARTITIONS * GetBinIdForEntropy(c->literal_min_,
409 c->literal_max_,
410 h->literal_cost_);
411 assert(bin_id < BIN_SIZE);
412 return bin_id;
413 }
414
415 // Construct the histograms from backward references. 413 // Construct the histograms from backward references.
416 static void HistogramBuild( 414 static void HistogramBuild(
417 int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs, 415 int xsize, int histo_bits, const VP8LBackwardRefs* const backward_refs,
418 VP8LHistogramSet* const image_histo) { 416 VP8LHistogramSet* const image_histo) {
419 int x = 0, y = 0; 417 int x = 0, y = 0;
420 const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits); 418 const int histo_xsize = VP8LSubSampleSize(xsize, histo_bits);
421 VP8LHistogram** const histograms = image_histo->histograms; 419 VP8LHistogram** const histograms = image_histo->histograms;
422 VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); 420 VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
423 assert(histo_bits > 0); 421 assert(histo_bits > 0);
424 while (VP8LRefsCursorOk(&c)) { 422 while (VP8LRefsCursorOk(&c)) {
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
462 460
463 // Analyze the dominant (literal, red and blue) entropy costs. 461 // Analyze the dominant (literal, red and blue) entropy costs.
464 for (i = 0; i < histo_size; ++i) { 462 for (i = 0; i < histo_size; ++i) {
465 VP8LHistogram* const histo = histograms[i]; 463 VP8LHistogram* const histo = histograms[i];
466 UpdateDominantCostRange(histo, &cost_range); 464 UpdateDominantCostRange(histo, &cost_range);
467 } 465 }
468 466
469 // bin-hash histograms on three of the dominant (literal, red and blue) 467 // bin-hash histograms on three of the dominant (literal, red and blue)
470 // symbol costs. 468 // symbol costs.
471 for (i = 0; i < histo_size; ++i) { 469 for (i = 0; i < histo_size; ++i) {
472 int num_histos; 470 const VP8LHistogram* const histo = histograms[i];
473 VP8LHistogram* const histo = histograms[i]; 471 const int bin_id = GetHistoBinIndex(histo, &cost_range, low_effort);
474 const int16_t bin_id = low_effort ?
475 (int16_t)GetHistoBinIndexLowEffort(histo, &cost_range) :
476 (int16_t)GetHistoBinIndex(histo, &cost_range);
477 const int bin_offset = bin_id * bin_depth; 472 const int bin_offset = bin_id * bin_depth;
478 // bin_map[n][0] for every bin 'n' maintains the counter for the number of 473 // bin_map[n][0] for every bin 'n' maintains the counter for the number of
479 // histograms in that bin. 474 // histograms in that bin.
480 // Get and increment the num_histos in that bin. 475 // Get and increment the num_histos in that bin.
481 num_histos = ++bin_map[bin_offset]; 476 const int num_histos = ++bin_map[bin_offset];
482 assert(bin_offset + num_histos < bin_depth * BIN_SIZE); 477 assert(bin_offset + num_histos < bin_depth * BIN_SIZE);
483 // Add histogram i'th index at num_histos (last) position in the bin_map. 478 // Add histogram i'th index at num_histos (last) position in the bin_map.
484 bin_map[bin_offset + num_histos] = i; 479 bin_map[bin_offset + num_histos] = i;
485 } 480 }
486 } 481 }
487 482
488 // Compact the histogram set by removing unused entries. 483 // Compact the histogram set by removing unused entries.
489 static void HistogramCompactBins(VP8LHistogramSet* const image_histo) { 484 static void HistogramCompactBins(VP8LHistogramSet* const image_histo) {
490 VP8LHistogram** const histograms = image_histo->histograms; 485 VP8LHistogram** const histograms = image_histo->histograms;
491 int i, j; 486 int i, j;
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
629 624
630 // We cannot add more elements than the capacity. 625 // We cannot add more elements than the capacity.
631 // The allocation adds an extra element to the official capacity so that 626 // The allocation adds an extra element to the official capacity so that
632 // histo_queue->queue[histo_queue->max_size] is read/written within bound. 627 // histo_queue->queue[histo_queue->max_size] is read/written within bound.
633 assert(histo_queue->size <= histo_queue->max_size); 628 assert(histo_queue->size <= histo_queue->max_size);
634 } 629 }
635 630
636 // ----------------------------------------------------------------------------- 631 // -----------------------------------------------------------------------------
637 632
638 static void PreparePair(VP8LHistogram** histograms, int idx1, int idx2, 633 static void PreparePair(VP8LHistogram** histograms, int idx1, int idx2,
639 HistogramPair* const pair, 634 HistogramPair* const pair) {
640 VP8LHistogram* const histos) { 635 VP8LHistogram* h1;
636 VP8LHistogram* h2;
637 double sum_cost;
638
641 if (idx1 > idx2) { 639 if (idx1 > idx2) {
642 const int tmp = idx2; 640 const int tmp = idx2;
643 idx2 = idx1; 641 idx2 = idx1;
644 idx1 = tmp; 642 idx1 = tmp;
645 } 643 }
646 pair->idx1 = idx1; 644 pair->idx1 = idx1;
647 pair->idx2 = idx2; 645 pair->idx2 = idx2;
648 pair->cost_diff = 646 h1 = histograms[idx1];
649 HistogramAddEval(histograms[idx1], histograms[idx2], histos, 0); 647 h2 = histograms[idx2];
650 pair->cost_combo = histos->bit_cost_; 648 sum_cost = h1->bit_cost_ + h2->bit_cost_;
649 pair->cost_combo = 0.;
650 GetCombinedHistogramEntropy(h1, h2, sum_cost, &pair->cost_combo);
651 pair->cost_diff = pair->cost_combo - sum_cost;
651 } 652 }
652 653
653 // Combines histograms by continuously choosing the one with the highest cost 654 // Combines histograms by continuously choosing the one with the highest cost
654 // reduction. 655 // reduction.
655 static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo, 656 static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
656 VP8LHistogram* const histos) {
657 int ok = 0; 657 int ok = 0;
658 int image_histo_size = image_histo->size; 658 int image_histo_size = image_histo->size;
659 int i, j; 659 int i, j;
660 VP8LHistogram** const histograms = image_histo->histograms; 660 VP8LHistogram** const histograms = image_histo->histograms;
661 // Indexes of remaining histograms. 661 // Indexes of remaining histograms.
662 int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters)); 662 int* const clusters = WebPSafeMalloc(image_histo_size, sizeof(*clusters));
663 // Priority queue of histogram pairs. 663 // Priority queue of histogram pairs.
664 HistoQueue histo_queue; 664 HistoQueue histo_queue;
665 665
666 if (!HistoQueueInit(&histo_queue, image_histo_size) || clusters == NULL) { 666 if (!HistoQueueInit(&histo_queue, image_histo_size) || clusters == NULL) {
667 goto End; 667 goto End;
668 } 668 }
669 669
670 for (i = 0; i < image_histo_size; ++i) { 670 for (i = 0; i < image_histo_size; ++i) {
671 // Initialize clusters indexes. 671 // Initialize clusters indexes.
672 clusters[i] = i; 672 clusters[i] = i;
673 for (j = i + 1; j < image_histo_size; ++j) { 673 for (j = i + 1; j < image_histo_size; ++j) {
674 // Initialize positions array. 674 // Initialize positions array.
675 PreparePair(histograms, i, j, &histo_queue.queue[histo_queue.size], 675 PreparePair(histograms, i, j, &histo_queue.queue[histo_queue.size]);
676 histos);
677 UpdateQueueFront(&histo_queue); 676 UpdateQueueFront(&histo_queue);
678 } 677 }
679 } 678 }
680 679
681 while (image_histo_size > 1 && histo_queue.size > 0) { 680 while (image_histo_size > 1 && histo_queue.size > 0) {
682 HistogramPair* copy_to; 681 HistogramPair* copy_to;
683 const int idx1 = histo_queue.queue[0].idx1; 682 const int idx1 = histo_queue.queue[0].idx1;
684 const int idx2 = histo_queue.queue[0].idx2; 683 const int idx2 = histo_queue.queue[0].idx2;
685 VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]); 684 VP8LHistogramAdd(histograms[idx2], histograms[idx1], histograms[idx1]);
686 histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo; 685 histograms[idx1]->bit_cost_ = histo_queue.queue[0].cost_combo;
(...skipping 21 matching lines...) Expand all
708 } 707 }
709 SwapHistogramPairs(copy_to, p); 708 SwapHistogramPairs(copy_to, p);
710 ++copy_to; 709 ++copy_to;
711 } 710 }
712 histo_queue.size = (int)(copy_to - histo_queue.queue); 711 histo_queue.size = (int)(copy_to - histo_queue.queue);
713 712
714 // Push new pairs formed with combined histogram to the queue. 713 // Push new pairs formed with combined histogram to the queue.
715 for (i = 0; i < image_histo_size; ++i) { 714 for (i = 0; i < image_histo_size; ++i) {
716 if (clusters[i] != idx1) { 715 if (clusters[i] != idx1) {
717 PreparePair(histograms, idx1, clusters[i], 716 PreparePair(histograms, idx1, clusters[i],
718 &histo_queue.queue[histo_queue.size], histos); 717 &histo_queue.queue[histo_queue.size]);
719 UpdateQueueFront(&histo_queue); 718 UpdateQueueFront(&histo_queue);
720 } 719 }
721 } 720 }
722 } 721 }
723 // Move remaining histograms to the beginning of the array. 722 // Move remaining histograms to the beginning of the array.
724 for (i = 0; i < image_histo_size; ++i) { 723 for (i = 0; i < image_histo_size; ++i) {
725 if (i != clusters[i]) { // swap the two histograms 724 if (i != clusters[i]) { // swap the two histograms
726 HistogramSwap(&histograms[i], &histograms[clusters[i]]); 725 HistogramSwap(&histograms[i], &histograms[clusters[i]]);
727 } 726 }
728 } 727 }
729 728
730 image_histo->size = image_histo_size; 729 image_histo->size = image_histo_size;
731 ok = 1; 730 ok = 1;
732 731
733 End: 732 End:
734 WebPSafeFree(clusters); 733 WebPSafeFree(clusters);
735 HistoQueueClear(&histo_queue); 734 HistoQueueClear(&histo_queue);
736 return ok; 735 return ok;
737 } 736 }
738 737
739 static VP8LHistogram* HistogramCombineStochastic( 738 static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
740 VP8LHistogramSet* const image_histo, 739 VP8LHistogram* tmp_histo,
741 VP8LHistogram* tmp_histo, 740 VP8LHistogram* best_combo,
742 VP8LHistogram* best_combo, 741 int quality, int min_cluster_size) {
743 int quality, int min_cluster_size) {
744 int iter; 742 int iter;
745 uint32_t seed = 0; 743 uint32_t seed = 0;
746 int tries_with_no_success = 0; 744 int tries_with_no_success = 0;
747 int image_histo_size = image_histo->size; 745 int image_histo_size = image_histo->size;
748 const int iter_mult = (quality < 25) ? 2 : 2 + (quality - 25) / 8; 746 const int iter_mult = (quality < 25) ? 2 : 2 + (quality - 25) / 8;
749 const int outer_iters = image_histo_size * iter_mult; 747 const int outer_iters = image_histo_size * iter_mult;
750 const int num_pairs = image_histo_size / 2; 748 const int num_pairs = image_histo_size / 2;
751 const int num_tries_no_success = outer_iters / 2; 749 const int num_tries_no_success = outer_iters / 2;
752 VP8LHistogram** const histograms = image_histo->histograms; 750 VP8LHistogram** const histograms = image_histo->histograms;
753 751
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after
793 HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]); 791 HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]);
794 histograms[image_histo_size] = NULL; 792 histograms[image_histo_size] = NULL;
795 } 793 }
796 tries_with_no_success = 0; 794 tries_with_no_success = 0;
797 } 795 }
798 if (++tries_with_no_success >= num_tries_no_success) { 796 if (++tries_with_no_success >= num_tries_no_success) {
799 break; 797 break;
800 } 798 }
801 } 799 }
802 image_histo->size = image_histo_size; 800 image_histo->size = image_histo_size;
803 return best_combo;
804 } 801 }
805 802
806 // ----------------------------------------------------------------------------- 803 // -----------------------------------------------------------------------------
807 // Histogram refinement 804 // Histogram refinement
808 805
809 // Find the best 'out' histogram for each of the 'in' histograms. 806 // Find the best 'out' histogram for each of the 'in' histograms.
810 // Note: we assume that out[]->bit_cost_ is already up-to-date. 807 // Note: we assume that out[]->bit_cost_ is already up-to-date.
811 static void HistogramRemap(const VP8LHistogramSet* const orig_histo, 808 static void HistogramRemap(const VP8LHistogramSet* const in,
812 const VP8LHistogramSet* const image_histo, 809 const VP8LHistogramSet* const out,
813 uint16_t* const symbols) { 810 uint16_t* const symbols) {
814 int i; 811 int i;
815 VP8LHistogram** const orig_histograms = orig_histo->histograms; 812 VP8LHistogram** const in_histo = in->histograms;
816 VP8LHistogram** const histograms = image_histo->histograms; 813 VP8LHistogram** const out_histo = out->histograms;
817 const int orig_histo_size = orig_histo->size; 814 const int in_size = in->size;
818 const int image_histo_size = image_histo->size; 815 const int out_size = out->size;
819 if (image_histo_size > 1) { 816 if (out_size > 1) {
820 for (i = 0; i < orig_histo_size; ++i) { 817 for (i = 0; i < in_size; ++i) {
821 int best_out = 0; 818 int best_out = 0;
822 double best_bits = 819 double best_bits = MAX_COST;
823 HistogramAddThresh(histograms[0], orig_histograms[i], MAX_COST);
824 int k; 820 int k;
825 for (k = 1; k < image_histo_size; ++k) { 821 for (k = 0; k < out_size; ++k) {
826 const double cur_bits = 822 const double cur_bits =
827 HistogramAddThresh(histograms[k], orig_histograms[i], best_bits); 823 HistogramAddThresh(out_histo[k], in_histo[i], best_bits);
828 if (cur_bits < best_bits) { 824 if (k == 0 || cur_bits < best_bits) {
829 best_bits = cur_bits; 825 best_bits = cur_bits;
830 best_out = k; 826 best_out = k;
831 } 827 }
832 } 828 }
833 symbols[i] = best_out; 829 symbols[i] = best_out;
834 } 830 }
835 } else { 831 } else {
836 assert(image_histo_size == 1); 832 assert(out_size == 1);
837 for (i = 0; i < orig_histo_size; ++i) { 833 for (i = 0; i < in_size; ++i) {
838 symbols[i] = 0; 834 symbols[i] = 0;
839 } 835 }
840 } 836 }
841 837
842 // Recompute each out based on raw and symbols. 838 // Recompute each out based on raw and symbols.
843 for (i = 0; i < image_histo_size; ++i) { 839 for (i = 0; i < out_size; ++i) {
844 HistogramClear(histograms[i]); 840 HistogramClear(out_histo[i]);
845 } 841 }
846 842
847 for (i = 0; i < orig_histo_size; ++i) { 843 for (i = 0; i < in_size; ++i) {
848 const int idx = symbols[i]; 844 const int idx = symbols[i];
849 VP8LHistogramAdd(orig_histograms[i], histograms[idx], histograms[idx]); 845 VP8LHistogramAdd(in_histo[i], out_histo[idx], out_histo[idx]);
850 } 846 }
851 } 847 }
852 848
853 static double GetCombineCostFactor(int histo_size, int quality) { 849 static double GetCombineCostFactor(int histo_size, int quality) {
854 double combine_cost_factor = 0.16; 850 double combine_cost_factor = 0.16;
855 if (quality < 90) { 851 if (quality < 90) {
856 if (histo_size > 256) combine_cost_factor /= 2.; 852 if (histo_size > 256) combine_cost_factor /= 2.;
857 if (histo_size > 512) combine_cost_factor /= 2.; 853 if (histo_size > 512) combine_cost_factor /= 2.;
858 if (histo_size > 1024) combine_cost_factor /= 2.; 854 if (histo_size > 1024) combine_cost_factor /= 2.;
859 if (quality <= 50) combine_cost_factor /= 2.; 855 if (quality <= 50) combine_cost_factor /= 2.;
(...skipping 53 matching lines...) Expand 10 before | Expand all | Expand 10 after
913 bin_depth, entropy_combine_num_bins, 909 bin_depth, entropy_combine_num_bins,
914 combine_cost_factor, low_effort); 910 combine_cost_factor, low_effort);
915 } 911 }
916 912
917 // Don't combine the histograms using stochastic and greedy heuristics for 913 // Don't combine the histograms using stochastic and greedy heuristics for
918 // low-effort compression mode. 914 // low-effort compression mode.
919 if (!low_effort || !entropy_combine) { 915 if (!low_effort || !entropy_combine) {
920 const float x = quality / 100.f; 916 const float x = quality / 100.f;
921 // cubic ramp between 1 and MAX_HISTO_GREEDY: 917 // cubic ramp between 1 and MAX_HISTO_GREEDY:
922 const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1)); 918 const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
923 cur_combo = HistogramCombineStochastic(image_histo, 919 HistogramCombineStochastic(image_histo, tmp_histos->histograms[0],
924 tmp_histos->histograms[0], 920 cur_combo, quality, threshold_size);
925 cur_combo, quality, threshold_size);
926 if ((image_histo->size <= threshold_size) && 921 if ((image_histo->size <= threshold_size) &&
927 !HistogramCombineGreedy(image_histo, cur_combo)) { 922 !HistogramCombineGreedy(image_histo)) {
928 goto Error; 923 goto Error;
929 } 924 }
930 } 925 }
931 926
932 // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also. 927 // TODO(vikasa): Optimize HistogramRemap for low-effort compression mode also.
933 // Find the optimal map from original histograms to the final ones. 928 // Find the optimal map from original histograms to the final ones.
934 HistogramRemap(orig_histo, image_histo, histogram_symbols); 929 HistogramRemap(orig_histo, image_histo, histogram_symbols);
935 930
936 ok = 1; 931 ok = 1;
937 932
938 Error: 933 Error:
939 WebPSafeFree(bin_map); 934 WebPSafeFree(bin_map);
940 VP8LFreeHistogramSet(orig_histo); 935 VP8LFreeHistogramSet(orig_histo);
941 return ok; 936 return ok;
942 } 937 }
OLDNEW
« no previous file with comments | « third_party/libwebp/enc/filter.c ('k') | third_party/libwebp/enc/near_lossless.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698