-
Notifications
You must be signed in to change notification settings - Fork 77
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Additional color transfers #81
Changes from all commits
a3b4375
97917d8
d0a79b4
4d4eb54
662c8d6
bfad217
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -15,6 +15,9 @@ namespace { | |
constexpr float REC709_ALPHA = 1.09929682680944f; | ||
constexpr float REC709_BETA = 0.018053968510807f; | ||
|
||
constexpr float SMPTE_240M_ALPHA = 1.1115; | ||
constexpr float SMPTE_240M_BETA = 0.0228; | ||
|
||
constexpr float SRGB_ALPHA = 1.055f; | ||
constexpr float SRGB_BETA = 0.0031308f; | ||
|
||
|
@@ -114,6 +117,66 @@ float rec_1886_inverse_eotf(float x) noexcept | |
return x < 0.0f ? 0.0f : zimg_x_powf(x, 1.0f / 2.4f); | ||
} | ||
|
||
float log100_oetf(float x) noexcept | ||
{ | ||
return x <= 0.01f ? 0 : 1.0f + log10f(x) / 2.0f; | ||
} | ||
|
||
float log100_inverse_oetf(float x) noexcept | ||
{ | ||
return x <= 0.0f ? 0.01f : zimg_x_powf(10, 2 * (x - 1.0f)); | ||
} | ||
|
||
float log316_oetf(float x) noexcept | ||
{ | ||
return x <= 0.0316227766f ? 0 : 1.0f + log10f(x) / 2.5f; | ||
} | ||
|
||
float log316_inverse_oetf(float x) noexcept | ||
{ | ||
return x <= 0.0f ? 0.00316227766f : zimg_x_powf(10, 2.5 * (x - 1.0f)); | ||
} | ||
|
||
float rec_470m_eotf(float x) noexcept | ||
{ | ||
return x < 0.0f ? 0.0f : zimg_x_powf(x, 2.2f); | ||
} | ||
|
||
float rec_470m_inverse_eotf(float x) noexcept | ||
{ | ||
return x < 0.0f ? 0.0f : zimg_x_powf(x, 1.0f / 2.2f); | ||
} | ||
|
||
float rec_470bg_eotf(float x) noexcept | ||
{ | ||
return x < 0.0f ? 0.0f : zimg_x_powf(x, 2.8f); | ||
} | ||
|
||
float rec_470bg_inverse_eotf(float x) noexcept | ||
{ | ||
return x < 0.0f ? 0.0f : zimg_x_powf(x, 1.0f / 2.8f); | ||
} | ||
|
||
float smpte_240m_oetf(float x) noexcept | ||
{ | ||
if (x < 4.0f * SMPTE_240M_BETA) | ||
x = x / 4.0f; | ||
else | ||
x = zimg_x_powf((x + (SMPTE_240M_ALPHA - 1.0f)) / SMPTE_240M_ALPHA, 1.0f / 0.45f); | ||
|
||
return x; | ||
} | ||
|
||
float smpte_240m_inverse_oetf(float x) noexcept | ||
{ | ||
if (x < SMPTE_240M_BETA) | ||
x = x * 4.0f; | ||
else | ||
x = SMPTE_240M_ALPHA * zimg_x_powf(x, 0.45f) - (SMPTE_240M_ALPHA - 1.0f); | ||
|
||
return x; | ||
} | ||
|
||
float srgb_eotf(float x) noexcept | ||
{ | ||
if (x < 12.92f * SRGB_BETA) | ||
|
@@ -134,6 +197,16 @@ float srgb_inverse_eotf(float x) noexcept | |
return x; | ||
} | ||
|
||
float xvycc_eotf(float x) noexcept | ||
{ | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. xvYCC should be implemented as a mirrored Rec.709 OETF. In other words, copysign(rec709_oetf(fabs(x)), x). There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It is also still unclear if the standard gamut portion of xvYCC should be handled with Rec.1886, which is what would occur if the signal were to reach a non-xv TV. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I tried using rec 709 but the colors when not display correctly with quicktime. I had to use the pure power bt1886 instead. Regarding the last point we could maybe introduce a new range type? This is what the specs say on that regard
or maybe let the applications deal with it? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you elaborate on how you used QuickTime to test this? The problem with using BT.1886 instead of Rec.709 outside of the [0-1] range, i.e. the extended gamut, is that it affects the gamut width. For example, 1.2^2.2 (BT.709) is less saturated than 1.2^2.4 (BT.1886). The behavior needs to be compared to a reference xvYCC implementation. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I converted a video containing xvycc with zimg and made sure colors matches the ones of the original video, can post pics if needed. |
||
return copysign(rec_1886_eotf(fabs(x)), x); | ||
} | ||
|
||
float xvycc_inverse_eotf(float x) noexcept | ||
{ | ||
return copysign(rec_1886_inverse_eotf(fabs(x)), x); | ||
} | ||
|
||
float st_2084_eotf(float x) noexcept | ||
{ | ||
// Filter negative values to avoid NAN. | ||
|
@@ -204,10 +277,34 @@ TransferFunction select_transfer_function(TransferCharacteristics transfer, doub | |
func.to_gamma_scale = 1.0f; | ||
|
||
switch (transfer) { | ||
case TransferCharacteristics::LOG_100: | ||
func.to_linear = log100_inverse_oetf; | ||
func.to_gamma = log100_oetf; | ||
break; | ||
case TransferCharacteristics::LOG_316: | ||
func.to_linear = log316_inverse_oetf; | ||
func.to_gamma = log316_oetf; | ||
break; | ||
case TransferCharacteristics::REC_709: | ||
func.to_linear = scene_referred ? rec_709_inverse_oetf : rec_1886_eotf; | ||
func.to_gamma = scene_referred ? rec_709_oetf : rec_1886_inverse_eotf; | ||
break; | ||
case TransferCharacteristics::REC_470_M: | ||
func.to_linear = rec_470m_eotf; | ||
func.to_gamma = rec_470m_inverse_eotf; | ||
break; | ||
case TransferCharacteristics::REC_470_BG: | ||
func.to_linear = rec_470bg_eotf; | ||
func.to_gamma = rec_470bg_inverse_eotf; | ||
break; | ||
case TransferCharacteristics::SMPTE_240M: | ||
func.to_linear = scene_referred ? smpte_240m_inverse_oetf : rec_1886_eotf; | ||
func.to_gamma = scene_referred ? smpte_240m_oetf : rec_1886_inverse_eotf; | ||
break; | ||
case TransferCharacteristics::XVYCC: | ||
func.to_linear = xvycc_eotf; | ||
func.to_gamma = xvycc_inverse_eotf; | ||
break; | ||
case TransferCharacteristics::SRGB: | ||
func.to_linear = srgb_eotf; | ||
func.to_gamma = srgb_inverse_eotf; | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
SMPTE 240M, like all other legacy gamma functions, is an OETF. The EOTF should be BT.1886.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
oh good point, should I just reflect that in the function name or is there something else I am missing?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function name should be updated, and in select_transfer_function, the OETF should only be returned if scene_referred is true. See the other gamma functions.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Attached.
s240m.pdf