ColorSpace -> Colorspace. I kept typing it wrong, so even though I usually say color...
[movit] / colorspace_conversion_effect_test.cpp
1 // Unit tests for ColorspaceConversionEffect.
2
3 #include "test_util.h"
4 #include "gtest/gtest.h"
5 #include "colorspace_conversion_effect.h"
6
7 TEST(ColorspaceConversionEffectTest, Reversible) {
8         float data[] = {
9                 0.0f, 0.0f, 0.0f, 1.0f,
10                 1.0f, 1.0f, 1.0f, 1.0f,
11                 1.0f, 0.0f, 0.0f, 1.0f,
12                 0.0f, 1.0f, 0.0f, 1.0f,
13                 0.0f, 0.0f, 1.0f, 1.0f,
14                 0.0f, 1.0f, 1.0f, 0.5f,
15         };
16         float temp_data[4 * 6], out_data[4 * 6];
17
18         {
19                 EffectChainTester tester(data, 1, 6, FORMAT_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
20                 tester.run(temp_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
21         }
22         {
23                 EffectChainTester tester(temp_data, 1, 6, FORMAT_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
24                 tester.run(out_data, GL_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
25         }
26
27         expect_equal(data, out_data, 4, 6);
28 }
29
30 TEST(ColorspaceConversionEffectTest, sRGB_Primaries) {
31         float data[] = {
32                 0.0f, 0.0f, 0.0f, 1.0f,
33                 1.0f, 1.0f, 1.0f, 1.0f,
34                 1.0f, 0.0f, 0.0f, 1.0f,
35                 0.0f, 1.0f, 0.0f, 1.0f,
36                 0.0f, 0.0f, 1.0f, 1.0f,
37         };
38         float out_data[4 * 5];
39
40         EffectChainTester tester(data, 1, 5, FORMAT_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
41         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
42
43         // Black should stay black.
44         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
45         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
46         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
47         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
48
49         // White point should be D65.
50         // XYZ values from http://en.wikipedia.org/wiki/CIE_Standard_Illuminant_D65.
51         EXPECT_NEAR(0.9505, out_data[1 * 4 + 0], 1e-3);
52         EXPECT_NEAR(1.0000, out_data[1 * 4 + 1], 1e-3);
53         EXPECT_NEAR(1.0889, out_data[1 * 4 + 2], 1e-3);
54         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
55
56         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
57         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
58         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
59         EXPECT_NEAR(0.3127, white_x, 1e-3);
60         EXPECT_NEAR(0.3290, white_y, 1e-3);
61         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
62
63         // Convert the primaries from XYZ to xyz, and compare to the references
64         // given by Rec. 709 (which are shared with sRGB).
65
66         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
67         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
68         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
69         EXPECT_NEAR(0.640, red_x, 1e-3);
70         EXPECT_NEAR(0.330, red_y, 1e-3);
71         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
72
73         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
74         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
75         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
76         EXPECT_NEAR(0.300, green_x, 1e-3);
77         EXPECT_NEAR(0.600, green_y, 1e-3);
78         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
79
80         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
81         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
82         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
83         EXPECT_NEAR(0.150, blue_x, 1e-3);
84         EXPECT_NEAR(0.060, blue_y, 1e-3);
85         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
86 }
87
88 TEST(ColorspaceConversionEffectTest, Rec601_525_Primaries) {
89         float data[] = {
90                 0.0f, 0.0f, 0.0f, 1.0f,
91                 1.0f, 1.0f, 1.0f, 1.0f,
92                 1.0f, 0.0f, 0.0f, 1.0f,
93                 0.0f, 1.0f, 0.0f, 1.0f,
94                 0.0f, 0.0f, 1.0f, 1.0f,
95         };
96         float out_data[4 * 5];
97
98         EffectChainTester tester(data, 1, 5, FORMAT_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
99         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
100
101         // Black should stay black.
102         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
103         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
104         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
105         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
106
107         // Convert the primaries from XYZ to xyz, and compare to the references
108         // given by Rec. 601.
109         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
110         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
111         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
112         EXPECT_NEAR(0.3127, white_x, 1e-3);
113         EXPECT_NEAR(0.3290, white_y, 1e-3);
114         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
115
116         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
117         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
118         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
119         EXPECT_NEAR(0.630, red_x, 1e-3);
120         EXPECT_NEAR(0.340, red_y, 1e-3);
121         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
122
123         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
124         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
125         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
126         EXPECT_NEAR(0.310, green_x, 1e-3);
127         EXPECT_NEAR(0.595, green_y, 1e-3);
128         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
129
130         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
131         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
132         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
133         EXPECT_NEAR(0.155, blue_x, 1e-3);
134         EXPECT_NEAR(0.070, blue_y, 1e-3);
135         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
136 }
137
138 TEST(ColorspaceConversionEffectTest, Rec601_625_Primaries) {
139         float data[] = {
140                 0.0f, 0.0f, 0.0f, 1.0f,
141                 1.0f, 1.0f, 1.0f, 1.0f,
142                 1.0f, 0.0f, 0.0f, 1.0f,
143                 0.0f, 1.0f, 0.0f, 1.0f,
144                 0.0f, 0.0f, 1.0f, 1.0f,
145         };
146         float out_data[4 * 5];
147
148         EffectChainTester tester(data, 1, 5, FORMAT_RGBA, COLORSPACE_REC_601_625, GAMMA_LINEAR);
149         tester.run(out_data, GL_RGBA, COLORSPACE_XYZ, GAMMA_LINEAR);
150
151         // Black should stay black.
152         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 0]);
153         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 1]);
154         EXPECT_FLOAT_EQ(0.0f, out_data[0 * 4 + 2]);
155         EXPECT_FLOAT_EQ(1.0f, out_data[0 * 4 + 3]);
156
157         // Convert the primaries from XYZ to xyz, and compare to the references
158         // given by Rec. 601.
159         float white_xyz_sum = out_data[1 * 4 + 0] + out_data[1 * 4 + 1] + out_data[1 * 4 + 2];
160         float white_x = out_data[1 * 4 + 0] / white_xyz_sum;
161         float white_y = out_data[1 * 4 + 1] / white_xyz_sum;
162         EXPECT_NEAR(0.3127, white_x, 1e-3);
163         EXPECT_NEAR(0.3290, white_y, 1e-3);
164         EXPECT_FLOAT_EQ(1.0f, out_data[1 * 4 + 3]);
165
166         float red_xyz_sum = out_data[2 * 4 + 0] + out_data[2 * 4 + 1] + out_data[2 * 4 + 2];
167         float red_x = out_data[2 * 4 + 0] / red_xyz_sum;
168         float red_y = out_data[2 * 4 + 1] / red_xyz_sum;
169         EXPECT_NEAR(0.640, red_x, 1e-3);
170         EXPECT_NEAR(0.330, red_y, 1e-3);
171         EXPECT_FLOAT_EQ(1.0f, out_data[2 * 4 + 3]);
172
173         float green_xyz_sum = out_data[3 * 4 + 0] + out_data[3 * 4 + 1] + out_data[3 * 4 + 2];
174         float green_x = out_data[3 * 4 + 0] / green_xyz_sum;
175         float green_y = out_data[3 * 4 + 1] / green_xyz_sum;
176         EXPECT_NEAR(0.290, green_x, 1e-3);
177         EXPECT_NEAR(0.600, green_y, 1e-3);
178         EXPECT_FLOAT_EQ(1.0f, out_data[3 * 4 + 3]);
179
180         float blue_xyz_sum = out_data[4 * 4 + 0] + out_data[4 * 4 + 1] + out_data[4 * 4 + 2];
181         float blue_x = out_data[4 * 4 + 0] / blue_xyz_sum;
182         float blue_y = out_data[4 * 4 + 1] / blue_xyz_sum;
183         EXPECT_NEAR(0.150, blue_x, 1e-3);
184         EXPECT_NEAR(0.060, blue_y, 1e-3);
185         EXPECT_FLOAT_EQ(1.0f, out_data[4 * 4 + 3]);
186 }
187
188 TEST(ColorspaceConversionEffectTest, sRGBToRec601_525) {
189         float data[] = {
190                 0.0f, 0.0f, 0.0f, 1.0f,
191                 1.0f, 1.0f, 1.0f, 1.0f,
192                 1.0f, 0.0f, 0.0f, 1.0f,
193                 0.0f, 1.0f, 0.0f, 1.0f,
194                 0.0f, 0.0f, 1.0f, 1.0f,
195                 0.0f, 1.0f, 1.0f, 0.5f,
196         };
197
198         // I have to admit that most of these come from the code itself;
199         // however, they do make sense if you look at the two gamuts
200         // in xy space.
201         float expected_data[] = {
202                 // Black should stay black.
203                 0.0f, 0.0f, 0.0f, 1.0f,
204
205                 // White should stay white (both use the D65 white point).
206                 1.0f, 1.0f, 1.0f, 1.0f,
207
208                 // sRGB red is slightly out-of-gamut for Rec. 601/525.
209                 1.064f, -0.020f, 0.0f, 1.0f,
210
211                 // Green too.
212                 -0.055f, 1.036f, 0.004f, 1.0f,
213
214                 // The blues are much closer; it _is_ still out-of-gamut,
215                 // but not actually more saturated (farther from the
216                 // white point).
217                 -0.010f, -0.017f, 0.994f, 1.0f,
218
219                 // Cyan is a mix of green and blue. Note: The alpha is kept.
220                 -0.065f, 1.0195f, 0.998f, 0.5f,
221         };
222         float out_data[4 * 6];
223
224         EffectChainTester tester(data, 1, 6, FORMAT_RGBA, COLORSPACE_sRGB, GAMMA_LINEAR);
225         tester.run(out_data, GL_RGBA, COLORSPACE_REC_601_525, GAMMA_LINEAR);
226
227         expect_equal(expected_data, out_data, 4, 6);
228 }