Skip to content

Commit 1fd3c7b

Browse files
committed
colorspace: switch to the CAT16 color transform
This is substantially more accurate than the method used in CAT97, and improves the perceptual quality of color adaptation, including color temperature adaptation and color blindness simulation. Also fixes an out-of-date comment.
1 parent bc9de9c commit 1fd3c7b

File tree

2 files changed

+16
-18
lines changed

2 files changed

+16
-18
lines changed

src/colorspace.c

Lines changed: 15 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1229,12 +1229,11 @@ pl_matrix3x3 pl_get_xyz2rgb_matrix(const struct pl_raw_primaries *prim)
12291229
return out;
12301230
}
12311231

1232-
// LMS<-XYZ revised matrix from CIECAM97, based on a linear transform and
1233-
// normalized for equal energy on monochrome inputs
1234-
static const pl_matrix3x3 m_cat97 = {{
1235-
{ 0.8562, 0.3372, -0.1934 },
1236-
{ -0.8360, 1.8327, 0.0033 },
1237-
{ 0.0357, -0.0469, 1.0112 },
1232+
// Matrix used in CAT16, a revised one-step linear transform method
1233+
static const pl_matrix3x3 m_cat16 = {{
1234+
{ 0.401288, 0.650173, -0.051461 },
1235+
{ -0.250268, 1.204414, 0.045854 },
1236+
{ -0.002079, 0.048952, 0.953127 },
12381237
}};
12391238

12401239
// M := M * XYZd<-XYZs
@@ -1247,32 +1246,31 @@ static void apply_chromatic_adaptation(struct pl_cie_xy src,
12471246
if (fabs(src.x - dest.x) < 1e-6 && fabs(src.y - dest.y) < 1e-6)
12481247
return;
12491248

1250-
// XYZd<-XYZs = Ma^-1 * (I*[Cd/Cs]) * Ma
1249+
// Linear "von Kries" method, adapted from CIECAM16
12511250
// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html
1252-
// For Ma, we use the CIECAM97 revised (linear) matrix
12531251
float C[3][2];
12541252

12551253
for (int i = 0; i < 3; i++) {
12561254
// source cone
1257-
C[i][0] = m_cat97.m[i][0] * pl_cie_X(src)
1258-
+ m_cat97.m[i][1] * 1
1259-
+ m_cat97.m[i][2] * pl_cie_Z(src);
1255+
C[i][0] = m_cat16.m[i][0] * pl_cie_X(src)
1256+
+ m_cat16.m[i][1] * 1
1257+
+ m_cat16.m[i][2] * pl_cie_Z(src);
12601258

12611259
// dest cone
1262-
C[i][1] = m_cat97.m[i][0] * pl_cie_X(dest)
1263-
+ m_cat97.m[i][1] * 1
1264-
+ m_cat97.m[i][2] * pl_cie_Z(dest);
1260+
C[i][1] = m_cat16.m[i][0] * pl_cie_X(dest)
1261+
+ m_cat16.m[i][1] * 1
1262+
+ m_cat16.m[i][2] * pl_cie_Z(dest);
12651263
}
12661264

12671265
// tmp := I * [Cd/Cs] * Ma
12681266
pl_matrix3x3 tmp = {0};
12691267
for (int i = 0; i < 3; i++)
12701268
tmp.m[i][i] = C[i][1] / C[i][0];
12711269

1272-
pl_matrix3x3_mul(&tmp, &m_cat97);
1270+
pl_matrix3x3_mul(&tmp, &m_cat16);
12731271

12741272
// M := M * Ma^-1 * tmp
1275-
pl_matrix3x3 ma_inv = m_cat97;
1273+
pl_matrix3x3 ma_inv = m_cat16;
12761274
pl_matrix3x3_invert(&ma_inv);
12771275
pl_matrix3x3_mul(mat, &ma_inv);
12781276
pl_matrix3x3_mul(mat, &tmp);
@@ -1354,7 +1352,7 @@ pl_matrix3x3 pl_get_cone_matrix(const struct pl_cone_params *params,
13541352
const struct pl_raw_primaries *prim)
13551353
{
13561354
// LMS<-RGB := LMS<-XYZ * XYZ<-RGB
1357-
pl_matrix3x3 rgb2lms = m_cat97;
1355+
pl_matrix3x3 rgb2lms = m_cat16;
13581356
pl_matrix3x3 rgb2xyz = pl_get_rgb2xyz_matrix(prim);
13591357
pl_matrix3x3_mul(&rgb2lms, &rgb2xyz);
13601358

src/include/libplacebo/colorspace.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -601,7 +601,7 @@ PL_API pl_matrix3x3 pl_get_color_mapping_matrix(const struct pl_raw_primaries *s
601601
enum pl_rendering_intent intent);
602602

603603
// Return a chromatic adaptation matrix, which converts from one white point to
604-
// another, using the Bradford matrix. This is an RGB->RGB transformation.
604+
// another, using the CAT16 matrix. This is an RGB->RGB transformation.
605605
PL_API pl_matrix3x3 pl_get_adaptation_matrix(struct pl_cie_xy src, struct pl_cie_xy dst);
606606

607607
// Returns true if 'b' is entirely contained in 'a'. Useful for figuring out if

0 commit comments

Comments
 (0)