diff --git a/examples/anim_diff.cc b/examples/anim_diff.cc index b360e38d..9e624a3d 100644 --- a/examples/anim_diff.cc +++ b/examples/anim_diff.cc @@ -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. bool CompareAnimatedImagePair(const AnimatedImage& img1, const AnimatedImage& img2, + bool premultiply, double min_psnr) { bool ok = true; ok = CompareValues(img1.canvas_width, img2.canvas_width, @@ -68,7 +69,7 @@ bool CompareAnimatedImagePair(const AnimatedImage& img1, int max_diff; double psnr; GetDiffAndPSNR(rgba1, rgba2, img1.canvas_width, img1.canvas_height, - &max_diff, &psnr); + premultiply, &max_diff, &psnr); if (min_psnr > 0.) { if (psnr < min_psnr) { fprintf(stderr, "Frame #%zu, psnr = %.2lf (min_psnr = %f)\n", i, @@ -87,7 +88,7 @@ bool CompareAnimatedImagePair(const AnimatedImage& img1, void Help() { printf("\nUsage: anim_diff [-dump_frames ] " - "[-min_psnr ]\n"); + "[-min_psnr ][-raw_comparison]\n"); } } // namespace @@ -98,6 +99,7 @@ int main(int argc, const char* argv[]) { double min_psnr = 0.; bool got_input1 = false; bool got_input2 = false; + bool premultiply = true; const char* files[2]; if (argc < 3) { @@ -127,6 +129,8 @@ int main(int argc, const char* argv[]) { } else { parse_error = true; } + } else if (!strcmp(argv[c], "-raw_comparison")) { + premultiply = false; } else { if (!got_input1) { 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]); return -3; } diff --git a/examples/anim_util.cc b/examples/anim_util.cc index 89795843..92f7132f 100644 --- a/examples/anim_util.cc +++ b/examples/anim_util.cc @@ -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[], - uint32_t width, uint32_t height, int* const max_diff, - double* const psnr) { + uint32_t width, uint32_t height, bool premultiply, + int* const max_diff, double* const psnr) { const uint32_t stride = width * kNumChannels; - *max_diff = 0; + const int kAlphaChannel = kNumChannels - 1; + double f_max_diff = 0.; double sse = 0.; 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 int diff = abs(rgba1[offset] - rgba2[offset]); - if (diff > *max_diff) *max_diff = diff; - sse += diff * diff; + const int alpha1 = rgba1[offset + kAlphaChannel]; + const int alpha2 = rgba2[offset + kAlphaChannel]; + 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(f_max_diff); if (*max_diff == 0) { *psnr = 99.; // PSNR when images are identical. } else { diff --git a/examples/anim_util.h b/examples/anim_util.h index 61083c5e..6b5b35d2 100644 --- a/examples/anim_util.h +++ b/examples/anim_util.h @@ -40,8 +40,10 @@ bool ReadAnimatedImage(const char filename[], AnimatedImage* const image, bool dump_frames, const char dump_folder[]); // 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[], - uint32_t width, uint32_t height, int* const max_diff, - double* const psnr); + uint32_t width, uint32_t height, bool premultiply, + int* const max_diff, double* const psnr); #endif // WEBP_EXAMPLES_ANIM_UTIL_H_