mirror of
				https://github.com/webmproject/libwebp.git
				synced 2025-10-30 18:05:36 +01:00 
			
		
		
		
	Fix FindClosestDiscretized in near lossless:
- The result is now indeed closest among possible results for all inputs, which was not the case for bits>4, where the mapping was not even monotonic because GetValAndDistance was correct only if the significant part of initial fit in a byte at most twice. - The set of results for a larger number of bits dropped is a subset of values for a smaller number of bits dropped. This implies that subsequent discretizations for a smaller number of bits dropped do not change already discretized pixels, which improves the quality (changes do not accumulate) and compression density (values tend to repeat more often). - Errors are more fairly distributed between upwards and downwards thanks to bankers’ rounding, which avoids images getting darker or lighter in overall. - Deltas between discretized values are more repetitive. This improves compression density if delta encoding is used. Also, the implementation is much shorter now. Change-Id: I0a98e7d5255e91a7b9c193a156cf5405d9701f16
This commit is contained in:
		
				
					committed by
					
						 Pascal Massimino
						Pascal Massimino
					
				
			
			
				
	
			
			
			
						parent
						
							8200643017
						
					
				
				
					commit
					e8feb20e39
				
			| @@ -14,6 +14,7 @@ | ||||
| // Author: Jyrki Alakuijala (jyrki@google.com) | ||||
| // Converted to C by Aleksander Kramarz (akramarz@google.com) | ||||
|  | ||||
| #include <assert.h> | ||||
| #include <stdlib.h> | ||||
|  | ||||
| #include "../dsp/lossless.h" | ||||
| @@ -23,42 +24,14 @@ | ||||
| #define MIN_DIM_FOR_NEAR_LOSSLESS 64 | ||||
| #define MAX_LIMIT_BITS             5 | ||||
|  | ||||
| // Computes quantized pixel value and distance from original value. | ||||
| static void GetValAndDistance(int a, int initial, int bits, | ||||
|                               int* const val, int* const distance) { | ||||
|   const int mask = ~((1 << bits) - 1); | ||||
|   *val = (initial & mask) | (initial >> (8 - bits)); | ||||
|   *distance = 2 * abs(a - *val); | ||||
| } | ||||
|  | ||||
| // Clamps the value to range [0, 255]. | ||||
| static int Clamp8b(int val) { | ||||
|   const int min_val = 0; | ||||
|   const int max_val = 0xff; | ||||
|   return (val < min_val) ? min_val : (val > max_val) ? max_val : val; | ||||
| } | ||||
|  | ||||
| // Quantizes values {a, a+(1<<bits), a-(1<<bits)} and returns the nearest one. | ||||
| // Quantizes the value up or down to a multiple of 1<<bits (or to 255), | ||||
| // choosing the closer one, resolving ties using bankers' rounding. | ||||
| static int FindClosestDiscretized(int a, int bits) { | ||||
|   int best_val = a, i; | ||||
|   int min_distance = 256; | ||||
|  | ||||
|   for (i = -1; i <= 1; ++i) { | ||||
|     int candidate, distance; | ||||
|     const int val = Clamp8b(a + i * (1 << bits)); | ||||
|     GetValAndDistance(a, val, bits, &candidate, &distance); | ||||
|     if (i != 0) { | ||||
|       ++distance; | ||||
|     } | ||||
|     // Smallest distance but favor i == 0 over i == -1 and i == 1 | ||||
|     // since that keeps the overall intensity more constant in the | ||||
|     // images. | ||||
|     if (distance < min_distance) { | ||||
|       min_distance = distance; | ||||
|       best_val = candidate; | ||||
|     } | ||||
|   } | ||||
|   return best_val; | ||||
|   const int mask = (1 << bits) - 1; | ||||
|   const int biased = a + (mask >> 1) + ((a >> bits) & 1); | ||||
|   assert(bits > 0); | ||||
|   if (biased > 0xff) return 0xff; | ||||
|   return biased & ~mask; | ||||
| } | ||||
|  | ||||
| // Applies FindClosestDiscretized to all channels of pixel. | ||||
|   | ||||
		Reference in New Issue
	
	Block a user