add a -dither dithering option to the decoder

Even at high quality setting, the U/V quantizer step is limited
to 4 which can lead to banding on gradient.
This option allows to selectively apply some randomness to
potentially flattened-out U/V blocks and attenuate the banding.

This option is off by default in 'dwebp', but set to -dither 50
by default in 'vwebp'.

Note: depending on the number of blocks selectively dithered,
we can have up to a 10% slow-down in decoding speed it seems.

Change-Id: Icc2446007f33ddacb60b3a80a9e63f2d5ad162de
This commit is contained in:
skal
2013-11-26 22:59:02 +01:00
committed by Pascal Massimino
parent e812401299
commit cbdd3e6e53
11 changed files with 138 additions and 11 deletions

View File

@ -34,8 +34,10 @@ typedef struct {
void VP8InitRandom(VP8Random* const rg, float dithering);
// Returns a centered pseudo-random number with 'num_bits' amplitude.
// (uses D.Knuth's Difference-based random generator)
static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
// (uses D.Knuth's Difference-based random generator).
// 'amp' is in VP8_RANDOM_DITHER_FIX fixed-point precision.
static WEBP_INLINE int VP8RandomBits2(VP8Random* const rg, int num_bits,
int amp) {
int diff;
assert(num_bits + VP8_RANDOM_DITHER_FIX <= 31);
diff = rg->tab_[rg->index1_] - rg->tab_[rg->index2_];
@ -43,12 +45,16 @@ static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
rg->tab_[rg->index1_] = diff;
if (++rg->index1_ == VP8_RANDOM_TABLE_SIZE) rg->index1_ = 0;
if (++rg->index2_ == VP8_RANDOM_TABLE_SIZE) rg->index2_ = 0;
diff = (diff << 1) >> (32 - num_bits); // sign-extend, 0-center
diff = (diff * rg->amp_) >> VP8_RANDOM_DITHER_FIX; // restrict range
diff += 1 << (num_bits - 1); // shift back to 0.5-center
diff = (diff << 1) >> (32 - num_bits); // sign-extend, 0-center
diff = (diff * amp) >> VP8_RANDOM_DITHER_FIX; // restrict range
diff += 1 << (num_bits - 1); // shift back to 0.5-center
return diff;
}
static WEBP_INLINE int VP8RandomBits(VP8Random* const rg, int num_bits) {
return VP8RandomBits2(rg, num_bits, rg->amp_);
}
#if defined(__cplusplus) || defined(c_plusplus)
} // extern "C"
#endif