+
+static
+double
+rms_error (boost::filesystem::path ref, boost::filesystem::path check)
+{
+ FFmpegImageProxy ref_proxy (ref);
+ auto ref_image = ref_proxy.image(Image::Alignment::COMPACT).image;
+ FFmpegImageProxy check_proxy (check);
+ auto check_image = check_proxy.image(Image::Alignment::COMPACT).image;
+
+ BOOST_REQUIRE_EQUAL (ref_image->pixel_format(), check_image->pixel_format());
+ AVPixelFormat const format = ref_image->pixel_format();
+
+ BOOST_REQUIRE (ref_image->size() == check_image->size());
+ int const width = ref_image->size().width;
+ int const height = ref_image->size().height;
+
+ double sum_square = 0;
+ switch (format) {
+ case AV_PIX_FMT_RGBA:
+ {
+ for (int y = 0; y < height; ++y) {
+ uint8_t* p = ref_image->data()[0] + y * ref_image->stride()[0];
+ uint8_t* q = check_image->data()[0] + y * check_image->stride()[0];
+ for (int x = 0; x < width; ++x) {
+ for (int c = 0; c < 4; ++c) {
+ sum_square += pow((*p++ - *q++), 2);
+ }
+ }
+ }
+ break;
+ }
+ case AV_PIX_FMT_RGB24:
+ {
+ for (int y = 0; y < height; ++y) {
+ uint8_t* p = ref_image->data()[0] + y * ref_image->stride()[0];
+ uint8_t* q = check_image->data()[0] + y * check_image->stride()[0];
+ for (int x = 0; x < width; ++x) {
+ for (int c = 0; c < 3; ++c) {
+ sum_square += pow((*p++ - *q++), 2);
+ }
+ }
+ }
+ break;
+ }
+ case AV_PIX_FMT_RGB48BE:
+ {
+ for (int y = 0; y < height; ++y) {
+ uint16_t* p = reinterpret_cast<uint16_t*>(ref_image->data()[0] + y * ref_image->stride()[0]);
+ uint16_t* q = reinterpret_cast<uint16_t*>(check_image->data()[0] + y * check_image->stride()[0]);
+ for (int x = 0; x < width; ++x) {
+ for (int c = 0; c < 3; ++c) {
+ sum_square += pow((*p++ - *q++), 2);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ BOOST_REQUIRE_MESSAGE (false, "unrecognised pixel format " << format);
+ }
+
+ return sqrt(sum_square / (height * width));
+}
+
+
+BOOST_AUTO_TEST_CASE (rms_error_test)
+{
+ BOOST_CHECK_CLOSE (rms_error("test/data/check_image0.png", "test/data/check_image0.png"), 0, 0.001);
+ BOOST_CHECK_CLOSE (rms_error("test/data/check_image0.png", "test/data/check_image1.png"), 2.2778, 0.001);
+ BOOST_CHECK_CLOSE (rms_error("test/data/check_image0.png", "test/data/check_image2.png"), 59.8896, 0.001);
+ BOOST_CHECK_CLOSE (rms_error("test/data/check_image0.png", "test/data/check_image3.png"), 0.89164, 0.001);
+}
+
+
+void
+check_image (boost::filesystem::path ref, boost::filesystem::path check, double threshold)
+{
+ double const e = rms_error (ref, check);
+ BOOST_CHECK_MESSAGE (e < threshold, ref << " differs from " << check << " " << e);
+}
+
+