X-Git-Url: https://git.sesse.net/?a=blobdiff_plain;f=resample_effect_test.cpp;fp=resample_effect_test.cpp;h=462f5c9c1f6d6751d874f5c5cb67e55d243f468c;hb=fb92a4e217a92ecf83b7812cc6933f6f3048b752;hp=0000000000000000000000000000000000000000;hpb=9e62fbe2ac764479c449472d8bda52ac4df0de91;p=movit diff --git a/resample_effect_test.cpp b/resample_effect_test.cpp new file mode 100644 index 0000000..462f5c9 --- /dev/null +++ b/resample_effect_test.cpp @@ -0,0 +1,162 @@ +// Unit tests for ResampleEffect. + +#include "test_util.h" +#include "gtest/gtest.h" +#include "resample_effect.h" +#include "flat_input.h" + +namespace { + +float sinc(float x) +{ + return sin(M_PI * x) / (M_PI * x); +} + +float lanczos(float x, float a) +{ + if (fabs(x) >= a) { + return 0.0f; + } else { + return sinc(x) * sinc(x / a); + } +} + +} // namespace + +TEST(ResampleEffectTest, IdentityTransformDoesNothing) { + const int size = 4; + + float data[size * size] = { + 0.0, 1.0, 0.0, 1.0, + 0.0, 1.0, 1.0, 0.0, + 0.0, 0.5, 1.0, 0.5, + 0.0, 0.0, 0.0, 0.0, + }; + float out_data[size * size]; + + EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect()); + ASSERT_TRUE(resample_effect->set_int("width", 4)); + ASSERT_TRUE(resample_effect->set_int("height", 4)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(data, out_data, size, size); +} + +TEST(ResampleEffectTest, UpscaleByTwoGetsCorrectPixelCenters) { + const int size = 5; + + float data[size * size] = { + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + }; + float expected_data[size * size * 4], out_data[size * size * 4]; + + for (int y = 0; y < size * 2; ++y) { + for (int x = 0; x < size * 2; ++x) { + float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f); + weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f); + expected_data[y * (size * 2) + x] = weight; + } + } + + EffectChainTester tester(NULL, size * 2, size * 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size); + input->set_pixel_data(data); + tester.get_chain()->add_input(input); + + Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect()); + ASSERT_TRUE(resample_effect->set_int("width", size * 2)); + ASSERT_TRUE(resample_effect->set_int("height", size * 2)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, size * 2, size * 2); +} + +TEST(ResampleEffectTest, DownscaleByTwoGetsCorrectPixelCenters) { + const int size = 5; + + // This isn't a perfect dot, since the Lanczos filter has a slight + // sharpening effect; the most important thing is that we have kept + // the texel center right (everything is nicely symmetric). + // The approximate magnitudes have been checked against ImageMagick. + float expected_data[size * size] = { + 0.0045, -0.0067, -0.0598, -0.0067, 0.0045, + -0.0067, 0.0099, 0.0886, 0.0099, -0.0067, + -0.0598, 0.0886, 0.7930, 0.0886, -0.0598, + -0.0067, 0.0099, 0.0886, 0.0099, -0.0067, + 0.0045, -0.0067, -0.0598, -0.0067, 0.0045, + }; + float data[size * size * 4], out_data[size * size]; + + for (int y = 0; y < size * 2; ++y) { + for (int x = 0; x < size * 2; ++x) { + float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f); + weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f); + data[y * (size * 2) + x] = weight; + } + } + + EffectChainTester tester(NULL, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size * 2, size * 2); + input->set_pixel_data(data); + tester.get_chain()->add_input(input); + + Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect()); + ASSERT_TRUE(resample_effect->set_int("width", size)); + ASSERT_TRUE(resample_effect->set_int("height", size)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + expect_equal(expected_data, out_data, size, size); +} + +TEST(ResampleEffectTest, UpscaleByThreeGetsCorrectPixelCenters) { + const int size = 5; + + float data[size * size] = { + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 1.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + 0.0, 0.0, 0.0, 0.0, 0.0, + }; + float out_data[size * size * 9]; + + EffectChainTester tester(NULL, size * 3, size * 3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR); + + ImageFormat format; + format.color_space = COLORSPACE_sRGB; + format.gamma_curve = GAMMA_LINEAR; + + FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size); + input->set_pixel_data(data); + tester.get_chain()->add_input(input); + + Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect()); + ASSERT_TRUE(resample_effect->set_int("width", size * 3)); + ASSERT_TRUE(resample_effect->set_int("height", size * 3)); + tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR); + + // We only bother checking that the middle pixel is still correct, + // and that symmetry holds. + EXPECT_FLOAT_EQ(1.0, out_data[7 * (size * 3) + 7]); + for (unsigned y = 0; y < size * 3; ++y) { + for (unsigned x = 0; x < size * 3; ++x) { + EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[(size * 3 - y - 1) * (size * 3) + x]); + EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[y * (size * 3) + (size * 3 - x - 1)]); + } + } +}