diff --git a/src/Magnum/DebugTools/CompareImage.cpp b/src/Magnum/DebugTools/CompareImage.cpp index 88ad04395a..d4c67ff8fd 100644 --- a/src/Magnum/DebugTools/CompareImage.cpp +++ b/src/Magnum/DebugTools/CompareImage.cpp @@ -52,7 +52,11 @@ namespace Magnum { namespace DebugTools { namespace Implementation { namespace { -template Float calculateImageDelta(const Containers::StridedArrayView2D>& actual, const Containers::StridedArrayView2D>& expected, const Containers::StridedArrayView2D& output) { +/* There's a separate implementation for integral types, as those don't need + any additional logic for handling NaN and infinity values, allowing the + comparison to be much simpler & faster. */ + +template::value, int>::type = 0> Float calculateImageDelta(const Containers::StridedArrayView2D>& actual, const Containers::StridedArrayView2D>& expected, const Containers::StridedArrayView2D& output) { CORRADE_INTERNAL_ASSERT(actual.size() == output.size()); CORRADE_INTERNAL_ASSERT(output.size() == expected.size()); @@ -93,6 +97,31 @@ template Float calculateImageDelta(const Containers:: return max; } +template::value, int>::type = 0> Float calculateImageDelta(const Containers::StridedArrayView2D>& actual, const Containers::StridedArrayView2D>& expected, const Containers::StridedArrayView2D& output) { + CORRADE_INTERNAL_ASSERT(actual.size() == output.size()); + CORRADE_INTERNAL_ASSERT(output.size() == expected.size()); + + /* Calculate deltas and maximal value of them */ + Float max{}; + for(std::size_t i = 0, iMax = expected.size()[0]; i != iMax; ++i) { + Containers::StridedArrayView1D> actualRow = actual[i]; + Containers::StridedArrayView1D> expectedRow = expected[i]; + Containers::StridedArrayView1D outputRow = output[i]; + + for(std::size_t j = 0, jMax = expectedRow.size(); j != jMax; ++j) { + /* Explicitly convert from T to Float */ + auto actualPixel = Math::Vector(actualRow[j]); + auto expectedPixel = Math::Vector(expectedRow[j]); + + Math::Vector diff = Math::abs(actualPixel - expectedPixel); + outputRow[j] = diff.sum()/size; + max = Math::max(max, outputRow[j]); + } + } + + return max; +} + } Containers::Triple, Float, Float> calculateImageDelta(const PixelFormat actualFormat, const Containers::StridedArrayView3D& actualPixels, const ImageView2D& expected) { diff --git a/src/Magnum/DebugTools/Test/CompareImageTest.cpp b/src/Magnum/DebugTools/Test/CompareImageTest.cpp index 6cfd8bc129..0dc09988ec 100644 --- a/src/Magnum/DebugTools/Test/CompareImageTest.cpp +++ b/src/Magnum/DebugTools/Test/CompareImageTest.cpp @@ -60,6 +60,7 @@ struct CompareImageTest: TestSuite::Tester { void formatImplementationSpecific(); void calculateDelta(); + void calculateDeltaInteger(); void calculateDeltaStorage(); void calculateDeltaSpecials(); void calculateDeltaSpecials3(); @@ -132,6 +133,7 @@ CompareImageTest::CompareImageTest() { &CompareImageTest::formatImplementationSpecific, &CompareImageTest::calculateDelta, + &CompareImageTest::calculateDeltaInteger, &CompareImageTest::calculateDeltaStorage, &CompareImageTest::calculateDeltaSpecials, &CompareImageTest::calculateDeltaSpecials3, @@ -289,6 +291,38 @@ void CompareImageTest::calculateDelta() { CORRADE_COMPARE(deltaMaxMean.third(), 0.208889f); } +void CompareImageTest::calculateDeltaInteger() { + /* Like ActualRedData, ExpectedRedData and DeltaRed, just multiplied 100 + times and saved into a Short */ + const Short actualRedData[]{ + 30, 100, 90, + 90, 60, 20, + -10, 100, 0 + }; + + const Short expectedRedData[]{ + 65, 100, 60, + 91, 60, 10, + 2, 0, 0 + }; + + const Float deltaRed[]{ + 35.0f, 0.0f, 30.0f, + 1.0f, 0.0f, 10.0f, + 12.0f, 100.0f, 0.0f + }; + + const ImageView2D actualRed{PixelStorage{}.setAlignment(2), PixelFormat::R16I, {3, 3}, actualRedData}; + const ImageView2D expectedRed{PixelStorage{}.setAlignment(2), PixelFormat::R16I, {3, 3}, expectedRedData}; + + Containers::Triple, Float, Float> deltaMaxMean = Implementation::calculateImageDelta(actualRed.format(), actualRed.pixels(), expectedRed); + CORRADE_COMPARE_AS(deltaMaxMean.first(), + Containers::arrayView(deltaRed), + TestSuite::Compare::Container); + CORRADE_COMPARE(deltaMaxMean.second(), 100.0f); + CORRADE_COMPARE(deltaMaxMean.third(), 20.8889f); +} + /* Different storage for each */ const UnsignedByte ActualRgbData[] = { 0, 0, 0, 0, 0, 0, 0, 0,