Skip to content
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

Merged
merged 6 commits into from
Oct 20, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 7 additions & 1 deletion src/testapp/table.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -76,10 +76,16 @@ const zimg::static_string_map<MatrixCoefficients, 10> g_matrix_table{
{ "ictcp", MatrixCoefficients::REC_2100_ICTCP },
};

const zimg::static_string_map<TransferCharacteristics, 6> g_transfer_table{
const zimg::static_string_map<TransferCharacteristics, 12> g_transfer_table{
{ "unspec", TransferCharacteristics::UNSPECIFIED },
{ "linear", TransferCharacteristics::LINEAR },
{ "log100", TransferCharacteristics::LOG_100 },
{ "log316", TransferCharacteristics::LOG_316 },
{ "240m", TransferCharacteristics::SMPTE_240M },
{ "709", TransferCharacteristics::REC_709 },
{ "470m", TransferCharacteristics::REC_470_M },
{ "470bg", TransferCharacteristics::REC_470_BG },
{ "xvycc", TransferCharacteristics::XVYCC },
{ "srgb", TransferCharacteristics::SRGB },
{ "st_2084", TransferCharacteristics::ST_2084 },
{ "arib_b67", TransferCharacteristics::ARIB_B67 },
Expand Down
2 changes: 1 addition & 1 deletion src/testapp/table.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class Filter;
extern const zimg::static_string_map<zimg::CPUClass, 8> g_cpu_table;
extern const zimg::static_string_map<zimg::PixelType, 4> g_pixel_table;
extern const zimg::static_string_map<zimg::colorspace::MatrixCoefficients, 10> g_matrix_table;
extern const zimg::static_string_map<zimg::colorspace::TransferCharacteristics, 6> g_transfer_table;
extern const zimg::static_string_map<zimg::colorspace::TransferCharacteristics, 12> g_transfer_table;
extern const zimg::static_string_map<zimg::colorspace::ColorPrimaries, 6> g_primaries_table;
extern const zimg::static_string_map<zimg::depth::DitherType, 4> g_dither_table;
extern const zimg::static_string_map<std::unique_ptr<zimg::resize::Filter>(*)(double, double), 7> g_resize_table;
Expand Down
8 changes: 7 additions & 1 deletion src/zimg/api/zimg.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -250,14 +250,20 @@ zimg::colorspace::TransferCharacteristics translate_transfer(zimg_transfer_chara
{
using zimg::colorspace::TransferCharacteristics;

static SM_CONSTEXPR_14 const zimg::static_map<zimg_transfer_characteristics_e, TransferCharacteristics, 9> map{
static SM_CONSTEXPR_14 const zimg::static_map<zimg_transfer_characteristics_e, TransferCharacteristics, 15> map{
{ ZIMG_TRANSFER_709, TransferCharacteristics::REC_709 },
{ ZIMG_TRANSFER_UNSPECIFIED, TransferCharacteristics::UNSPECIFIED },
{ ZIMG_TRANSFER_240M, TransferCharacteristics::SMPTE_240M },
{ ZIMG_TRANSFER_601, TransferCharacteristics::REC_709 },
{ ZIMG_TRANSFER_470_M, TransferCharacteristics::REC_470_M },
{ ZIMG_TRANSFER_470_BG, TransferCharacteristics::REC_470_BG },
{ ZIMG_TRANSFER_IEC_61966_2_4, TransferCharacteristics::XVYCC },
{ ZIMG_TRANSFER_IEC_61966_2_1, TransferCharacteristics::SRGB },
{ ZIMG_TRANSFER_2020_10, TransferCharacteristics::REC_709 },
{ ZIMG_TRANSFER_2020_12, TransferCharacteristics::REC_709 },
{ ZIMG_TRANSFER_LINEAR, TransferCharacteristics::LINEAR },
{ ZIMG_TRANSFER_LOG_100, TransferCharacteristics::LOG_100 },
{ ZIMG_TRANSFER_LOG_316, TransferCharacteristics::LOG_316 },
{ ZIMG_TRANSFER_ST2084, TransferCharacteristics::ST_2084 },
{ ZIMG_TRANSFER_ARIB_B67, TransferCharacteristics::ARIB_B67 },
};
Expand Down
6 changes: 6 additions & 0 deletions src/zimg/api/zimg.h
Original file line number Diff line number Diff line change
Expand Up @@ -280,8 +280,14 @@ typedef enum zimg_transfer_characteristics_e {
ZIMG_TRANSFER_INTERNAL = -1, /**< Not part of the API. */
ZIMG_TRANSFER_709 = 1,
ZIMG_TRANSFER_UNSPECIFIED = 2,
ZIMG_TRANSFER_470_M = 4,
ZIMG_TRANSFER_470_BG = 5,
ZIMG_TRANSFER_601 = 6, /* Equivalent to 1. */
ZIMG_TRANSFER_240M = 7,
ZIMG_TRANSFER_LINEAR = 8,
ZIMG_TRANSFER_LOG_100 = 9,
ZIMG_TRANSFER_LOG_316 = 10,
ZIMG_TRANSFER_IEC_61966_2_4 = 11,
ZIMG_TRANSFER_IEC_61966_2_1 = 13,
ZIMG_TRANSFER_2020_10 = 14, /* Equivalent to 1. */
ZIMG_TRANSFER_2020_12 = 15, /* Equivalent to 1. */
Expand Down
6 changes: 6 additions & 0 deletions src/zimg/colorspace/colorspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,13 @@ enum class MatrixCoefficients {
enum class TransferCharacteristics {
UNSPECIFIED,
LINEAR,
LOG_100,
LOG_316,
REC_709,
REC_470_M,
REC_470_BG,
SMPTE_240M,
XVYCC,
SRGB,
ST_2084,
ARIB_B67,
Expand Down
97 changes: 97 additions & 0 deletions src/zimg/colorspace/gamma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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);
}
Copy link
Owner

@sekrit-twc sekrit-twc Sep 19, 2017

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.

Copy link
Contributor Author

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?

Copy link
Owner

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.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Attached.

s240m.pdf


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)
Expand All @@ -134,6 +197,16 @@ float srgb_inverse_eotf(float x) noexcept
return x;
}

float xvycc_eotf(float x) noexcept
{
Copy link
Owner

Choose a reason for hiding this comment

The 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).

Copy link
Owner

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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

Otherwise (TransferCharacteristics is equal to 11 (IEC 61966-2-4) or 12 (Rec. ITU-R BT.1361 extended colour gamut system)), E′R, E′G and E′B are analogue with a larger range not specified in this part of ISO/IEC 23001.

or maybe let the applications deal with it?

Copy link
Owner

@sekrit-twc sekrit-twc Oct 5, 2017

Choose a reason for hiding this comment

The 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.

Copy link
Contributor Author

Choose a reason for hiding this comment

The 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.
Expand Down Expand Up @@ -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;
Expand Down