mirror of
https://github.com/webmproject/libwebp.git
synced 2024-12-27 06:08:21 +01:00
Perform greedy histogram merge in a unified way.
Previously, the stochastic method for histogram combination could finish in a greedy way if the number of iterations to perform so was smaller. Except that another greedy combination was performed afterwards ... hence wasted CPU in some cases. Change-Id: Ic0f26873e6dc746679486b91cb35d73efee91931
This commit is contained in:
parent
5b393f2d2a
commit
868aa6901f
@ -777,10 +777,13 @@ static int HistogramCombineGreedy(VP8LHistogramSet* const image_histo) {
|
|||||||
return ok;
|
return ok;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Perform histogram aggregation using a stochastic approach.
|
||||||
|
// 'do_greedy' is set to 1 if a greedy approach needs to be performed
|
||||||
|
// afterwards, 0 otherwise.
|
||||||
static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
||||||
VP8LHistogram* tmp_histo,
|
VP8LHistogram* tmp_histo,
|
||||||
VP8LHistogram* best_combo,
|
VP8LHistogram* best_combo, int quality,
|
||||||
int quality, int min_cluster_size) {
|
int min_cluster_size, int* do_greedy) {
|
||||||
int iter;
|
int iter;
|
||||||
uint32_t seed = 0;
|
uint32_t seed = 0;
|
||||||
int tries_with_no_success = 0;
|
int tries_with_no_success = 0;
|
||||||
@ -789,48 +792,44 @@ static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
|||||||
const int outer_iters = image_histo_size * iter_mult;
|
const int outer_iters = image_histo_size * iter_mult;
|
||||||
const int num_pairs = image_histo_size / 2;
|
const int num_pairs = image_histo_size / 2;
|
||||||
const int num_tries_no_success = outer_iters / 2;
|
const int num_tries_no_success = outer_iters / 2;
|
||||||
int idx2_max = image_histo_size - 1;
|
|
||||||
int do_brute_dorce = 0;
|
|
||||||
VP8LHistogram** const histograms = image_histo->histograms;
|
VP8LHistogram** const histograms = image_histo->histograms;
|
||||||
|
|
||||||
// Collapse similar histograms in 'image_histo'.
|
// Collapse similar histograms in 'image_histo'.
|
||||||
|
*do_greedy = (image_histo->size <= min_cluster_size);
|
||||||
++min_cluster_size;
|
++min_cluster_size;
|
||||||
for (iter = 0;
|
for (iter = 0; iter < outer_iters && image_histo_size >= min_cluster_size &&
|
||||||
iter < outer_iters && image_histo_size >= min_cluster_size;
|
++tries_with_no_success < num_tries_no_success;
|
||||||
++iter) {
|
++iter) {
|
||||||
double best_cost_diff = 0.;
|
double best_cost_diff = 0.;
|
||||||
int best_idx1 = -1, best_idx2 = 1;
|
int best_idx1 = -1, best_idx2 = 1;
|
||||||
int j;
|
int j;
|
||||||
int num_tries =
|
int num_tries =
|
||||||
(num_pairs < image_histo_size) ? num_pairs : image_histo_size;
|
(num_pairs < image_histo_size) ? num_pairs : image_histo_size;
|
||||||
// Use a brute force approach if:
|
// If the stochastic method has not worked for a while (10 iterations) and
|
||||||
// - stochastic has not worked for a while and
|
// if it requires less iterations to finish off with a greedy approach, go
|
||||||
// - if the number of iterations for brute force is less than the number of
|
// for it.
|
||||||
// iterations if we never find a match ever again stochastically (hence
|
// With the greedy approach, each histogram is compared to the other ones,
|
||||||
// num_tries times the number of remaining outer iterations).
|
// hence (image_histo_size-1)*image_histo_size/2 overall comparisons.
|
||||||
do_brute_dorce =
|
// Then, at each iteration, the best pair is merged and compared to all
|
||||||
(tries_with_no_success > 10) &&
|
// the other ones, adding (image_histo_size-2)*(image_histo_size-1)/2 more
|
||||||
(idx2_max * (idx2_max + 1) < 2 * num_tries * (outer_iters - iter));
|
// comparisons. Overall: (image_histo_size-1)^2 comparisons.
|
||||||
if (do_brute_dorce) num_tries = idx2_max;
|
*do_greedy |= (tries_with_no_success > 10) &&
|
||||||
|
((image_histo_size - 1) * (image_histo_size - 1) <
|
||||||
|
num_tries * (outer_iters - iter));
|
||||||
|
if (*do_greedy) break;
|
||||||
|
|
||||||
seed += iter;
|
seed += iter;
|
||||||
for (j = 0; j < num_tries; ++j) {
|
for (j = 0; j < num_tries; ++j) {
|
||||||
double curr_cost_diff;
|
double curr_cost_diff;
|
||||||
// Choose two histograms at random and try to combine them.
|
// Choose two histograms at random and try to combine them.
|
||||||
uint32_t idx1, idx2;
|
uint32_t idx1, idx2;
|
||||||
if (do_brute_dorce) {
|
const uint32_t tmp = (j & 7) + 1;
|
||||||
// Use a brute force approach.
|
const uint32_t diff =
|
||||||
idx1 = (uint32_t)j;
|
(tmp < 3) ? tmp : MyRand(&seed) % (image_histo_size - 1);
|
||||||
idx2 = (uint32_t)idx2_max;
|
idx1 = MyRand(&seed) % image_histo_size;
|
||||||
} else {
|
idx2 = (idx1 + diff + 1) % image_histo_size;
|
||||||
const uint32_t tmp = (j & 7) + 1;
|
if (idx1 == idx2) {
|
||||||
const uint32_t diff =
|
continue;
|
||||||
(tmp < 3) ? tmp : MyRand(&seed) % (image_histo_size - 1);
|
|
||||||
idx1 = MyRand(&seed) % image_histo_size;
|
|
||||||
idx2 = (idx1 + diff + 1) % image_histo_size;
|
|
||||||
if (idx1 == idx2) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate cost reduction on combining.
|
// Calculate cost reduction on combining.
|
||||||
@ -843,24 +842,20 @@ static void HistogramCombineStochastic(VP8LHistogramSet* const image_histo,
|
|||||||
best_idx2 = idx2;
|
best_idx2 = idx2;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (do_brute_dorce) --idx2_max;
|
|
||||||
|
|
||||||
if (best_idx1 >= 0) {
|
if (best_idx1 >= 0) {
|
||||||
HistogramSwap(&best_combo, &histograms[best_idx1]);
|
HistogramSwap(&best_combo, &histograms[best_idx1]);
|
||||||
// swap best_idx2 slot with last one (which is now unused)
|
// swap best_idx2 slot with last one (which is now unused)
|
||||||
--image_histo_size;
|
--image_histo_size;
|
||||||
if (idx2_max >= image_histo_size) idx2_max = image_histo_size - 1;
|
|
||||||
if (best_idx2 != image_histo_size) {
|
if (best_idx2 != image_histo_size) {
|
||||||
HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]);
|
HistogramSwap(&histograms[image_histo_size], &histograms[best_idx2]);
|
||||||
histograms[image_histo_size] = NULL;
|
histograms[image_histo_size] = NULL;
|
||||||
}
|
}
|
||||||
tries_with_no_success = 0;
|
tries_with_no_success = 0;
|
||||||
}
|
}
|
||||||
if (++tries_with_no_success >= num_tries_no_success || idx2_max == 0) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
image_histo->size = image_histo_size;
|
image_histo->size = image_histo_size;
|
||||||
|
*do_greedy |= (image_histo->size <= min_cluster_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
// -----------------------------------------------------------------------------
|
// -----------------------------------------------------------------------------
|
||||||
@ -970,10 +965,10 @@ int VP8LGetHistoImageSymbols(int xsize, int ysize,
|
|||||||
const float x = quality / 100.f;
|
const float x = quality / 100.f;
|
||||||
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
// cubic ramp between 1 and MAX_HISTO_GREEDY:
|
||||||
const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
|
const int threshold_size = (int)(1 + (x * x * x) * (MAX_HISTO_GREEDY - 1));
|
||||||
|
int do_greedy;
|
||||||
HistogramCombineStochastic(image_histo, tmp_histos->histograms[0],
|
HistogramCombineStochastic(image_histo, tmp_histos->histograms[0],
|
||||||
cur_combo, quality, threshold_size);
|
cur_combo, quality, threshold_size, &do_greedy);
|
||||||
if ((image_histo->size <= threshold_size) &&
|
if (do_greedy && !HistogramCombineGreedy(image_histo)) {
|
||||||
!HistogramCombineGreedy(image_histo)) {
|
|
||||||
goto Error;
|
goto Error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user