diff --git a/lib/src/gainmapmath.cpp b/lib/src/gainmapmath.cpp index fa56c3e8..59f91845 100644 --- a/lib/src/gainmapmath.cpp +++ b/lib/src/gainmapmath.cpp @@ -89,7 +89,7 @@ void ShepardsIDW::fillShepardsIDW(float* weights, int incR, int incB) { // sRGB transformations // See IEC 61966-2-1/Amd 1:2003, Equation F.7. -static const float kSrgbR = 0.2126f, kSrgbG = 0.7152f, kSrgbB = 0.0722f; +static const float kSrgbR = 0.212639f, kSrgbG = 0.715169f, kSrgbB = 0.072192f; float srgbLuminance(Color e) { return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b; } @@ -97,7 +97,7 @@ float srgbLuminance(Color e) { return kSrgbR * e.r + kSrgbG * e.g + kSrgbB * e.b // Uses the same coefficients for deriving luma signal as // IEC 61966-2-1/Amd 1:2003 states for luminance, so we reuse the luminance // function above. -static const float kSrgbCb = 1.8556f, kSrgbCr = 1.5748f; +static const float kSrgbCb = (2 * (1 - kSrgbB)), kSrgbCr = (2 * (1 - kSrgbR)); Color srgbRgbToYuv(Color e_gamma) { float y_gamma = srgbLuminance(e_gamma); @@ -121,7 +121,7 @@ float srgbInvOetf(float e_gamma) { if (e_gamma <= 0.04045f) { return e_gamma / 12.92f; } else { - return pow((e_gamma + 0.055f) / 1.055f, 2.4); + return pow((e_gamma + 0.055f) / 1.055f, 2.4f); } } @@ -129,7 +129,6 @@ Color srgbInvOetf(Color e_gamma) { return {{{srgbInvOetf(e_gamma.r), srgbInvOetf(e_gamma.g), srgbInvOetf(e_gamma.b)}}}; } -// See IEC 61966-2-1, Equations F.5 and F.6. float srgbInvOetfLUT(float e_gamma) { int32_t value = static_cast(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5); // TODO() : Remove once conversion modules have appropriate clamping in place @@ -142,15 +141,16 @@ Color srgbInvOetfLUT(Color e_gamma) { return {{{srgbInvOetfLUT(e_gamma.r), srgbInvOetfLUT(e_gamma.g), srgbInvOetfLUT(e_gamma.b)}}}; } +// See IEC 61966-2-1/Amd 1:2003, Equations F.10 and F.11. float srgbOetf(float e) { - constexpr float kThreshold = 0.0031308; - constexpr float kLowSlope = 12.92; - constexpr float kHighOffset = 0.055; - constexpr float kPowerExponent = 1.0 / 2.4; + constexpr float kThreshold = 0.0031308f; + constexpr float kLowSlope = 12.92f; + constexpr float kHighOffset = 0.055f; + constexpr float kPowerExponent = 1.0f / 2.4f; if (e <= kThreshold) { return kLowSlope * e; } - return (1.0 + kHighOffset) * std::pow(e, kPowerExponent) - kHighOffset; + return (1.0f + kHighOffset) * std::pow(e, kPowerExponent) - kHighOffset; } Color srgbOetf(Color e) { return {{{srgbOetf(e.r), srgbOetf(e.g), srgbOetf(e.b)}}}; } @@ -158,8 +158,8 @@ Color srgbOetf(Color e) { return {{{srgbOetf(e.r), srgbOetf(e.g), srgbOetf(e.b)} //////////////////////////////////////////////////////////////////////////////// // Display-P3 transformations -// See SMPTE EG 432-1, Equation 7-8. -static const float kP3R = 0.20949f, kP3G = 0.72160f, kP3B = 0.06891f; +// See SMPTE EG 432-1, Equation G-7. +static const float kP3R = 0.2289746f, kP3G = 0.6917385f, kP3B = 0.0792869f; float p3Luminance(Color e) { return kP3R * e.r + kP3G * e.g + kP3B * e.b; } @@ -190,14 +190,14 @@ Color p3YuvToRgb(Color e_gamma) { // BT.2100 transformations - according to ITU-R BT.2100-2 // See ITU-R BT.2100-2, Table 5, HLG Reference OOTF -static const float kBt2100R = 0.2627f, kBt2100G = 0.6780f, kBt2100B = 0.0593f; +static const float kBt2100R = 0.2627f, kBt2100G = 0.677998f, kBt2100B = 0.059302f; float bt2100Luminance(Color e) { return kBt2100R * e.r + kBt2100G * e.g + kBt2100B * e.b; } // See ITU-R BT.2100-2, Table 6, Derivation of colour difference signals. // BT.2100 uses the same coefficients for calculating luma signal and luminance, // so we reuse the luminance function here. -static const float kBt2100Cb = 1.8814f, kBt2100Cr = 1.4746f; +static const float kBt2100Cb = (2 * (1 - kBt2100B)), kBt2100Cr = (2 * (1 - kBt2100R)); Color bt2100RgbToYuv(Color e_gamma) { float y_gamma = bt2100Luminance(e_gamma); @@ -239,7 +239,7 @@ Color bt2100YuvToRgb(Color e_gamma) { } // See ITU-R BT.2100-2, Table 5, HLG Reference OETF. -static const float kHlgA = 0.17883277f, kHlgB = 0.28466892f, kHlgC = 0.55991073; +static const float kHlgA = 0.17883277f, kHlgB = 0.28466892f, kHlgC = 0.55991073f; float hlgOetf(float e) { if (e <= 1.0f / 12.0f) { @@ -286,9 +286,11 @@ Color hlgInvOetfLUT(Color e_gamma) { return {{{hlgInvOetfLUT(e_gamma.r), hlgInvOetfLUT(e_gamma.g), hlgInvOetfLUT(e_gamma.b)}}}; } -// 1.2f + 0.42 * log(kHlgMaxNits / 1000) +// See ITU-R BT.2100-2, Table 5, Note 5f +// Gamma = 1.2 + 0.42 * log(kHlgMaxNits / 1000) static const float kOotfGamma = 1.2f; +// See ITU-R BT.2100-2, Table 5, HLG Reference OOTF Color hlgOotf(Color e, LuminanceFn luminance) { float y = luminance(e); return e * std::pow(y, kOotfGamma - 1.0f); @@ -298,6 +300,7 @@ Color hlgOotfApprox(Color e, [[maybe_unused]] LuminanceFn luminance) { return {{{std::pow(e.r, kOotfGamma), std::pow(e.g, kOotfGamma), std::pow(e.b, kOotfGamma)}}}; } +// See ITU-R BT.2100-2, Table 5, Note 5i Color hlgInverseOotf(Color e, LuminanceFn luminance) { float y = luminance(e); return e * std::pow(y, (1.0f / kOotfGamma) - 1.0f); @@ -600,41 +603,43 @@ void putYuv444Pixel(uhdr_raw_image_t* image, size_t x, size_t y, Color& pixel) { //////////////////////////////////////////////////////////////////////////////// // Color space conversions +// Sample, See, +// https://registry.khronos.org/DataFormat/specs/1.3/dataformat.1.3.html#_bt_709_bt_2020_primary_conversion_example Color bt709ToP3(Color e) { - return {{{0.82254f * e.r + 0.17755f * e.g + 0.00006f * e.b, - 0.03312f * e.r + 0.96684f * e.g + -0.00001f * e.b, - 0.01706f * e.r + 0.07240f * e.g + 0.91049f * e.b}}}; + return {{{0.822462f * e.r + 0.177537f * e.g + 0.000001f * e.b, + 0.033194f * e.r + 0.966807f * e.g + -0.000001f * e.b, + 0.017083f * e.r + 0.072398f * e.g + 0.91052f * e.b}}}; } Color bt709ToBt2100(Color e) { - return {{{0.62740f * e.r + 0.32930f * e.g + 0.04332f * e.b, - 0.06904f * e.r + 0.91958f * e.g + 0.01138f * e.b, - 0.01636f * e.r + 0.08799f * e.g + 0.89555f * e.b}}}; + return {{{0.627404f * e.r + 0.329282f * e.g + 0.043314f * e.b, + 0.069097f * e.r + 0.919541f * e.g + 0.011362f * e.b, + 0.016392f * e.r + 0.088013f * e.g + 0.895595f * e.b}}}; } Color p3ToBt709(Color e) { - return {{{1.22482f * e.r + -0.22490f * e.g + -0.00007f * e.b, - -0.04196f * e.r + 1.04199f * e.g + 0.00001f * e.b, - -0.01961f * e.r + -0.07865f * e.g + 1.09831f * e.b}}}; + return {{{1.22494f * e.r + -0.22494f * e.g + 0.0f * e.b, + -0.042057f * e.r + 1.042057f * e.g + 0.0f * e.b, + -0.019638f * e.r + -0.078636f * e.g + 1.098274f * e.b}}}; } Color p3ToBt2100(Color e) { - return {{{0.75378f * e.r + 0.19862f * e.g + 0.04754f * e.b, - 0.04576f * e.r + 0.94177f * e.g + 0.01250f * e.b, - -0.00121f * e.r + 0.01757f * e.g + 0.98359f * e.b}}}; + return {{{0.753833f * e.r + 0.198597f * e.g + 0.04757f * e.b, + 0.045744f * e.r + 0.941777f * e.g + 0.012479f * e.b, + -0.00121f * e.r + 0.017601f * e.g + 0.983608f * e.b}}}; } Color bt2100ToBt709(Color e) { - return {{{1.66045f * e.r + -0.58764f * e.g + -0.07286f * e.b, - -0.12445f * e.r + 1.13282f * e.g + -0.00837f * e.b, - -0.01811f * e.r + -0.10057f * e.g + 1.11878f * e.b}}}; + return {{{1.660491f * e.r + -0.587641f * e.g + -0.07285f * e.b, + -0.124551f * e.r + 1.1329f * e.g + -0.008349f * e.b, + -0.018151f * e.r + -0.100579f * e.g + 1.11873f * e.b}}}; } Color bt2100ToP3(Color e) { - return {{{1.34369f * e.r + -0.28223f * e.g + -0.06135f * e.b, - -0.06533f * e.r + 1.07580f * e.g + -0.01051f * e.b, - 0.00283f * e.r + -0.01957f * e.g + 1.01679f * e.b}}}; + return {{{1.343578f * e.r + -0.282179f * e.g + -0.061399f * e.b, + -0.065298f * e.r + 1.075788f * e.g + -0.01049f * e.b, + 0.002822f * e.r + -0.019598f * e.g + 1.016777f * e.b}}}; } // All of these conversions are derived from the respective input YUV->RGB conversion followed by diff --git a/lib/src/icc.cpp b/lib/src/icc.cpp index 64f0505f..0f184ce6 100644 --- a/lib/src/icc.cpp +++ b/lib/src/icc.cpp @@ -601,7 +601,7 @@ std::shared_ptr IccHelper::writeIccProfile(uhdr_color_transfer_t tf, bool IccHelper::tagsEqualToMatrix(const Matrix3x3& matrix, const uint8_t* red_tag, const uint8_t* green_tag, const uint8_t* blue_tag) { - const float tolerance = 0.001; + const float tolerance = 0.001f; Fixed r_x_fixed = Endian_SwapBE32(reinterpret_cast(const_cast(red_tag))[2]); Fixed r_y_fixed = Endian_SwapBE32(reinterpret_cast(const_cast(red_tag))[3]); Fixed r_z_fixed = Endian_SwapBE32(reinterpret_cast(const_cast(red_tag))[4]); diff --git a/lib/src/jpegr.cpp b/lib/src/jpegr.cpp index 1f83b34d..7e1df212 100644 --- a/lib/src/jpegr.cpp +++ b/lib/src/jpegr.cpp @@ -920,7 +920,7 @@ uhdr_error_info_t JpegR::generateGainMap(uhdr_raw_image_t* sdr_intent, uhdr_raw_ min_content_boost_log2 = (std::max)(min_content_boost_log2, suggestion); } if (fabs(max_content_boost_log2 - min_content_boost_log2) < FLT_EPSILON) { - max_content_boost_log2 += 0.1; // to avoid div by zero during affine transform + max_content_boost_log2 += 0.1f; // to avoid div by zero during affine transform } std::function encodeMap = [this, gainmap_data, map_width, dest, min_content_boost_log2, @@ -1422,7 +1422,7 @@ uhdr_error_info_t JpegR::applyGainMap(uhdr_raw_image_t* sdr_intent, uhdr_raw_ima float gainmap_aspect_ratio = (float)gainmap_img->w / gainmap_img->h; float delta_aspect_ratio = fabs(primary_aspect_ratio - gainmap_aspect_ratio); // Allow 1% delta - const float delta_tolerance = 0.01; + const float delta_tolerance = 0.01f; if (delta_aspect_ratio / primary_aspect_ratio > delta_tolerance) { resized_gainmap = resize_image(gainmap_img, sdr_intent->w, sdr_intent->h); if (resized_gainmap == nullptr) { @@ -1697,8 +1697,8 @@ uhdr_error_info_t JpegR::parseJpegInfo(uhdr_compressed_image_t* jpeg_image, j_in } static float ReinhardMap(float y_hdr, float headroom) { - float out = 1.0 + y_hdr / (headroom * headroom); - out /= 1.0 + y_hdr; + float out = 1.0f + y_hdr / (headroom * headroom); + out /= 1.0f + y_hdr; return out * y_hdr; } diff --git a/tests/gainmapmath_test.cpp b/tests/gainmapmath_test.cpp index 91d942a8..ecc1d695 100644 --- a/tests/gainmapmath_test.cpp +++ b/tests/gainmapmath_test.cpp @@ -540,9 +540,9 @@ TEST_F(GainMapMathTest, ColorDivideFloat) { TEST_F(GainMapMathTest, SrgbLuminance) { EXPECT_FLOAT_EQ(srgbLuminance(RgbBlack()), 0.0f); EXPECT_FLOAT_EQ(srgbLuminance(RgbWhite()), 1.0f); - EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.2126f); - EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.7152f); - EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.0722f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbRed()), 0.212639f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbGreen()), 0.715169f); + EXPECT_FLOAT_EQ(srgbLuminance(RgbBlue()), 0.072192f); } TEST_F(GainMapMathTest, SrgbYuvToRgb) { @@ -607,9 +607,9 @@ TEST_F(GainMapMathTest, SrgbTransferFunction) { TEST_F(GainMapMathTest, P3Luminance) { EXPECT_FLOAT_EQ(p3Luminance(RgbBlack()), 0.0f); EXPECT_FLOAT_EQ(p3Luminance(RgbWhite()), 1.0f); - EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.20949f); - EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.72160f); - EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.06891f); + EXPECT_FLOAT_EQ(p3Luminance(RgbRed()), 0.2289746f); + EXPECT_FLOAT_EQ(p3Luminance(RgbGreen()), 0.6917385f); + EXPECT_FLOAT_EQ(p3Luminance(RgbBlue()), 0.0792869f); } TEST_F(GainMapMathTest, P3YuvToRgb) { @@ -666,8 +666,8 @@ TEST_F(GainMapMathTest, Bt2100Luminance) { EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlack()), 0.0f); EXPECT_FLOAT_EQ(bt2100Luminance(RgbWhite()), 1.0f); EXPECT_FLOAT_EQ(bt2100Luminance(RgbRed()), 0.2627f); - EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.6780f); - EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.0593f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbGreen()), 0.677998f); + EXPECT_FLOAT_EQ(bt2100Luminance(RgbBlue()), 0.059302f); } TEST_F(GainMapMathTest, Bt2100YuvToRgb) {