anim_diff: add a -raw_comparison flag

If this flag is not used, RGB is premultiplied before comparison.
Otherwise, the raw R/G/B values are compared, which can be a problem
in transparent area (alpha=0 R/G/B=anything)

Change-Id: I131cc10ec92414ad508b81f599a60d0097cac470
This commit is contained in:
Pascal Massimino 2015-07-07 22:45:49 +00:00 committed by James Zern
parent 155c1b222b
commit acb297e9c2
3 changed files with 40 additions and 12 deletions

View File

@ -37,6 +37,7 @@ bool CompareValues(T a, T b, const std::string& output_str) {
// is OK for other aspects like offsets, dispose/blend method to vary. // is OK for other aspects like offsets, dispose/blend method to vary.
bool CompareAnimatedImagePair(const AnimatedImage& img1, bool CompareAnimatedImagePair(const AnimatedImage& img1,
const AnimatedImage& img2, const AnimatedImage& img2,
bool premultiply,
double min_psnr) { double min_psnr) {
bool ok = true; bool ok = true;
ok = CompareValues(img1.canvas_width, img2.canvas_width, ok = CompareValues(img1.canvas_width, img2.canvas_width,
@ -68,7 +69,7 @@ bool CompareAnimatedImagePair(const AnimatedImage& img1,
int max_diff; int max_diff;
double psnr; double psnr;
GetDiffAndPSNR(rgba1, rgba2, img1.canvas_width, img1.canvas_height, GetDiffAndPSNR(rgba1, rgba2, img1.canvas_width, img1.canvas_height,
&max_diff, &psnr); premultiply, &max_diff, &psnr);
if (min_psnr > 0.) { if (min_psnr > 0.) {
if (psnr < min_psnr) { if (psnr < min_psnr) {
fprintf(stderr, "Frame #%zu, psnr = %.2lf (min_psnr = %f)\n", i, fprintf(stderr, "Frame #%zu, psnr = %.2lf (min_psnr = %f)\n", i,
@ -87,7 +88,7 @@ bool CompareAnimatedImagePair(const AnimatedImage& img1,
void Help() { void Help() {
printf("\nUsage: anim_diff <image1> <image2> [-dump_frames <folder>] " printf("\nUsage: anim_diff <image1> <image2> [-dump_frames <folder>] "
"[-min_psnr <float>]\n"); "[-min_psnr <float>][-raw_comparison]\n");
} }
} // namespace } // namespace
@ -98,6 +99,7 @@ int main(int argc, const char* argv[]) {
double min_psnr = 0.; double min_psnr = 0.;
bool got_input1 = false; bool got_input1 = false;
bool got_input2 = false; bool got_input2 = false;
bool premultiply = true;
const char* files[2]; const char* files[2];
if (argc < 3) { if (argc < 3) {
@ -127,6 +129,8 @@ int main(int argc, const char* argv[]) {
} else { } else {
parse_error = true; parse_error = true;
} }
} else if (!strcmp(argv[c], "-raw_comparison")) {
premultiply = false;
} else { } else {
if (!got_input1) { if (!got_input1) {
files[0] = argv[c]; files[0] = argv[c];
@ -161,7 +165,8 @@ int main(int argc, const char* argv[]) {
} }
} }
if (!CompareAnimatedImagePair(images[0], images[1], min_psnr)) { if (!CompareAnimatedImagePair(images[0], images[1],
premultiply, min_psnr)) {
fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]); fprintf(stderr, "\nFiles %s and %s differ.\n", files[0], files[1]);
return -3; return -3;
} }

View File

@ -815,20 +815,41 @@ bool ReadAnimatedImage(const char filename[], AnimatedImage* const image,
} }
} }
static void Accumulate(double v1, double v2, double* const max_diff,
double* const sse) {
const double diff = fabs(v1 - v2);
if (diff > *max_diff) *max_diff = diff;
*sse += diff * diff;
}
void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
uint32_t width, uint32_t height, int* const max_diff, uint32_t width, uint32_t height, bool premultiply,
double* const psnr) { int* const max_diff, double* const psnr) {
const uint32_t stride = width * kNumChannels; const uint32_t stride = width * kNumChannels;
*max_diff = 0; const int kAlphaChannel = kNumChannels - 1;
double f_max_diff = 0.;
double sse = 0.; double sse = 0.;
for (uint32_t y = 0; y < height; ++y) { for (uint32_t y = 0; y < height; ++y) {
for (uint32_t x = 0; x < stride; ++x) { for (uint32_t x = 0; x < stride; x += kNumChannels) {
const size_t offset = y * stride + x; const size_t offset = y * stride + x;
const int diff = abs(rgba1[offset] - rgba2[offset]); const int alpha1 = rgba1[offset + kAlphaChannel];
if (diff > *max_diff) *max_diff = diff; const int alpha2 = rgba2[offset + kAlphaChannel];
sse += diff * diff; Accumulate(alpha1, alpha2, &f_max_diff, &sse);
if (!premultiply) {
for (int k = 0; k < kAlphaChannel; ++k) {
Accumulate(rgba1[offset + k], rgba2[offset + k], &f_max_diff, &sse);
}
} else {
// premultiply R/G/B channels with alpha value
for (int k = 0; k < kAlphaChannel; ++k) {
Accumulate(rgba1[offset + k] * alpha1 / 255.,
rgba2[offset + k] * alpha2 / 255.,
&f_max_diff, &sse);
}
}
} }
} }
*max_diff = static_cast<int>(f_max_diff);
if (*max_diff == 0) { if (*max_diff == 0) {
*psnr = 99.; // PSNR when images are identical. *psnr = 99.; // PSNR when images are identical.
} else { } else {

View File

@ -40,8 +40,10 @@ bool ReadAnimatedImage(const char filename[], AnimatedImage* const image,
bool dump_frames, const char dump_folder[]); bool dump_frames, const char dump_folder[]);
// Given two RGBA buffers, calculate max pixel difference and PSNR. // Given two RGBA buffers, calculate max pixel difference and PSNR.
// If 'premultiply' is true, R/G/B values will be pre-multiplied by the
// transparency before comparison.
void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[], void GetDiffAndPSNR(const uint8_t rgba1[], const uint8_t rgba2[],
uint32_t width, uint32_t height, int* const max_diff, uint32_t width, uint32_t height, bool premultiply,
double* const psnr); int* const max_diff, double* const psnr);
#endif // WEBP_EXAMPLES_ANIM_UTIL_H_ #endif // WEBP_EXAMPLES_ANIM_UTIL_H_