opsin_image_test.cc (4577B)
1 // Copyright (c) the JPEG XL Project Authors. All rights reserved. 2 // 3 // Use of this source code is governed by a BSD-style 4 // license that can be found in the LICENSE file. 5 6 #include <jxl/cms.h> 7 #include <jxl/memory_manager.h> 8 9 #include <cstddef> 10 #include <utility> 11 12 #include "lib/jxl/base/compiler_specific.h" 13 #include "lib/jxl/base/matrix_ops.h" 14 #include "lib/jxl/base/rect.h" 15 #include "lib/jxl/cms/opsin_params.h" 16 #include "lib/jxl/dec_xyb.h" 17 #include "lib/jxl/enc_xyb.h" 18 #include "lib/jxl/image.h" 19 #include "lib/jxl/image_bundle.h" 20 #include "lib/jxl/image_metadata.h" 21 #include "lib/jxl/opsin_params.h" 22 #include "lib/jxl/test_memory_manager.h" 23 #include "lib/jxl/test_utils.h" 24 #include "lib/jxl/testing.h" 25 26 namespace jxl { 27 namespace { 28 29 // Convert a single linear sRGB color to xyb, using the exact image conversion 30 // procedure that jpeg xl uses. 31 void LinearSrgbToOpsin(float rgb_r, float rgb_g, float rgb_b, 32 float* JXL_RESTRICT xyb_x, float* JXL_RESTRICT xyb_y, 33 float* JXL_RESTRICT xyb_b) { 34 JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); 35 JXL_TEST_ASSIGN_OR_DIE(Image3F linear, Image3F::Create(memory_manager, 1, 1)); 36 linear.PlaneRow(0, 0)[0] = rgb_r; 37 linear.PlaneRow(1, 0)[0] = rgb_g; 38 linear.PlaneRow(2, 0)[0] = rgb_b; 39 40 ImageMetadata metadata; 41 metadata.SetFloat32Samples(); 42 metadata.color_encoding = ColorEncoding::LinearSRGB(); 43 ImageBundle ib(memory_manager, &metadata); 44 ASSERT_TRUE(ib.SetFromImage(std::move(linear), metadata.color_encoding)); 45 JXL_TEST_ASSIGN_OR_DIE(Image3F opsin, Image3F::Create(memory_manager, 1, 1)); 46 (void)ToXYB(ib, /*pool=*/nullptr, &opsin, *JxlGetDefaultCms()); 47 48 *xyb_x = opsin.PlaneRow(0, 0)[0]; 49 *xyb_y = opsin.PlaneRow(1, 0)[0]; 50 *xyb_b = opsin.PlaneRow(2, 0)[0]; 51 } 52 53 // Convert a single XYB color to linear sRGB, using the exact image conversion 54 // procedure that jpeg xl uses. 55 void OpsinToLinearSrgb(float xyb_x, float xyb_y, float xyb_b, 56 float* JXL_RESTRICT rgb_r, float* JXL_RESTRICT rgb_g, 57 float* JXL_RESTRICT rgb_b) { 58 JxlMemoryManager* memory_manager = jxl::test::MemoryManager(); 59 JXL_TEST_ASSIGN_OR_DIE(Image3F opsin, Image3F::Create(memory_manager, 1, 1)); 60 opsin.PlaneRow(0, 0)[0] = xyb_x; 61 opsin.PlaneRow(1, 0)[0] = xyb_y; 62 opsin.PlaneRow(2, 0)[0] = xyb_b; 63 JXL_TEST_ASSIGN_OR_DIE(Image3F linear, Image3F::Create(memory_manager, 1, 1)); 64 OpsinParams opsin_params; 65 opsin_params.Init(/*intensity_target=*/255.0f); 66 ASSERT_TRUE( 67 OpsinToLinear(opsin, Rect(opsin), nullptr, &linear, opsin_params)); 68 *rgb_r = linear.PlaneRow(0, 0)[0]; 69 *rgb_g = linear.PlaneRow(1, 0)[0]; 70 *rgb_b = linear.PlaneRow(2, 0)[0]; 71 } 72 73 void OpsinRoundtripTestRGB(float r, float g, float b) { 74 float xyb_x; 75 float xyb_y; 76 float xyb_b; 77 LinearSrgbToOpsin(r, g, b, &xyb_x, &xyb_y, &xyb_b); 78 float r2; 79 float g2; 80 float b2; 81 OpsinToLinearSrgb(xyb_x, xyb_y, xyb_b, &r2, &g2, &b2); 82 EXPECT_NEAR(r, r2, 1e-3); 83 EXPECT_NEAR(g, g2, 1e-3); 84 EXPECT_NEAR(b, b2, 1e-3); 85 } 86 87 TEST(OpsinImageTest, VerifyOpsinAbsorbanceInverseMatrix) { 88 Matrix3x3 matrix; // writable copy 89 matrix = GetOpsinAbsorbanceInverseMatrix(); 90 EXPECT_TRUE(Inv3x3Matrix(matrix)); 91 for (int j = 0; j < 3; j++) { 92 for (int i = 0; i < 3; i++) { 93 EXPECT_NEAR(matrix[j][i], jxl::cms::kOpsinAbsorbanceMatrix[j][i], 1e-6); 94 } 95 } 96 } 97 98 TEST(OpsinImageTest, OpsinRoundtrip) { 99 OpsinRoundtripTestRGB(0, 0, 0); 100 OpsinRoundtripTestRGB(1. / 255, 1. / 255, 1. / 255); 101 OpsinRoundtripTestRGB(128. / 255, 128. / 255, 128. / 255); 102 OpsinRoundtripTestRGB(1, 1, 1); 103 104 OpsinRoundtripTestRGB(0, 0, 1. / 255); 105 OpsinRoundtripTestRGB(0, 0, 128. / 255); 106 OpsinRoundtripTestRGB(0, 0, 1); 107 108 OpsinRoundtripTestRGB(0, 1. / 255, 0); 109 OpsinRoundtripTestRGB(0, 128. / 255, 0); 110 OpsinRoundtripTestRGB(0, 1, 0); 111 112 OpsinRoundtripTestRGB(1. / 255, 0, 0); 113 OpsinRoundtripTestRGB(128. / 255, 0, 0); 114 OpsinRoundtripTestRGB(1, 0, 0); 115 } 116 117 TEST(OpsinImageTest, VerifyZero) { 118 // Test that black color (zero energy) is 0,0,0 in xyb. 119 float x; 120 float y; 121 float b; 122 LinearSrgbToOpsin(0, 0, 0, &x, &y, &b); 123 EXPECT_NEAR(0, x, 1e-9); 124 EXPECT_NEAR(0, y, 1e-7); 125 EXPECT_NEAR(0, b, 1e-7); 126 } 127 128 TEST(OpsinImageTest, VerifyGray) { 129 // Test that grayscale colors have a fixed y/b ratio and x==0. 130 for (size_t i = 1; i < 255; i++) { 131 float x; 132 float y; 133 float b; 134 LinearSrgbToOpsin(i / 255., i / 255., i / 255., &x, &y, &b); 135 EXPECT_NEAR(0, x, 1e-6); 136 EXPECT_NEAR(jxl::cms::kYToBRatio, b / y, 3e-5); 137 } 138 } 139 140 } // namespace 141 } // namespace jxl