make QuantizeLevels() store the sum of squared error

(instead of MSE).
Useful for directly storing the alpha-PSNR (in another patch)

Change-Id: I4072864f9c53eb4f38366e8025a2816eb14f504e
This commit is contained in:
Pascal Massimino 2012-07-23 14:26:56 -07:00
parent 5955cf5e89
commit d39177b74c
2 changed files with 13 additions and 22 deletions

View File

@ -11,7 +11,6 @@
// Author: Skal (pascal.massimino@gmail.com) // Author: Skal (pascal.massimino@gmail.com)
#include <assert.h> #include <assert.h>
#include <math.h> // for sqrt()
#include "./quant_levels.h" #include "./quant_levels.h"
@ -27,8 +26,8 @@ extern "C" {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// Quantize levels. // Quantize levels.
int QuantizeLevels(uint8_t* data, int width, int height, int QuantizeLevels(uint8_t* const data, int width, int height,
int num_levels, float* mse) { int num_levels, uint64_t* const sse) {
int freq[NUM_SYMBOLS] = { 0 }; int freq[NUM_SYMBOLS] = { 0 };
int q_level[NUM_SYMBOLS] = { 0 }; int q_level[NUM_SYMBOLS] = { 0 };
double inv_q_level[NUM_SYMBOLS] = { 0 }; double inv_q_level[NUM_SYMBOLS] = { 0 };
@ -36,6 +35,7 @@ int QuantizeLevels(uint8_t* data, int width, int height,
const size_t data_size = height * width; const size_t data_size = height * width;
int i, num_levels_in, iter; int i, num_levels_in, iter;
double last_err = 1.e38, err = 0.; double last_err = 1.e38, err = 0.;
const double err_threshold = ERROR_THRESHOLD * data_size;
if (data == NULL) { if (data == NULL) {
return 0; return 0;
@ -60,10 +60,7 @@ int QuantizeLevels(uint8_t* data, int width, int height,
} }
} }
if (num_levels_in <= num_levels) { if (num_levels_in <= num_levels) goto End; // nothing to do!
if (mse) *mse = 0.;
return 1; // nothing to do !
}
// Start with uniformly spread centroids. // Start with uniformly spread centroids.
for (i = 0; i < num_levels; ++i) { for (i = 0; i < num_levels; ++i) {
@ -78,7 +75,6 @@ int QuantizeLevels(uint8_t* data, int width, int height,
// k-Means iterations. // k-Means iterations.
for (iter = 0; iter < MAX_ITER; ++iter) { for (iter = 0; iter < MAX_ITER; ++iter) {
double err_count;
double q_sum[NUM_SYMBOLS] = { 0 }; double q_sum[NUM_SYMBOLS] = { 0 };
double q_count[NUM_SYMBOLS] = { 0 }; double q_count[NUM_SYMBOLS] = { 0 };
int s, slot = 0; int s, slot = 0;
@ -109,17 +105,14 @@ int QuantizeLevels(uint8_t* data, int width, int height,
// Compute convergence error. // Compute convergence error.
err = 0.; err = 0.;
err_count = 0.;
for (s = min_s; s <= max_s; ++s) { for (s = min_s; s <= max_s; ++s) {
const double error = s - inv_q_level[q_level[s]]; const double error = s - inv_q_level[q_level[s]];
err += freq[s] * error * error; err += freq[s] * error * error;
err_count += freq[s];
} }
if (err_count > 0.) err /= err_count;
// Check for convergence: we stop as soon as the error is no // Check for convergence: we stop as soon as the error is no
// longer improving. // longer improving.
if (last_err - err < ERROR_THRESHOLD) break; if (last_err - err < err_threshold) break;
last_err = err; last_err = err;
} }
@ -140,16 +133,14 @@ int QuantizeLevels(uint8_t* data, int width, int height,
data[n] = map[data[n]]; data[n] = map[data[n]];
} }
} }
End:
// Compute final mean squared error if needed. // Store sum of squared error if needed.
if (mse != NULL) { if (sse != NULL) *sse = (uint64_t)err;
*mse = (float)sqrt(err);
}
return 1; return 1;
} }
int DequantizeLevels(uint8_t* data, int width, int height) { int DequantizeLevels(uint8_t* const data, int width, int height) {
if (data == NULL || width <= 0 || height <= 0) return 0; if (data == NULL || width <= 0 || height <= 0) return 0;
// TODO(skal): implement gradient smoothing. // TODO(skal): implement gradient smoothing.
(void)data; (void)data;

View File

@ -21,16 +21,16 @@ extern "C" {
#endif #endif
// Replace the input 'data' of size 'width'x'height' with 'num-levels' // Replace the input 'data' of size 'width'x'height' with 'num-levels'
// quantized values. If not NULL, 'mse' will contain the mean-squared error. // quantized values. If not NULL, 'sse' will contain the sum of squared error.
// Valid range for 'num_levels' is [2, 256]. // Valid range for 'num_levels' is [2, 256].
// Returns false in case of error (data is NULL, or parameters are invalid). // Returns false in case of error (data is NULL, or parameters are invalid).
int QuantizeLevels(uint8_t* data, int width, int height, int num_levels, int QuantizeLevels(uint8_t* const data, int width, int height, int num_levels,
float* mse); uint64_t* const sse);
// Apply post-processing to input 'data' of size 'width'x'height' assuming // Apply post-processing to input 'data' of size 'width'x'height' assuming
// that the source was quantized to a reduced number of levels. // that the source was quantized to a reduced number of levels.
// Returns false in case of error (data is NULL, invalid parameters, ...). // Returns false in case of error (data is NULL, invalid parameters, ...).
int DequantizeLevels(uint8_t* data, int width, int height); int DequantizeLevels(uint8_t* const data, int width, int height);
#if defined(__cplusplus) || defined(c_plusplus) #if defined(__cplusplus) || defined(c_plusplus)
} // extern "C" } // extern "C"