]> git.sesse.net Git - movit/blob - resample_effect_test.cpp
952553681a87834beab57618120c85c42cb661b2
[movit] / resample_effect_test.cpp
1 // Unit tests for ResampleEffect.
2
3 #include <GL/glew.h>
4 #include <math.h>
5
6 #include "effect_chain.h"
7 #include "flat_input.h"
8 #include "glew.h"
9 #include "gtest/gtest.h"
10 #include "image_format.h"
11 #include "resample_effect.h"
12 #include "test_util.h"
13
14 namespace {
15
16 float sinc(float x)
17 {
18         return sin(M_PI * x) / (M_PI * x);
19 }
20
21 float lanczos(float x, float a)
22 {
23         if (fabs(x) >= a) {
24                 return 0.0f;
25         } else {
26                 return sinc(x) * sinc(x / a);
27         }
28 }
29
30 }  // namespace
31
32 TEST(ResampleEffectTest, IdentityTransformDoesNothing) {
33         const int size = 4;
34
35         float data[size * size] = {
36                 0.0, 1.0, 0.0, 1.0,
37                 0.0, 1.0, 1.0, 0.0,
38                 0.0, 0.5, 1.0, 0.5,
39                 0.0, 0.0, 0.0, 0.0,
40         };
41         float out_data[size * size];
42
43         EffectChainTester tester(data, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
44         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
45         ASSERT_TRUE(resample_effect->set_int("width", 4));
46         ASSERT_TRUE(resample_effect->set_int("height", 4));
47         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
48
49         expect_equal(data, out_data, size, size);
50 }
51
52 TEST(ResampleEffectTest, UpscaleByTwoGetsCorrectPixelCenters) {
53         const int size = 5;
54
55         float data[size * size] = {
56                 0.0, 0.0, 0.0, 0.0, 0.0,
57                 0.0, 0.0, 0.0, 0.0, 0.0,
58                 0.0, 0.0, 1.0, 0.0, 0.0,
59                 0.0, 0.0, 0.0, 0.0, 0.0,
60                 0.0, 0.0, 0.0, 0.0, 0.0,
61         };
62         float expected_data[size * size * 4], out_data[size * size * 4];
63
64         for (int y = 0; y < size * 2; ++y) {
65                 for (int x = 0; x < size * 2; ++x) {
66                         float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
67                         weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
68                         expected_data[y * (size * 2) + x] = weight;
69                 }
70         }
71
72         EffectChainTester tester(NULL, size * 2, size * 2, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
73
74         ImageFormat format;
75         format.color_space = COLORSPACE_sRGB;
76         format.gamma_curve = GAMMA_LINEAR;
77
78         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
79         input->set_pixel_data(data);
80         tester.get_chain()->add_input(input);
81
82         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
83         ASSERT_TRUE(resample_effect->set_int("width", size * 2));
84         ASSERT_TRUE(resample_effect->set_int("height", size * 2));
85         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
86
87         expect_equal(expected_data, out_data, size * 2, size * 2);
88 }
89
90 TEST(ResampleEffectTest, DownscaleByTwoGetsCorrectPixelCenters) {
91         const int size = 5;
92
93         // This isn't a perfect dot, since the Lanczos filter has a slight
94         // sharpening effect; the most important thing is that we have kept
95         // the texel center right (everything is nicely symmetric).
96         // The approximate magnitudes have been checked against ImageMagick.
97         float expected_data[size * size] = {
98                  0.0045, -0.0067, -0.0598, -0.0067,  0.0045, 
99                 -0.0067,  0.0099,  0.0886,  0.0099, -0.0067, 
100                 -0.0598,  0.0886,  0.7930,  0.0886, -0.0598, 
101                 -0.0067,  0.0099,  0.0886,  0.0099, -0.0067, 
102                  0.0045, -0.0067, -0.0598, -0.0067,  0.0045, 
103         };
104         float data[size * size * 4], out_data[size * size];
105
106         for (int y = 0; y < size * 2; ++y) {
107                 for (int x = 0; x < size * 2; ++x) {
108                         float weight = lanczos((x - size + 0.5f) * 0.5f, 3.0f);
109                         weight *= lanczos((y - size + 0.5f) * 0.5f, 3.0f);
110                         data[y * (size * 2) + x] = weight;
111                 }
112         }
113
114         EffectChainTester tester(NULL, size, size, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
115
116         ImageFormat format;
117         format.color_space = COLORSPACE_sRGB;
118         format.gamma_curve = GAMMA_LINEAR;
119
120         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size * 2, size * 2);
121         input->set_pixel_data(data);
122         tester.get_chain()->add_input(input);
123
124         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
125         ASSERT_TRUE(resample_effect->set_int("width", size));
126         ASSERT_TRUE(resample_effect->set_int("height", size));
127         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
128
129         expect_equal(expected_data, out_data, size, size);
130 }
131
132 TEST(ResampleEffectTest, UpscaleByThreeGetsCorrectPixelCenters) {
133         const int size = 5;
134
135         float data[size * size] = {
136                 0.0, 0.0, 0.0, 0.0, 0.0,
137                 0.0, 0.0, 0.0, 0.0, 0.0,
138                 0.0, 0.0, 1.0, 0.0, 0.0,
139                 0.0, 0.0, 0.0, 0.0, 0.0,
140                 0.0, 0.0, 0.0, 0.0, 0.0,
141         };
142         float out_data[size * size * 9];
143
144         EffectChainTester tester(NULL, size * 3, size * 3, FORMAT_GRAYSCALE, COLORSPACE_sRGB, GAMMA_LINEAR);
145
146         ImageFormat format;
147         format.color_space = COLORSPACE_sRGB;
148         format.gamma_curve = GAMMA_LINEAR;
149
150         FlatInput *input = new FlatInput(format, FORMAT_GRAYSCALE, GL_FLOAT, size, size);
151         input->set_pixel_data(data);
152         tester.get_chain()->add_input(input);
153
154         Effect *resample_effect = tester.get_chain()->add_effect(new ResampleEffect());
155         ASSERT_TRUE(resample_effect->set_int("width", size * 3));
156         ASSERT_TRUE(resample_effect->set_int("height", size * 3));
157         tester.run(out_data, GL_RED, COLORSPACE_sRGB, GAMMA_LINEAR);
158
159         // We only bother checking that the middle pixel is still correct,
160         // and that symmetry holds.
161         EXPECT_FLOAT_EQ(1.0, out_data[7 * (size * 3) + 7]);
162         for (unsigned y = 0; y < size * 3; ++y) {
163                 for (unsigned x = 0; x < size * 3; ++x) {
164                         EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[(size * 3 - y - 1) * (size * 3) + x]);
165                         EXPECT_FLOAT_EQ(out_data[y * (size * 3) + x], out_data[y * (size * 3) + (size * 3 - x - 1)]);
166                 }
167         }
168 }