blob: 1d522d186081670fc24c6bfae4f2b7f0665c2242 [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) {
Nick Deakin38125332022-12-12 15:48:24 -050039 return {{{ (static_cast<float>(y) - 64.0f) / 876.0f,
40 (static_cast<float>(u) - 64.0f) / 896.0f - 0.5f,
41 (static_cast<float>(v) - 64.0f) / 896.0f - 0.5f }}};
Nick Deakin65f492a2022-11-29 22:47:40 -050042 }
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
Harish Mahendrakar555a06b2022-12-14 09:37:27 -0800520TEST_F(RecoveryMapMathTest, PqInvOetfLUT) {
521 float increment = 1.0 / 1024.0;
522 float value = 0.0f;
523 for (int idx = 0; idx < 1024; idx++, value += increment) {
524 EXPECT_FLOAT_EQ(pqInvOetf(value), pqInvOetfLUT(value));
525 }
526}
527
528TEST_F(RecoveryMapMathTest, HlgInvOetfLUT) {
529 float increment = 1.0 / 1024.0;
530 float value = 0.0f;
531 for (int idx = 0; idx < 1024; idx++, value += increment) {
532 EXPECT_FLOAT_EQ(hlgInvOetf(value), hlgInvOetfLUT(value));
533 }
534}
535
536TEST_F(RecoveryMapMathTest, pqOetfLUT) {
537 float increment = 1.0 / 1024.0;
538 float value = 0.0f;
539 for (int idx = 0; idx < 1024; idx++, value += increment) {
540 EXPECT_FLOAT_EQ(pqOetf(value), pqOetfLUT(value));
541 }
542}
543
544TEST_F(RecoveryMapMathTest, hlgOetfLUT) {
545 float increment = 1.0 / 1024.0;
546 float value = 0.0f;
547 for (int idx = 0; idx < 1024; idx++, value += increment) {
548 EXPECT_FLOAT_EQ(hlgOetf(value), hlgOetfLUT(value));
549 }
550}
551
552TEST_F(RecoveryMapMathTest, srgbInvOetfLUT) {
553 float increment = 1.0 / 1024.0;
554 float value = 0.0f;
555 for (int idx = 0; idx < 1024; idx++, value += increment) {
556 EXPECT_FLOAT_EQ(srgbInvOetf(value), srgbInvOetfLUT(value));
557 }
558}
559
Harish Mahendrakarf25991f2022-12-16 11:57:44 -0800560TEST_F(RecoveryMapMathTest, applyRecoveryLUT) {
561 float increment = 2.0 / kRecoveryFactorNumEntries;
562 for (float hdrRatio = 1.0f; hdrRatio <= 10.0f; hdrRatio += 1.0f) {
563 RecoveryLUT recoveryLUT(hdrRatio);
564 for (float value = -1.0f; value <= -1.0f; value += increment) {
565 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), value, hdrRatio),
566 applyRecoveryLUT(RgbBlack(), value, recoveryLUT));
567 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), value, hdrRatio),
568 applyRecoveryLUT(RgbWhite(), value, recoveryLUT));
569 EXPECT_RGB_NEAR(applyRecovery(RgbRed(), value, hdrRatio),
570 applyRecoveryLUT(RgbRed(), value, recoveryLUT));
571 EXPECT_RGB_NEAR(applyRecovery(RgbGreen(), value, hdrRatio),
572 applyRecoveryLUT(RgbGreen(), value, recoveryLUT));
573 EXPECT_RGB_NEAR(applyRecovery(RgbBlue(), value, hdrRatio),
574 applyRecoveryLUT(RgbBlue(), value, recoveryLUT));
575 }
576 }
577}
578
Nick Deakin65f492a2022-11-29 22:47:40 -0500579TEST_F(RecoveryMapMathTest, PqTransferFunctionRoundtrip) {
580 EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(0.0f)), 0.0f);
581 EXPECT_NEAR(pqInvOetf(pqOetf(0.01f)), 0.01f, ComparisonEpsilon());
582 EXPECT_NEAR(pqInvOetf(pqOetf(0.5f)), 0.5f, ComparisonEpsilon());
583 EXPECT_NEAR(pqInvOetf(pqOetf(0.99f)), 0.99f, ComparisonEpsilon());
584 EXPECT_FLOAT_EQ(pqInvOetf(pqOetf(1.0f)), 1.0f);
585}
586
587TEST_F(RecoveryMapMathTest, ColorConversionLookup) {
588 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_UNSPECIFIED),
589 nullptr);
590 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT709),
591 identityConversion);
592 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_P3),
593 p3ToBt709);
594 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT709, JPEGR_COLORGAMUT_BT2100),
595 bt2100ToBt709);
596
597 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_UNSPECIFIED),
598 nullptr);
599 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT709),
600 bt709ToP3);
601 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_P3),
602 identityConversion);
603 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_P3, JPEGR_COLORGAMUT_BT2100),
604 bt2100ToP3);
605
606 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_UNSPECIFIED),
607 nullptr);
608 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT709),
609 bt709ToBt2100);
610 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_P3),
611 p3ToBt2100);
612 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_BT2100, JPEGR_COLORGAMUT_BT2100),
613 identityConversion);
614
615 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_UNSPECIFIED),
616 nullptr);
617 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT709),
618 nullptr);
619 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_P3),
620 nullptr);
621 EXPECT_EQ(getHdrConversionFn(JPEGR_COLORGAMUT_UNSPECIFIED, JPEGR_COLORGAMUT_BT2100),
622 nullptr);
623}
624
625TEST_F(RecoveryMapMathTest, EncodeRecovery) {
626 EXPECT_EQ(encodeRecovery(0.0f, 0.0f, 4.0f), 127);
627 EXPECT_EQ(encodeRecovery(0.0f, 1.0f, 4.0f), 127);
628 EXPECT_EQ(encodeRecovery(1.0f, 0.0f, 4.0f), 0);
629 EXPECT_EQ(encodeRecovery(0.5f, 0.0f, 4.0f), 0);
630
631 EXPECT_EQ(encodeRecovery(1.0f, 1.0f, 4.0f), 127);
632 EXPECT_EQ(encodeRecovery(1.0f, 4.0f, 4.0f), 255);
633 EXPECT_EQ(encodeRecovery(1.0f, 5.0f, 4.0f), 255);
634 EXPECT_EQ(encodeRecovery(4.0f, 1.0f, 4.0f), 0);
635 EXPECT_EQ(encodeRecovery(4.0f, 0.5f, 4.0f), 0);
636 EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 4.0f), 191);
637 EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 4.0f), 63);
638
639 EXPECT_EQ(encodeRecovery(1.0f, 2.0f, 2.0f), 255);
640 EXPECT_EQ(encodeRecovery(2.0f, 1.0f, 2.0f), 0);
641 EXPECT_EQ(encodeRecovery(1.0f, 1.41421f, 2.0f), 191);
642 EXPECT_EQ(encodeRecovery(1.41421f, 1.0f, 2.0f), 63);
643
644 EXPECT_EQ(encodeRecovery(1.0f, 8.0f, 8.0f), 255);
645 EXPECT_EQ(encodeRecovery(8.0f, 1.0f, 8.0f), 0);
646 EXPECT_EQ(encodeRecovery(1.0f, 2.82843f, 8.0f), 191);
647 EXPECT_EQ(encodeRecovery(2.82843f, 1.0f, 8.0f), 63);
648}
649
650TEST_F(RecoveryMapMathTest, ApplyRecovery) {
651 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), -1.0f, 4.0f), RgbBlack());
652 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 0.0f, 4.0f), RgbBlack());
653 EXPECT_RGB_NEAR(applyRecovery(RgbBlack(), 1.0f, 4.0f), RgbBlack());
654
655 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 4.0f), RgbWhite() / 4.0f);
656 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 4.0f), RgbWhite() / 2.0f);
657 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 4.0f), RgbWhite());
658 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 4.0f), RgbWhite() * 2.0f);
659 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 4.0f), RgbWhite() * 4.0f);
660
661 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 2.0f), RgbWhite() / 2.0f);
662 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 2.0f), RgbWhite() / 1.41421f);
663 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 2.0f), RgbWhite());
664 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 2.0f), RgbWhite() * 1.41421f);
665 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 2.0f), RgbWhite() * 2.0f);
666
667 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -1.0f, 8.0f), RgbWhite() / 8.0f);
668 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), -0.5f, 8.0f), RgbWhite() / 2.82843f);
669 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.0f, 8.0f), RgbWhite());
670 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 0.5f, 8.0f), RgbWhite() * 2.82843f);
671 EXPECT_RGB_NEAR(applyRecovery(RgbWhite(), 1.0f, 8.0f), RgbWhite() * 8.0f);
672
673 Color e = {{{ 0.0f, 0.5f, 1.0f }}};
674
675 EXPECT_RGB_NEAR(applyRecovery(e, -1.0f, 4.0f), e / 4.0f);
676 EXPECT_RGB_NEAR(applyRecovery(e, -0.5f, 4.0f), e / 2.0f);
677 EXPECT_RGB_NEAR(applyRecovery(e, 0.0f, 4.0f), e);
678 EXPECT_RGB_NEAR(applyRecovery(e, 0.5f, 4.0f), e * 2.0f);
679 EXPECT_RGB_NEAR(applyRecovery(e, 1.0f, 4.0f), e * 4.0f);
680}
681
682TEST_F(RecoveryMapMathTest, GetYuv420Pixel) {
683 jpegr_uncompressed_struct image = Yuv420Image();
684 Color (*colors)[4] = Yuv420Colors();
685
686 for (size_t y = 0; y < 4; ++y) {
687 for (size_t x = 0; x < 4; ++x) {
688 EXPECT_YUV_NEAR(getYuv420Pixel(&image, x, y), colors[y][x]);
689 }
690 }
691}
692
693TEST_F(RecoveryMapMathTest, GetP010Pixel) {
694 jpegr_uncompressed_struct image = P010Image();
695 Color (*colors)[4] = P010Colors();
696
697 for (size_t y = 0; y < 4; ++y) {
698 for (size_t x = 0; x < 4; ++x) {
699 EXPECT_YUV_NEAR(getP010Pixel(&image, x, y), colors[y][x]);
700 }
701 }
702}
703
704TEST_F(RecoveryMapMathTest, SampleYuv420) {
705 jpegr_uncompressed_struct image = Yuv420Image();
706 Color (*colors)[4] = Yuv420Colors();
707
708 static const size_t kMapScaleFactor = 2;
709 for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
710 for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
711 Color min = {{{ 1.0f, 1.0f, 1.0f }}};
712 Color max = {{{ -1.0f, -1.0f, -1.0f }}};
713
714 for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
715 for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
716 Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
717 min = ColorMin(min, e);
718 max = ColorMax(max, e);
719 }
720 }
721
722 // Instead of reimplementing the sampling algorithm, confirm that the
723 // sample output is within the range of the min and max of the nearest
724 // points.
725 EXPECT_YUV_BETWEEN(sampleYuv420(&image, kMapScaleFactor, x, y), min, max);
726 }
727 }
728}
729
730TEST_F(RecoveryMapMathTest, SampleP010) {
731 jpegr_uncompressed_struct image = P010Image();
732 Color (*colors)[4] = P010Colors();
733
734 static const size_t kMapScaleFactor = 2;
735 for (size_t y = 0; y < 4 / kMapScaleFactor; ++y) {
736 for (size_t x = 0; x < 4 / kMapScaleFactor; ++x) {
737 Color min = {{{ 1.0f, 1.0f, 1.0f }}};
738 Color max = {{{ -1.0f, -1.0f, -1.0f }}};
739
740 for (size_t dy = 0; dy < kMapScaleFactor; ++dy) {
741 for (size_t dx = 0; dx < kMapScaleFactor; ++dx) {
742 Color e = colors[y * kMapScaleFactor + dy][x * kMapScaleFactor + dx];
743 min = ColorMin(min, e);
744 max = ColorMax(max, e);
745 }
746 }
747
748 // Instead of reimplementing the sampling algorithm, confirm that the
749 // sample output is within the range of the min and max of the nearest
750 // points.
751 EXPECT_YUV_BETWEEN(sampleP010(&image, kMapScaleFactor, x, y), min, max);
752 }
753 }
754}
755
756TEST_F(RecoveryMapMathTest, SampleMap) {
757 jpegr_uncompressed_struct image = MapImage();
758 float (*values)[4] = MapValues();
759
760 static const size_t kMapScaleFactor = 2;
Ram Mohanfe723d62022-12-15 00:59:11 +0530761 ShepardsIDW idwTable(kMapScaleFactor);
Nick Deakin65f492a2022-11-29 22:47:40 -0500762 for (size_t y = 0; y < 4 * kMapScaleFactor; ++y) {
763 for (size_t x = 0; x < 4 * kMapScaleFactor; ++x) {
764 size_t x_base = x / kMapScaleFactor;
765 size_t y_base = y / kMapScaleFactor;
766
767 float min = 1.0f;
768 float max = -1.0f;
769
770 min = fmin(min, values[y_base][x_base]);
771 max = fmax(max, values[y_base][x_base]);
772 if (y_base + 1 < 4) {
773 min = fmin(min, values[y_base + 1][x_base]);
774 max = fmax(max, values[y_base + 1][x_base]);
775 }
776 if (x_base + 1 < 4) {
777 min = fmin(min, values[y_base][x_base + 1]);
778 max = fmax(max, values[y_base][x_base + 1]);
779 }
780 if (y_base + 1 < 4 && x_base + 1 < 4) {
781 min = fmin(min, values[y_base + 1][x_base + 1]);
782 max = fmax(max, values[y_base + 1][x_base + 1]);
783 }
784
785 // Instead of reimplementing the sampling algorithm, confirm that the
786 // sample output is within the range of the min and max of the nearest
787 // points.
Ram Mohanfe723d62022-12-15 00:59:11 +0530788 EXPECT_THAT(sampleMap(&image, kMapScaleFactor, x, y, idwTable),
Nick Deakin65f492a2022-11-29 22:47:40 -0500789 testing::AllOf(testing::Ge(min), testing::Le(max)));
790 }
791 }
792}
793
794TEST_F(RecoveryMapMathTest, ColorToRgba1010102) {
795 EXPECT_EQ(colorToRgba1010102(RgbBlack()), 0x3 << 30);
796 EXPECT_EQ(colorToRgba1010102(RgbWhite()), 0xFFFFFFFF);
797 EXPECT_EQ(colorToRgba1010102(RgbRed()), 0x3 << 30 | 0x3ff);
798 EXPECT_EQ(colorToRgba1010102(RgbGreen()), 0x3 << 30 | 0x3ff << 10);
799 EXPECT_EQ(colorToRgba1010102(RgbBlue()), 0x3 << 30 | 0x3ff << 20);
800
801 Color e_gamma = {{{ 0.1f, 0.2f, 0.3f }}};
802 EXPECT_EQ(colorToRgba1010102(e_gamma),
803 0x3 << 30
804 | static_cast<uint32_t>(0.1f * static_cast<float>(0x3ff))
805 | static_cast<uint32_t>(0.2f * static_cast<float>(0x3ff)) << 10
806 | static_cast<uint32_t>(0.3f * static_cast<float>(0x3ff)) << 20);
807}
808
809TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgb) {
810 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), srgbLuminance),
811 0.0f);
812 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), srgbLuminance),
813 kSdrWhiteNits);
814 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), srgbLuminance),
815 srgbLuminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
816 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), srgbLuminance),
817 srgbLuminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
818 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), srgbLuminance),
819 srgbLuminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
820}
821
822TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbP3) {
823 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), p3Luminance),
824 0.0f);
825 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), p3Luminance),
826 kSdrWhiteNits);
827 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), p3Luminance),
828 p3Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
829 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), p3Luminance),
830 p3Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
831 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), p3Luminance),
832 p3Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
833}
834
835TEST_F(RecoveryMapMathTest, GenerateMapLuminanceSrgbBt2100) {
836 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvBlack(), bt2100Luminance),
837 0.0f);
838 EXPECT_FLOAT_EQ(SrgbYuvToLuminance(YuvWhite(), bt2100Luminance),
839 kSdrWhiteNits);
840 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvRed(), bt2100Luminance),
841 bt2100Luminance(RgbRed()) * kSdrWhiteNits, LuminanceEpsilon());
842 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvGreen(), bt2100Luminance),
843 bt2100Luminance(RgbGreen()) * kSdrWhiteNits, LuminanceEpsilon());
844 EXPECT_NEAR(SrgbYuvToLuminance(SrgbYuvBlue(), bt2100Luminance),
845 bt2100Luminance(RgbBlue()) * kSdrWhiteNits, LuminanceEpsilon());
846}
847
848TEST_F(RecoveryMapMathTest, GenerateMapLuminanceHlg) {
849 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), hlgInvOetf, identityConversion,
850 bt2100Luminance, kHlgMaxNits),
851 0.0f);
852 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), hlgInvOetf, identityConversion,
853 bt2100Luminance, kHlgMaxNits),
854 kHlgMaxNits);
855 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), hlgInvOetf, identityConversion,
856 bt2100Luminance, kHlgMaxNits),
857 bt2100Luminance(RgbRed()) * kHlgMaxNits, LuminanceEpsilon());
858 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), hlgInvOetf, identityConversion,
859 bt2100Luminance, kHlgMaxNits),
860 bt2100Luminance(RgbGreen()) * kHlgMaxNits, LuminanceEpsilon());
861 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), hlgInvOetf, identityConversion,
862 bt2100Luminance, kHlgMaxNits),
863 bt2100Luminance(RgbBlue()) * kHlgMaxNits, LuminanceEpsilon());
864}
865
866TEST_F(RecoveryMapMathTest, GenerateMapLuminancePq) {
867 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvBlack(), pqInvOetf, identityConversion,
868 bt2100Luminance, kPqMaxNits),
869 0.0f);
870 EXPECT_FLOAT_EQ(Bt2100YuvToLuminance(YuvWhite(), pqInvOetf, identityConversion,
871 bt2100Luminance, kPqMaxNits),
872 kPqMaxNits);
873 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvRed(), pqInvOetf, identityConversion,
874 bt2100Luminance, kPqMaxNits),
875 bt2100Luminance(RgbRed()) * kPqMaxNits, LuminanceEpsilon());
876 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvGreen(), pqInvOetf, identityConversion,
877 bt2100Luminance, kPqMaxNits),
878 bt2100Luminance(RgbGreen()) * kPqMaxNits, LuminanceEpsilon());
879 EXPECT_NEAR(Bt2100YuvToLuminance(Bt2100YuvBlue(), pqInvOetf, identityConversion,
880 bt2100Luminance, kPqMaxNits),
881 bt2100Luminance(RgbBlue()) * kPqMaxNits, LuminanceEpsilon());
882}
883
Nick Deakin65f492a2022-11-29 22:47:40 -0500884TEST_F(RecoveryMapMathTest, ApplyMap) {
885 EXPECT_RGB_EQ(Recover(YuvWhite(), 1.0f, 8.0f),
886 RgbWhite() * 8.0f);
887 EXPECT_RGB_EQ(Recover(YuvBlack(), 1.0f, 8.0f),
888 RgbBlack());
889 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 1.0f, 8.0f),
890 RgbRed() * 8.0f);
891 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 1.0f, 8.0f),
892 RgbGreen() * 8.0f);
893 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 1.0f, 8.0f),
894 RgbBlue() * 8.0f);
895
896 EXPECT_RGB_EQ(Recover(YuvWhite(), 0.5f, 8.0f),
897 RgbWhite() * sqrt(8.0f));
898 EXPECT_RGB_EQ(Recover(YuvBlack(), 0.5f, 8.0f),
899 RgbBlack());
900 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.5f, 8.0f),
901 RgbRed() * sqrt(8.0f));
902 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.5f, 8.0f),
903 RgbGreen() * sqrt(8.0f));
904 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.5f, 8.0f),
905 RgbBlue() * sqrt(8.0f));
906
907 EXPECT_RGB_EQ(Recover(YuvWhite(), 0.0f, 8.0f),
908 RgbWhite());
909 EXPECT_RGB_EQ(Recover(YuvBlack(), 0.0f, 8.0f),
910 RgbBlack());
911 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), 0.0f, 8.0f),
912 RgbRed());
913 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), 0.0f, 8.0f),
914 RgbGreen());
915 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), 0.0f, 8.0f),
916 RgbBlue());
917
918 EXPECT_RGB_EQ(Recover(YuvWhite(), -0.5f, 8.0f),
919 RgbWhite() / sqrt(8.0f));
920 EXPECT_RGB_EQ(Recover(YuvBlack(), -0.5f, 8.0f),
921 RgbBlack());
922 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -0.5f, 8.0f),
923 RgbRed() / sqrt(8.0f));
924 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -0.5f, 8.0f),
925 RgbGreen() / sqrt(8.0f));
926 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -0.5f, 8.0f),
927 RgbBlue() / sqrt(8.0f));
928
929 EXPECT_RGB_EQ(Recover(YuvWhite(), -1.0f, 8.0f),
930 RgbWhite() / 8.0f);
931 EXPECT_RGB_EQ(Recover(YuvBlack(), -1.0f, 8.0f),
932 RgbBlack());
933 EXPECT_RGB_CLOSE(Recover(SrgbYuvRed(), -1.0f, 8.0f),
934 RgbRed() / 8.0f);
935 EXPECT_RGB_CLOSE(Recover(SrgbYuvGreen(), -1.0f, 8.0f),
936 RgbGreen() / 8.0f);
937 EXPECT_RGB_CLOSE(Recover(SrgbYuvBlue(), -1.0f, 8.0f),
938 RgbBlue() / 8.0f);
939}
940
941} // namespace android::recoverymap