blob: 169201c73b24d15395b70702ac0e39ec650967d9 [file] [log] [blame]
Nick Deakin65f492a2022-11-29 22:47:40 -05001/*
2 * Copyright 2022 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17#include <cmath>
18#include <gtest/gtest.h>
19#include <gmock/gmock.h>
20#include <jpegrecoverymap/recoverymapmath.h>
21
22namespace android::recoverymap {
23
24class RecoveryMapMathTest : public testing::Test {
25public:
26 RecoveryMapMathTest();
27 ~RecoveryMapMathTest();
28
29 float ComparisonEpsilon() { return 1e-4f; }
30 float LuminanceEpsilon() { return 1e-2f; }
31
32 Color Yuv420(uint8_t y, uint8_t u, uint8_t v) {
33 return {{{ static_cast<float>(y) / 255.0f,
34 (static_cast<float>(u) - 128.0f) / 255.0f,
35 (static_cast<float>(v) - 128.0f) / 255.0f }}};
36 }
37
38 Color P010(uint16_t y, uint16_t u, uint16_t v) {
39 return {{{ static_cast<float>(y) / 940.0f,
40 (static_cast<float>(u) - 64.0f) / 940.0f - 0.5f,
41 (static_cast<float>(v) - 64.0f) / 940.0f - 0.5f }}};
42 }
43
44 float Map(uint8_t e) {
45 return (static_cast<float>(e) - 127.5f) / 127.5f;
46 }
47
48 Color ColorMin(Color e1, Color e2) {
49 return {{{ fmin(e1.r, e2.r), fmin(e1.g, e2.g), fmin(e1.b, e2.b) }}};
50 }
51
52 Color ColorMax(Color e1, Color e2) {
53 return {{{ fmax(e1.r, e2.r), fmax(e1.g, e2.g), fmax(e1.b, e2.b) }}};
54 }
55
56 Color RgbBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; }
57 Color RgbWhite() { return {{{ 1.0f, 1.0f, 1.0f }}}; }
58
59 Color RgbRed() { return {{{ 1.0f, 0.0f, 0.0f }}}; }
60 Color RgbGreen() { return {{{ 0.0f, 1.0f, 0.0f }}}; }
61 Color RgbBlue() { return {{{ 0.0f, 0.0f, 1.0f }}}; }
62
63 Color YuvBlack() { return {{{ 0.0f, 0.0f, 0.0f }}}; }
64 Color YuvWhite() { return {{{ 1.0f, 0.0f, 0.0f }}}; }
65
66 Color SrgbYuvRed() { return {{{ 0.299f, -0.1687f, 0.5f }}}; }
67 Color SrgbYuvGreen() { return {{{ 0.587f, -0.3313f, -0.4187f }}}; }
68 Color SrgbYuvBlue() { return {{{ 0.114f, 0.5f, -0.0813f }}}; }
69
70 Color Bt2100YuvRed() { return {{{ 0.2627f, -0.13963f, 0.5f }}}; }
71 Color Bt2100YuvGreen() { return {{{ 0.6780f, -0.36037f, -0.45979f }}}; }
72 Color Bt2100YuvBlue() { return {{{ 0.0593f, 0.5f, -0.04021f }}}; }
73
74 float SrgbYuvToLuminance(Color yuv_gamma, ColorCalculationFn luminanceFn) {
75 Color rgb_gamma = srgbYuvToRgb(yuv_gamma);
76 Color rgb = srgbInvOetf(rgb_gamma);
77 float luminance_scaled = luminanceFn(rgb);
78 return luminance_scaled * kSdrWhiteNits;
79 }
80
81 float Bt2100YuvToLuminance(Color yuv_gamma, ColorTransformFn hdrInvOetf,
82 ColorTransformFn gamutConversionFn, ColorCalculationFn luminanceFn,
83 float scale_factor) {
84 Color rgb_gamma = bt2100YuvToRgb(yuv_gamma);
85 Color rgb = hdrInvOetf(rgb_gamma);
86 rgb = gamutConversionFn(rgb);
87 float luminance_scaled = luminanceFn(rgb);
88 return luminance_scaled * scale_factor;
89 }
90
91 Color Recover(Color yuv_gamma, float recovery, float range_scaling_factor) {
92 Color rgb_gamma = srgbYuvToRgb(yuv_gamma);
93 Color rgb = srgbInvOetf(rgb_gamma);
94 return applyRecovery(rgb, recovery, range_scaling_factor);
95 }
96
97 jpegr_uncompressed_struct Yuv420Image() {
98 static uint8_t pixels[] = {
99 // Y
100 0x00, 0x10, 0x20, 0x30,
101 0x01, 0x11, 0x21, 0x31,
102 0x02, 0x12, 0x22, 0x32,
103 0x03, 0x13, 0x23, 0x33,
104 // U
105 0xA0, 0xA1,
106 0xA2, 0xA3,
107 // V
108 0xB0, 0xB1,
109 0xB2, 0xB3,
110 };
111 return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 };
112 }
113
114 Color (*Yuv420Colors())[4] {
115 static Color colors[4][4] = {
116 {
117 Yuv420(0x00, 0xA0, 0xB0), Yuv420(0x10, 0xA0, 0xB0),
118 Yuv420(0x20, 0xA1, 0xB1), Yuv420(0x30, 0xA1, 0xB1),
119 }, {
120 Yuv420(0x01, 0xA0, 0xB0), Yuv420(0x11, 0xA0, 0xB0),
121 Yuv420(0x21, 0xA1, 0xB1), Yuv420(0x31, 0xA1, 0xB1),
122 }, {
123 Yuv420(0x02, 0xA2, 0xB2), Yuv420(0x12, 0xA2, 0xB2),
124 Yuv420(0x22, 0xA3, 0xB3), Yuv420(0x32, 0xA3, 0xB3),
125 }, {
126 Yuv420(0x03, 0xA2, 0xB2), Yuv420(0x13, 0xA2, 0xB2),
127 Yuv420(0x23, 0xA3, 0xB3), Yuv420(0x33, 0xA3, 0xB3),
128 },
129 };
130 return colors;
131 }
132
133 jpegr_uncompressed_struct P010Image() {
134 static uint16_t pixels[] = {
135 // Y
136 0x00 << 6, 0x10 << 6, 0x20 << 6, 0x30 << 6,
137 0x01 << 6, 0x11 << 6, 0x21 << 6, 0x31 << 6,
138 0x02 << 6, 0x12 << 6, 0x22 << 6, 0x32 << 6,
139 0x03 << 6, 0x13 << 6, 0x23 << 6, 0x33 << 6,
140 // UV
141 0xA0 << 6, 0xB0 << 6, 0xA1 << 6, 0xB1 << 6,
142 0xA2 << 6, 0xB2 << 6, 0xA3 << 6, 0xB3 << 6,
143 };
144 return { pixels, 4, 4, JPEGR_COLORGAMUT_BT709 };
145 }
146
147 Color (*P010Colors())[4] {
148 static Color colors[4][4] = {
149 {
150 P010(0x00, 0xA0, 0xB0), P010(0x10, 0xA0, 0xB0),
151 P010(0x20, 0xA1, 0xB1), P010(0x30, 0xA1, 0xB1),
152 }, {
153 P010(0x01, 0xA0, 0xB0), P010(0x11, 0xA0, 0xB0),
154 P010(0x21, 0xA1, 0xB1), P010(0x31, 0xA1, 0xB1),
155 }, {
156 P010(0x02, 0xA2, 0xB2), P010(0x12, 0xA2, 0xB2),
157 P010(0x22, 0xA3, 0xB3), P010(0x32, 0xA3, 0xB3),
158 }, {
159 P010(0x03, 0xA2, 0xB2), P010(0x13, 0xA2, 0xB2),
160 P010(0x23, 0xA3, 0xB3), P010(0x33, 0xA3, 0xB3),
161 },
162 };
163 return colors;
164 }
165
166 jpegr_uncompressed_struct MapImage() {
167 static uint8_t pixels[] = {
168 0x00, 0x10, 0x20, 0x30,
169 0x01, 0x11, 0x21, 0x31,
170 0x02, 0x12, 0x22, 0x32,
171 0x03, 0x13, 0x23, 0x33,
172 };
173 return { pixels, 4, 4, JPEGR_COLORGAMUT_UNSPECIFIED };
174 }
175
176 float (*MapValues())[4] {
177 static float values[4][4] = {
178 {
179 Map(0x00), Map(0x10), Map(0x20), Map(0x30),
180 }, {
181 Map(0x01), Map(0x11), Map(0x21), Map(0x31),
182 }, {
183 Map(0x02), Map(0x12), Map(0x22), Map(0x32),
184 }, {
185 Map(0x03), Map(0x13), Map(0x23), Map(0x33),
186 },
187 };
188 return values;
189 }
190
191protected:
192 virtual void SetUp();
193 virtual void TearDown();
194};
195
196RecoveryMapMathTest::RecoveryMapMathTest() {}
197RecoveryMapMathTest::~RecoveryMapMathTest() {}
198
199void RecoveryMapMathTest::SetUp() {}
200void RecoveryMapMathTest::TearDown() {}
201
202#define EXPECT_RGB_EQ(e1, e2) \
203 EXPECT_FLOAT_EQ((e1).r, (e2).r); \
204 EXPECT_FLOAT_EQ((e1).g, (e2).g); \
205 EXPECT_FLOAT_EQ((e1).b, (e2).b)
206
207#define EXPECT_RGB_NEAR(e1, e2) \
208 EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon()); \
209 EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon()); \
210 EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon())
211
212#define EXPECT_RGB_CLOSE(e1, e2) \
213 EXPECT_NEAR((e1).r, (e2).r, ComparisonEpsilon() * 10.0f); \
214 EXPECT_NEAR((e1).g, (e2).g, ComparisonEpsilon() * 10.0f); \
215 EXPECT_NEAR((e1).b, (e2).b, ComparisonEpsilon() * 10.0f)
216
217#define EXPECT_YUV_EQ(e1, e2) \
218 EXPECT_FLOAT_EQ((e1).y, (e2).y); \
219 EXPECT_FLOAT_EQ((e1).u, (e2).u); \
220 EXPECT_FLOAT_EQ((e1).v, (e2).v)
221
222#define EXPECT_YUV_NEAR(e1, e2) \
223 EXPECT_NEAR((e1).y, (e2).y, ComparisonEpsilon()); \
224 EXPECT_NEAR((e1).u, (e2).u, ComparisonEpsilon()); \
225 EXPECT_NEAR((e1).v, (e2).v, ComparisonEpsilon())
226
227#define EXPECT_YUV_BETWEEN(e, min, max) \
228 EXPECT_THAT((e).y, testing::AllOf(testing::Ge((min).y), testing::Le((max).y))); \
229 EXPECT_THAT((e).u, testing::AllOf(testing::Ge((min).u), testing::Le((max).u))); \
230 EXPECT_THAT((e).v, testing::AllOf(testing::Ge((min).v), testing::Le((max).v)))
231
232// TODO: a bunch of these tests can be parameterized.
233
234TEST_F(RecoveryMapMathTest, ColorConstruct) {
235 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
236
237 EXPECT_FLOAT_EQ(e1.r, 0.1f);
238 EXPECT_FLOAT_EQ(e1.g, 0.2f);
239 EXPECT_FLOAT_EQ(e1.b, 0.3f);
240
241 EXPECT_FLOAT_EQ(e1.y, 0.1f);
242 EXPECT_FLOAT_EQ(e1.u, 0.2f);
243 EXPECT_FLOAT_EQ(e1.v, 0.3f);
244}
245
246TEST_F(RecoveryMapMathTest, ColorAddColor) {
247 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
248
249 Color e2 = e1 + e1;
250 EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f);
251 EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f);
252 EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f);
253
254 e2 += e1;
255 EXPECT_FLOAT_EQ(e2.r, e1.r * 3.0f);
256 EXPECT_FLOAT_EQ(e2.g, e1.g * 3.0f);
257 EXPECT_FLOAT_EQ(e2.b, e1.b * 3.0f);
258}
259
260TEST_F(RecoveryMapMathTest, ColorAddFloat) {
261 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
262
263 Color e2 = e1 + 0.1f;
264 EXPECT_FLOAT_EQ(e2.r, e1.r + 0.1f);
265 EXPECT_FLOAT_EQ(e2.g, e1.g + 0.1f);
266 EXPECT_FLOAT_EQ(e2.b, e1.b + 0.1f);
267
268 e2 += 0.1f;
269 EXPECT_FLOAT_EQ(e2.r, e1.r + 0.2f);
270 EXPECT_FLOAT_EQ(e2.g, e1.g + 0.2f);
271 EXPECT_FLOAT_EQ(e2.b, e1.b + 0.2f);
272}
273
274TEST_F(RecoveryMapMathTest, ColorSubtractColor) {
275 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
276
277 Color e2 = e1 - e1;
278 EXPECT_FLOAT_EQ(e2.r, 0.0f);
279 EXPECT_FLOAT_EQ(e2.g, 0.0f);
280 EXPECT_FLOAT_EQ(e2.b, 0.0f);
281
282 e2 -= e1;
283 EXPECT_FLOAT_EQ(e2.r, -e1.r);
284 EXPECT_FLOAT_EQ(e2.g, -e1.g);
285 EXPECT_FLOAT_EQ(e2.b, -e1.b);
286}
287
288TEST_F(RecoveryMapMathTest, ColorSubtractFloat) {
289 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
290
291 Color e2 = e1 - 0.1f;
292 EXPECT_FLOAT_EQ(e2.r, e1.r - 0.1f);
293 EXPECT_FLOAT_EQ(e2.g, e1.g - 0.1f);
294 EXPECT_FLOAT_EQ(e2.b, e1.b - 0.1f);
295
296 e2 -= 0.1f;
297 EXPECT_FLOAT_EQ(e2.r, e1.r - 0.2f);
298 EXPECT_FLOAT_EQ(e2.g, e1.g - 0.2f);
299 EXPECT_FLOAT_EQ(e2.b, e1.b - 0.2f);
300}
301
302TEST_F(RecoveryMapMathTest, ColorMultiplyFloat) {
303 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
304
305 Color e2 = e1 * 2.0f;
306 EXPECT_FLOAT_EQ(e2.r, e1.r * 2.0f);
307 EXPECT_FLOAT_EQ(e2.g, e1.g * 2.0f);
308 EXPECT_FLOAT_EQ(e2.b, e1.b * 2.0f);
309
310 e2 *= 2.0f;
311 EXPECT_FLOAT_EQ(e2.r, e1.r * 4.0f);
312 EXPECT_FLOAT_EQ(e2.g, e1.g * 4.0f);
313 EXPECT_FLOAT_EQ(e2.b, e1.b * 4.0f);
314}
315
316TEST_F(RecoveryMapMathTest, ColorDivideFloat) {
317 Color e1 = {{{ 0.1f, 0.2f, 0.3f }}};
318
319 Color e2 = e1 / 2.0f;
320 EXPECT_FLOAT_EQ(e2.r, e1.r / 2.0f);
321 EXPECT_FLOAT_EQ(e2.g, e1.g / 2.0f);
322 EXPECT_FLOAT_EQ(e2.b, e1.b / 2.0f);
323
324 e2 /= 2.0f;
325 EXPECT_FLOAT_EQ(e2.r, e1.r / 4.0f);
326 EXPECT_FLOAT_EQ(e2.g, e1.g / 4.0f);
327 EXPECT_FLOAT_EQ(e2.b, e1.b / 4.0f);
328}
329
330TEST_F(RecoveryMapMathTest, SrgbLuminance) {
331 EXPECT_FLOAT_EQ(srgbLuminance(RgbBlack()), 0.0f);
332 EXPECT_FLOAT_EQ(srgbLuminance(RgbWhite()), 1.0f);
333 EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.2126f);
334 EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.7152f);
335 EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.0722f);
336}
337
338TEST_F(RecoveryMapMathTest, SrgbYuvToRgb) {
339 Color rgb_black = srgbYuvToRgb(YuvBlack());
340 EXPECT_RGB_NEAR(rgb_black, RgbBlack());
341
342 Color rgb_white = srgbYuvToRgb(YuvWhite());
343 EXPECT_RGB_NEAR(rgb_white, RgbWhite());
344
345 Color rgb_r = srgbYuvToRgb(SrgbYuvRed());
346 EXPECT_RGB_NEAR(rgb_r, RgbRed());
347
348 Color rgb_g = srgbYuvToRgb(SrgbYuvGreen());
349 EXPECT_RGB_NEAR(rgb_g, RgbGreen());
350
351 Color rgb_b = srgbYuvToRgb(SrgbYuvBlue());
352 EXPECT_RGB_NEAR(rgb_b, RgbBlue());
353}
354
355TEST_F(RecoveryMapMathTest, SrgbRgbToYuv) {
356 Color yuv_black = srgbRgbToYuv(RgbBlack());
357 EXPECT_YUV_NEAR(yuv_black, YuvBlack());
358
359 Color yuv_white = srgbRgbToYuv(RgbWhite());
360 EXPECT_YUV_NEAR(yuv_white, YuvWhite());
361
362 Color yuv_r = srgbRgbToYuv(RgbRed());
363 EXPECT_YUV_NEAR(yuv_r, SrgbYuvRed());
364
365 Color yuv_g = srgbRgbToYuv(RgbGreen());
366 EXPECT_YUV_NEAR(yuv_g, SrgbYuvGreen());
367
368 Color yuv_b = srgbRgbToYuv(RgbBlue());
369 EXPECT_YUV_NEAR(yuv_b, SrgbYuvBlue());
370}
371
372TEST_F(RecoveryMapMathTest, SrgbRgbYuvRoundtrip) {
373 Color rgb_black = srgbYuvToRgb(srgbRgbToYuv(RgbBlack()));
374 EXPECT_RGB_NEAR(rgb_black, RgbBlack());
375
376 Color rgb_white = srgbYuvToRgb(srgbRgbToYuv(RgbWhite()));
377 EXPECT_RGB_NEAR(rgb_white, RgbWhite());
378
379 Color rgb_r = srgbYuvToRgb(srgbRgbToYuv(RgbRed()));
380 EXPECT_RGB_NEAR(rgb_r, RgbRed());
381
382 Color rgb_g = srgbYuvToRgb(srgbRgbToYuv(RgbGreen()));
383 EXPECT_RGB_NEAR(rgb_g, RgbGreen());
384
385 Color rgb_b = srgbYuvToRgb(srgbRgbToYuv(RgbBlue()));
386 EXPECT_RGB_NEAR(rgb_b, RgbBlue());
387}
388
389TEST_F(RecoveryMapMathTest, SrgbTransferFunction) {
390 EXPECT_FLOAT_EQ(srgbInvOetf(0.0f), 0.0f);
391 EXPECT_NEAR(srgbInvOetf(0.02f), 0.00154f, ComparisonEpsilon());
392 EXPECT_NEAR(srgbInvOetf(0.04045f), 0.00313f, ComparisonEpsilon());
393 EXPECT_NEAR(srgbInvOetf(0.5f), 0.21404f, ComparisonEpsilon());
394 EXPECT_FLOAT_EQ(srgbInvOetf(1.0f), 1.0f);
395}
396
397TEST_F(RecoveryMapMathTest, P3Luminance) {
398 EXPECT_FLOAT_EQ(p3Luminance(RgbBlack()), 0.0f);
399 EXPECT_FLOAT_EQ(p3Luminance(RgbWhite()), 1.0f);
400 EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.20949f);
401 EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.72160f);
402 EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.06891f);
403}
404
405TEST_F(RecoveryMapMathTest, Bt2100Luminance) {
406 EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlack()), 0.0f);
407 EXPECT_FLOAT_EQ(bt2100Luminance(RgbWhite()), 1.0f);
408 EXPECT_FLOAT_EQ(bt2100Luminance(RgbRed()), 0.2627f);
409 EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.6780f);
410 EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.0593f);
411}
412
413TEST_F(RecoveryMapMathTest, Bt2100YuvToRgb) {
414 Color rgb_black = bt2100YuvToRgb(YuvBlack());
415 EXPECT_RGB_NEAR(rgb_black, RgbBlack());
416
417 Color rgb_white = bt2100YuvToRgb(YuvWhite());
418 EXPECT_RGB_NEAR(rgb_white, RgbWhite());
419
420 Color rgb_r = bt2100YuvToRgb(Bt2100YuvRed());
421 EXPECT_RGB_NEAR(rgb_r, RgbRed());
422
423 Color rgb_g = bt2100YuvToRgb(Bt2100YuvGreen());
424 EXPECT_RGB_NEAR(rgb_g, RgbGreen());
425
426 Color rgb_b = bt2100YuvToRgb(Bt2100YuvBlue());
427 EXPECT_RGB_NEAR(rgb_b, RgbBlue());
428}
429
430TEST_F(RecoveryMapMathTest, Bt2100RgbToYuv) {
431 Color yuv_black = bt2100RgbToYuv(RgbBlack());
432 EXPECT_YUV_NEAR(yuv_black, YuvBlack());
433
434 Color yuv_white = bt2100RgbToYuv(RgbWhite());
435 EXPECT_YUV_NEAR(yuv_white, YuvWhite());
436
437 Color yuv_r = bt2100RgbToYuv(RgbRed());
438 EXPECT_YUV_NEAR(yuv_r, Bt2100YuvRed());
439
440 Color yuv_g = bt2100RgbToYuv(RgbGreen());
441 EXPECT_YUV_NEAR(yuv_g, Bt2100YuvGreen());
442
443 Color yuv_b = bt2100RgbToYuv(RgbBlue());
444 EXPECT_YUV_NEAR(yuv_b, Bt2100YuvBlue());
445}
446
447TEST_F(RecoveryMapMathTest, Bt2100RgbYuvRoundtrip) {
448 Color rgb_black = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlack()));
449 EXPECT_RGB_NEAR(rgb_black, RgbBlack());
450
451 Color rgb_white = bt2100YuvToRgb(bt2100RgbToYuv(RgbWhite()));
452 EXPECT_RGB_NEAR(rgb_white, RgbWhite());
453
454 Color rgb_r = bt2100YuvToRgb(bt2100RgbToYuv(RgbRed()));
455 EXPECT_RGB_NEAR(rgb_r, RgbRed());
456
457 Color rgb_g = bt2100YuvToRgb(bt2100RgbToYuv(RgbGreen()));
458 EXPECT_RGB_NEAR(rgb_g, RgbGreen());
459
460 Color rgb_b = bt2100YuvToRgb(bt2100RgbToYuv(RgbBlue()));
461 EXPECT_RGB_NEAR(rgb_b, RgbBlue());
462}
463
464TEST_F(RecoveryMapMathTest, HlgOetf) {
465 EXPECT_FLOAT_EQ(hlgOetf(0.0f), 0.0f);
466 EXPECT_NEAR(hlgOetf(0.04167f), 0.35357f, ComparisonEpsilon());
467 EXPECT_NEAR(hlgOetf(0.08333f), 0.5f, ComparisonEpsilon());
468 EXPECT_NEAR(hlgOetf(0.5f), 0.87164f, ComparisonEpsilon());
469 EXPECT_FLOAT_EQ(hlgOetf(1.0f), 1.0f);
470
471 Color e = {{{ 0.04167f, 0.08333f, 0.5f }}};
472 Color e_gamma = {{{ 0.35357f, 0.5f, 0.87164f }}};
473 EXPECT_RGB_NEAR(hlgOetf(e), e_gamma);
474}
475
476TEST_F(RecoveryMapMathTest, HlgInvOetf) {
477 EXPECT_FLOAT_EQ(hlgInvOetf(0.0f), 0.0f);
478 EXPECT_NEAR(hlgInvOetf(0.25f), 0.02083f, ComparisonEpsilon());
479 EXPECT_NEAR(hlgInvOetf(0.5f), 0.08333f, ComparisonEpsilon());
480 EXPECT_NEAR(hlgInvOetf(0.75f), 0.26496f, ComparisonEpsilon());
481 EXPECT_FLOAT_EQ(hlgInvOetf(1.0f), 1.0f);
482
483 Color e_gamma = {{{ 0.25f, 0.5f, 0.75f }}};
484 Color e = {{{ 0.02083f, 0.08333f, 0.26496f }}};
485 EXPECT_RGB_NEAR(hlgInvOetf(e_gamma), e);
486}
487
488TEST_F(RecoveryMapMathTest, HlgTransferFunctionRoundtrip) {
489 EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(0.0f)), 0.0f);
490 EXPECT_NEAR(hlgInvOetf(hlgOetf(0.04167f)), 0.04167f, ComparisonEpsilon());
491 EXPECT_NEAR(hlgInvOetf(hlgOetf(0.08333f)), 0.08333f, ComparisonEpsilon());
492 EXPECT_NEAR(hlgInvOetf(hlgOetf(0.5f)), 0.5f, ComparisonEpsilon());
493 EXPECT_FLOAT_EQ(hlgInvOetf(hlgOetf(1.0f)), 1.0f);
494}
495
496TEST_F(RecoveryMapMathTest, PqOetf) {
497 EXPECT_FLOAT_EQ(pqOetf(0.0f), 0.0f);
498 EXPECT_NEAR(pqOetf(0.01f), 0.50808f, ComparisonEpsilon());
499 EXPECT_NEAR(pqOetf(0.5f), 0.92655f, ComparisonEpsilon());
500 EXPECT_NEAR(pqOetf(0.99f), 0.99895f, ComparisonEpsilon());
501 EXPECT_FLOAT_EQ(pqOetf(1.0f), 1.0f);
502
503 Color e = {{{ 0.01f, 0.5f, 0.99f }}};
504 Color e_gamma = {{{ 0.50808f, 0.92655f, 0.99895f }}};
505 EXPECT_RGB_NEAR(pqOetf(e), e_gamma);
506}
507
508TEST_F(RecoveryMapMathTest, PqInvOetf) {
509 EXPECT_FLOAT_EQ(pqInvOetf(0.0f), 0.0f);
510 EXPECT_NEAR(pqInvOetf(0.01f), 2.31017e-7f, ComparisonEpsilon());
511 EXPECT_NEAR(pqInvOetf(0.5f), 0.00922f, ComparisonEpsilon());
512 EXPECT_NEAR(pqInvOetf(0.99f), 0.90903f, ComparisonEpsilon());
513 EXPECT_FLOAT_EQ(pqInvOetf(1.0f), 1.0f);
514
515 Color e_gamma = {{{ 0.01f, 0.5f, 0.99f }}};
516 Color e = {{{ 2.31017e-7f, 0.00922f, 0.90903f }}};
517 EXPECT_RGB_NEAR(pqInvOetf(e_gamma), e);
518}
519
520TEST_F(RecoveryMapMathTest, PqTransferFunctionRoundtrip) {
521 EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f);
522 EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon());
523 EXPECT_NEAR(pqInvOetf(pqOetf(0.5f)), 0.5f, ComparisonEpsilon());
524 EXPECT_NEAR(pqInvOetf(pqOetf(0.99f)), 0.99f, ComparisonEpsilon());
525 EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(1.0f)), 1.0f);
526}
527
528TEST_F(RecoveryMapMathTest, ColorConversionLookup) {
529 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_UNSPECIFIED),
530 nullptr);
531 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT709),
532 identityConversion);
533 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_P3),
534 p3ToBt709);
535 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT2100),
536 bt2100ToBt709);
537
538 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_UNSPECIFIED),
539 nullptr);
540 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT709),
541 bt709ToP3);
542 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_P3),
543 identityConversion);
544 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT2100),
545 bt2100ToP3);
546
547 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_UNSPECIFIED),
548 nullptr);
549 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT709),
550 bt709ToBt2100);
551 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_P3),
552 p3ToBt2100);
553 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT2100),
554 identityConversion);
555
556 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_UNSPECIFIED),
557 nullptr);
558 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709),
559 nullptr);
560 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_P3),
561 nullptr);
562 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT2100),
563 nullptr);
564}
565
566TEST_F(RecoveryMapMathTest, EncodeRecovery) {
567 EXPECT_EQ(encodeRecovery(0.0f, 0.0f, 4.0f), 127);
568 EXPECT_EQ(encodeRecovery(0.0f, 1.0f, 4.0f), 127);
569 EXPECT_EQ(encodeRecovery(1.0f, 0.0f, 4.0f), 0);
570 EXPECT_EQ(encodeRecovery(0.5f, 0.0f, 4.0f), 0);
571
572 EXPECT_EQ(encodeRecovery(1.0f, 1.0f, 4.0f), 127);
573 EXPECT_EQ(encodeRecovery(1.0f, 4.0f, 4.0f), 255);
574 EXPECT_EQ(encodeRecovery(1.0f, 5.0f, 4.0f), 255);
575 EXPECT_EQ(encodeRecovery(4.0f, 1.0f, 4.0f), 0);
576 EXPECT_EQ(encodeRecovery(4.0f, 0.5f, 4.0f), 0);
577 EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 4.0f), 191);
578 EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 4.0f), 63);
579
580 EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 2.0f), 255);
581 EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 2.0f), 0);
582 EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, 2.0f), 191);
583 EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, 2.0f), 63);
584
585 EXPECT_EQ(encodeRecovery(1.0f, 8.0f, 8.0f), 255);
586 EXPECT_EQ(encodeRecovery(8.0f, 1.0f, 8.0f), 0);
587 EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, 8.0f), 191);
588 EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, 8.0f), 63);
589}
590
591TEST_F(RecoveryMapMathTest, ApplyRecovery) {
592 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), -1.0f, 4.0f), RgbBlack());
593 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, 4.0f), RgbBlack());
594 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, 4.0f), RgbBlack());
595
596 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 4.0f), RgbWhite() / 4.0f);
597 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 4.0f), RgbWhite() / 2.0f);
598 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 4.0f), RgbWhite());
599 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 4.0f), RgbWhite() * 2.0f);
600 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 4.0f), RgbWhite() * 4.0f);
601
602 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 2.0f), RgbWhite() / 2.0f);
603 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 2.0f), RgbWhite() / 1.41421f);
604 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 2.0f), RgbWhite());
605 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 2.0f), RgbWhite() * 1.41421f);
606 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 2.0f), RgbWhite() * 2.0f);
607
608 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 8.0f), RgbWhite() / 8.0f);
609 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 8.0f), RgbWhite() / 2.82843f);
610 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 8.0f), RgbWhite());
611 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 8.0f), RgbWhite() * 2.82843f);
612 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 8.0f), RgbWhite() * 8.0f);
613
614 Color e = {{{ 0.0f, 0.5f, 1.0f }}};
615
616 EXPECT_RGB_NEAR(applyRecovery(e, -1.0f, 4.0f), e / 4.0f);
617 EXPECT_RGB_NEAR(applyRecovery(e, -0.5f, 4.0f), e / 2.0f);
618 EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, 4.0f), e);
619 EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, 4.0f), e * 2.0f);
620 EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, 4.0f), e * 4.0f);
621}
622
623TEST_F(RecoveryMapMathTest, GetYuv420Pixel) {
624 jpegr_uncompressed_struct image = Yuv420Image();
625 Color (*colors)[4] = Yuv420Colors();
626
627 for (size_t y = 0; y < 4; ++y) {
628 for (size_t x = 0; x < 4; ++x) {
629 EXPECT_YUV_NEAR(getYuv420Pixel(&image, x, y), colors[y][x]);
630 }
631 }
632}
633
634TEST_F(RecoveryMapMathTest, GetP010Pixel) {
635 jpegr_uncompressed_struct image = P010Image();
636 Color (*colors)[4] = P010Colors();
637
638 for (size_t y = 0; y < 4; ++y) {
639 for (size_t x = 0; x < 4; ++x) {
640 EXPECT_YUV_NEAR(getP010Pixel(&image, x, y), colors[y][x]);
641 }
642 }
643}
644
645TEST_F(RecoveryMapMathTest, SampleYuv420) {
646 jpegr_uncompressed_struct image = Yuv420Image();
647 Color (*colors)[4] = Yuv420Colors();
648
649 static const size_t kMapScaleFactor = 2;
650 for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
651 for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
652 Color min = {{{ 1.0f, 1.0f, 1.0f }}};
653 Color max = {{{ -1.0f, -1.0f, -1.0f }}};
654
655 for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
656 for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
657 Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
658 min = ColorMin(min, e);
659 max = ColorMax(max, e);
660 }
661 }
662
663 // Instead of reimplementing the sampling algorithm, confirm that the
664 // sample output is within the range of the min and max of the nearest
665 // points.
666 EXPECT_YUV_BETWEEN(sampleYuv420(&image, kMapScaleFactor, x, y), min, max);
667 }
668 }
669}
670
671TEST_F(RecoveryMapMathTest, SampleP010) {
672 jpegr_uncompressed_struct image = P010Image();
673 Color (*colors)[4] = P010Colors();
674
675 static const size_t kMapScaleFactor = 2;
676 for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
677 for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
678 Color min = {{{ 1.0f, 1.0f, 1.0f }}};
679 Color max = {{{ -1.0f, -1.0f, -1.0f }}};
680
681 for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
682 for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
683 Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
684 min = ColorMin(min, e);
685 max = ColorMax(max, e);
686 }
687 }
688
689 // Instead of reimplementing the sampling algorithm, confirm that the
690 // sample output is within the range of the min and max of the nearest
691 // points.
692 EXPECT_YUV_BETWEEN(sampleP010(&image, kMapScaleFactor, x, y), min, max);
693 }
694 }
695}
696
697TEST_F(RecoveryMapMathTest, SampleMap) {
698 jpegr_uncompressed_struct image = MapImage();
699 float (*values)[4] = MapValues();
700
701 static const size_t kMapScaleFactor = 2;
702 for (size_t y = 0; y < 4 * kMapScaleFactor; ++y) {
703 for (size_t x = 0; x < 4 * kMapScaleFactor; ++x) {
704 size_t x_base = x / kMapScaleFactor;
705 size_t y_base = y / kMapScaleFactor;
706
707 float min = 1.0f;
708 float max = -1.0f;
709
710 min = fmin(min, values[y_base][x_base]);
711 max = fmax(max, values[y_base][x_base]);
712 if (y_base + 1 < 4) {
713 min = fmin(min, values[y_base + 1][x_base]);
714 max = fmax(max, values[y_base + 1][x_base]);
715 }
716 if (x_base + 1 < 4) {
717 min = fmin(min, values[y_base][x_base + 1]);
718 max = fmax(max, values[y_base][x_base + 1]);
719 }
720 if (y_base + 1 < 4 && x_base + 1 < 4) {
721 min = fmin(min, values[y_base + 1][x_base + 1]);
722 max = fmax(max, values[y_base + 1][x_base + 1]);
723 }
724
725 // Instead of reimplementing the sampling algorithm, confirm that the
726 // sample output is within the range of the min and max of the nearest
727 // points.
728 EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y),
729 testing::AllOf(testing::Ge(min), testing::Le(max)));
730 }
731 }
732}
733
734TEST_F(RecoveryMapMathTest, ColorToRgba1010102) {
735 EXPECT_EQ(colorToRgba1010102(RgbBlack()), 0x3 << 30);
736 EXPECT_EQ(colorToRgba1010102(RgbWhite()), 0xFFFFFFFF);
737 EXPECT_EQ(colorToRgba1010102(RgbRed()), 0x3 << 30 | 0x3ff);
738 EXPECT_EQ(colorToRgba1010102(RgbGreen()), 0x3 << 30 | 0x3ff << 10);
739 EXPECT_EQ(colorToRgba1010102(RgbBlue()), 0x3 << 30 | 0x3ff << 20);
740
741 Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}};
742 EXPECT_EQ(colorToRgba1010102(e_gamma),
743 0x3 << 30
744 | static_cast<uint32_t>(0.1f * static_cast<float>(0x3ff))
745 | static_cast<uint32_t>(0.2f * static_cast<float>(0x3ff)) << 10
746 | static_cast<uint32_t>(0.3f * static_cast<float>(0x3ff)) << 20);
747}
748
749TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgb) {
750 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), srgbLuminance),
751 0.0f);
752 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), srgbLuminance),
753 kSdrWhiteNits);
754 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), srgbLuminance),
755 srgbLuminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
756 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), srgbLuminance),
757 srgbLuminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
758 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), srgbLuminance),
759 srgbLuminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
760}
761
762TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbP3) {
763 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), p3Luminance),
764 0.0f);
765 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), p3Luminance),
766 kSdrWhiteNits);
767 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), p3Luminance),
768 p3Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
769 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), p3Luminance),
770 p3Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
771 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), p3Luminance),
772 p3Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
773}
774
775TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbBt2100) {
776 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), bt2100Luminance),
777 0.0f);
778 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), bt2100Luminance),
779 kSdrWhiteNits);
780 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), bt2100Luminance),
781 bt2100Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
782 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), bt2100Luminance),
783 bt2100Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
784 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), bt2100Luminance),
785 bt2100Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
786}
787
788TEST_F(RecoveryMapMathTest, GenerateMapLuminanceHlg) {
789 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), hlgInvOetf, identityConversion,
790 bt2100Luminance, kHlgMaxNits),
791 0.0f);
792 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), hlgInvOetf, identityConversion,
793 bt2100Luminance, kHlgMaxNits),
794 kHlgMaxNits);
795 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), hlgInvOetf, identityConversion,
796 bt2100Luminance, kHlgMaxNits),
797 bt2100Luminance(RgbRed()) * kHlgMaxNits, LuminanceEpsilon());
798 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), hlgInvOetf, identityConversion,
799 bt2100Luminance, kHlgMaxNits),
800 bt2100Luminance(RgbGreen()) * kHlgMaxNits, LuminanceEpsilon());
801 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), hlgInvOetf, identityConversion,
802 bt2100Luminance, kHlgMaxNits),
803 bt2100Luminance(RgbBlue()) * kHlgMaxNits, LuminanceEpsilon());
804}
805
806TEST_F(RecoveryMapMathTest, GenerateMapLuminancePq) {
807 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), pqInvOetf, identityConversion,
808 bt2100Luminance, kPqMaxNits),
809 0.0f);
810 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), pqInvOetf, identityConversion,
811 bt2100Luminance, kPqMaxNits),
812 kPqMaxNits);
813 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), pqInvOetf, identityConversion,
814 bt2100Luminance, kPqMaxNits),
815 bt2100Luminance(RgbRed()) * kPqMaxNits, LuminanceEpsilon());
816 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), pqInvOetf, identityConversion,
817 bt2100Luminance, kPqMaxNits),
818 bt2100Luminance(RgbGreen()) * kPqMaxNits, LuminanceEpsilon());
819 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), pqInvOetf, identityConversion,
820 bt2100Luminance, kPqMaxNits),
821 bt2100Luminance(RgbBlue()) * kPqMaxNits, LuminanceEpsilon());
822}
823
824//Color Recover(Color yuv_gamma, float recovery, float range_scaling_factor) {
825TEST_F(RecoveryMapMathTest, ApplyMap) {
826 EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, 8.0f),
827 RgbWhite() * 8.0f);
828 EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, 8.0f),
829 RgbBlack());
830 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, 8.0f),
831 RgbRed() * 8.0f);
832 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, 8.0f),
833 RgbGreen() * 8.0f);
834 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, 8.0f),
835 RgbBlue() * 8.0f);
836
837 EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, 8.0f),
838 RgbWhite() * sqrt(8.0f));
839 EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, 8.0f),
840 RgbBlack());
841 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, 8.0f),
842 RgbRed() * sqrt(8.0f));
843 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, 8.0f),
844 RgbGreen() * sqrt(8.0f));
845 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, 8.0f),
846 RgbBlue() * sqrt(8.0f));
847
848 EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, 8.0f),
849 RgbWhite());
850 EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, 8.0f),
851 RgbBlack());
852 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, 8.0f),
853 RgbRed());
854 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, 8.0f),
855 RgbGreen());
856 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, 8.0f),
857 RgbBlue());
858
859 EXPECT_RGB_EQ(Recover(YuvWhite(), -0.5f, 8.0f),
860 RgbWhite() / sqrt(8.0f));
861 EXPECT_RGB_EQ(Recover(YuvBlack(), -0.5f, 8.0f),
862 RgbBlack());
863 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -0.5f, 8.0f),
864 RgbRed() / sqrt(8.0f));
865 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -0.5f, 8.0f),
866 RgbGreen() / sqrt(8.0f));
867 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -0.5f, 8.0f),
868 RgbBlue() / sqrt(8.0f));
869
870 EXPECT_RGB_EQ(Recover(YuvWhite(), -1.0f, 8.0f),
871 RgbWhite() / 8.0f);
872 EXPECT_RGB_EQ(Recover(YuvBlack(), -1.0f, 8.0f),
873 RgbBlack());
874 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -1.0f, 8.0f),
875 RgbRed() / 8.0f);
876 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -1.0f, 8.0f),
877 RgbGreen() / 8.0f);
878 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -1.0f, 8.0f),
879 RgbBlue() / 8.0f);
880}
881
882} // namespace android::recoverymap