Skip to content

Commit

Permalink
fix primaries used for display p3 gamut
Browse files Browse the repository at this point in the history
- luminance function of p3 gamut is using weights of dci p3 instead of
  display p3. this is corrected. accordingly the gamut conversions
  involving display p3 are updated.
- increased precision of some constants used in csc

Test: ./ultrahdr_unit_test
Change-Id: Iec77b3d24adb7ad887a8f53d805eecc0c0160f28
  • Loading branch information
ram-mohan committed Nov 28, 2024
1 parent cff53d3 commit ee9e793
Show file tree
Hide file tree
Showing 4 changed files with 51 additions and 46 deletions.
71 changes: 38 additions & 33 deletions lib/src/gainmapmath.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -89,15 +89,15 @@ 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; }

// See ITU-R BT.709-6, Section 3.
// 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);
Expand All @@ -121,15 +121,14 @@ 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);
}
}

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<int32_t>(e_gamma * (kSrgbInvOETFNumEntries - 1) + 0.5);
// TODO() : Remove once conversion modules have appropriate clamping in place
Expand All @@ -142,24 +141,25 @@ 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)}}}; }

////////////////////////////////////////////////////////////////////////////////
// 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; }

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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);
Expand All @@ -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);
Expand Down Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion lib/src/icc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -601,7 +601,7 @@ std::shared_ptr<DataStruct> 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<int32_t*>(const_cast<uint8_t*>(red_tag))[2]);
Fixed r_y_fixed = Endian_SwapBE32(reinterpret_cast<int32_t*>(const_cast<uint8_t*>(red_tag))[3]);
Fixed r_z_fixed = Endian_SwapBE32(reinterpret_cast<int32_t*>(const_cast<uint8_t*>(red_tag))[4]);
Expand Down
8 changes: 4 additions & 4 deletions lib/src/jpegr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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<void()> encodeMap = [this, gainmap_data, map_width, dest, min_content_boost_log2,
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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;
}

Expand Down
16 changes: 8 additions & 8 deletions tests/gainmapmath_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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) {
Expand Down

0 comments on commit ee9e793

Please sign in to comment.