mirror of
https://gitlab.freedesktop.org/wayland/weston
synced 2024-10-04 20:52:25 +00:00
tests: replace mat2XYZ
The primaries and the white point are the fundamental definition of the
color spaces in these tests. Instead of hard-coding mat2XYZ, use
LittleCMS to derive the result from the fundamental definition.
This removes derived hard-coded constants, which is a benefit in itself.
How these constants were originally produced was not mentioned in
0c5860fafb
but I was able to reproduce
them with python3:
import colour
import numpy as np
x = colour.RGB_COLOURSPACES['sRGB']
w_d50 = np.array([0.34567, 0.35850])
print(x.chromatically_adapt(w_d50, 'D50', 'Bradford'))
It's identical to 3-4 decimals of the hardcoded values, and also for
Adobe RGB. I printed the LittleCMS generated values as well, and they
are the same as with python up to roughly 4 decimals.
Signed-off-by: Pekka Paalanen <pekka.paalanen@collabora.com>
This commit is contained in:
parent
7d38e044dd
commit
94ccce4e38
|
@ -59,9 +59,6 @@ const struct lcms_pipeline pipeline_sRGB = {
|
||||||
.mat = LCMSMAT3(1.0, 0.0, 0.0,
|
.mat = LCMSMAT3(1.0, 0.0, 0.0,
|
||||||
0.0, 1.0, 0.0,
|
0.0, 1.0, 0.0,
|
||||||
0.0, 0.0, 1.0),
|
0.0, 0.0, 1.0),
|
||||||
.mat2XYZ = LCMSMAT3(0.436037, 0.385124, 0.143039,
|
|
||||||
0.222482, 0.716913, 0.060605,
|
|
||||||
0.013922, 0.097078, 0.713899),
|
|
||||||
.post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE
|
.post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -76,9 +73,6 @@ const struct lcms_pipeline pipeline_adobeRGB = {
|
||||||
.mat = LCMSMAT3( 0.715127, 0.284868, 0.000005,
|
.mat = LCMSMAT3( 0.715127, 0.284868, 0.000005,
|
||||||
0.000001, 0.999995, 0.000004,
|
0.000001, 0.999995, 0.000004,
|
||||||
-0.000003, 0.041155, 0.958848),
|
-0.000003, 0.041155, 0.958848),
|
||||||
.mat2XYZ = LCMSMAT3(0.609740, 0.205279, 0.149181,
|
|
||||||
0.311111, 0.625681, 0.063208,
|
|
||||||
0.019469, 0.060879, 0.744552),
|
|
||||||
.post_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE
|
.post_fn = TRANSFER_FN_ADOBE_RGB_EOTF_INVERSE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -61,9 +61,6 @@ const struct lcms_pipeline pipeline_sRGB = {
|
||||||
.mat = LCMSMAT3(1.0, 0.0, 0.0,
|
.mat = LCMSMAT3(1.0, 0.0, 0.0,
|
||||||
0.0, 1.0, 0.0,
|
0.0, 1.0, 0.0,
|
||||||
0.0, 0.0, 1.0),
|
0.0, 0.0, 1.0),
|
||||||
.mat2XYZ = LCMSMAT3(0.436037, 0.385124, 0.143039,
|
|
||||||
0.222482, 0.716913, 0.060605,
|
|
||||||
0.013922, 0.097078, 0.713899),
|
|
||||||
.post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE
|
.post_fn = TRANSFER_FN_SRGB_EOTF_INVERSE
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -32,11 +32,12 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#include <libweston/matrix.h>
|
||||||
#include "shared/helpers.h"
|
#include "shared/helpers.h"
|
||||||
#include "color_util.h"
|
#include "color_util.h"
|
||||||
#include "lcms_util.h"
|
#include "lcms_util.h"
|
||||||
|
|
||||||
static cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 };
|
static const cmsCIExyY wp_d65 = { 0.31271, 0.32902, 1.0 };
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* MPE tone curves can only use LittleCMS parametric curve types 6-8 and not
|
* MPE tone curves can only use LittleCMS parametric curve types 6-8 and not
|
||||||
|
@ -280,32 +281,33 @@ roundtrip_verification(cmsPipeline *DToB, cmsPipeline *BToD, float tolerance)
|
||||||
assert(stat.two_norm.max < tolerance);
|
assert(stat.two_norm.max < tolerance);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct transform_sampler_context {
|
||||||
|
cmsHTRANSFORM t;
|
||||||
|
};
|
||||||
|
|
||||||
static cmsInt32Number
|
static cmsInt32Number
|
||||||
sampler_matrix(const float src[], float dst[], void *cargo)
|
transform_sampler(const float src[], float dst[], void *cargo)
|
||||||
{
|
{
|
||||||
const struct lcmsMAT3 *mat = cargo;
|
const struct transform_sampler_context *tsc = cargo;
|
||||||
struct color_float in = { .r = src[0], .g = src[1], .b = src[2] };
|
|
||||||
struct color_float cf;
|
|
||||||
unsigned i;
|
|
||||||
|
|
||||||
cf = color_float_apply_matrix(mat, in);
|
cmsDoTransform(tsc->t, src, dst, 1);
|
||||||
|
|
||||||
for (i = 0; i < COLOR_CHAN_NUM; i++)
|
|
||||||
dst[i] = cf.rgb[i];
|
|
||||||
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static cmsStage *
|
static cmsStage *
|
||||||
create_cLUT_from_matrix(cmsContext context_id, const struct lcmsMAT3 *mat,
|
create_cLUT_from_transform(cmsContext context_id, const cmsHTRANSFORM t,
|
||||||
int dim_size)
|
int dim_size)
|
||||||
{
|
{
|
||||||
|
struct transform_sampler_context tsc;
|
||||||
cmsStage *cLUT_stage;
|
cmsStage *cLUT_stage;
|
||||||
|
|
||||||
assert(dim_size);
|
assert(dim_size);
|
||||||
|
|
||||||
|
tsc.t = t;
|
||||||
|
|
||||||
cLUT_stage = cmsStageAllocCLutFloat(context_id, dim_size, 3, 3, NULL);
|
cLUT_stage = cmsStageAllocCLutFloat(context_id, dim_size, 3, 3, NULL);
|
||||||
cmsStageSampleCLutFloat(cLUT_stage, sampler_matrix, (void *)mat, 0);
|
cmsStageSampleCLutFloat(cLUT_stage, transform_sampler, &tsc, 0);
|
||||||
|
|
||||||
return cLUT_stage;
|
return cLUT_stage;
|
||||||
}
|
}
|
||||||
|
@ -341,9 +343,41 @@ build_lcms_clut_profile_output(cmsContext context_id,
|
||||||
cmsStage *stage;
|
cmsStage *stage;
|
||||||
cmsStage *stage_inv_eotf;
|
cmsStage *stage_inv_eotf;
|
||||||
cmsStage *stage_eotf;
|
cmsStage *stage_eotf;
|
||||||
struct lcmsMAT3 mat2XYZ_inv;
|
cmsToneCurve *identity_curves[3];
|
||||||
|
cmsHPROFILE linear_device;
|
||||||
|
cmsHPROFILE pcs;
|
||||||
|
cmsHTRANSFORM linear_device_to_pcs;
|
||||||
|
cmsHTRANSFORM pcs_to_linear_device;
|
||||||
|
|
||||||
lcmsMAT3_invert(&mat2XYZ_inv, &pipeline->mat2XYZ);
|
identity_curves[0] = identity_curves[1] = identity_curves[2] =
|
||||||
|
cmsBuildGamma(context_id, 1.0);
|
||||||
|
|
||||||
|
linear_device = cmsCreateRGBProfileTHR(context_id, &wp_d65,
|
||||||
|
&pipeline->prim_output,
|
||||||
|
identity_curves);
|
||||||
|
assert(cmsIsMatrixShaper(linear_device));
|
||||||
|
cmsFreeToneCurve(identity_curves[0]);
|
||||||
|
|
||||||
|
pcs = cmsCreateXYZProfileTHR(context_id);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Since linear_device is a matrix-shaper profile, all rendering intents
|
||||||
|
* share the same device<->PCS transformations. We only need to pick
|
||||||
|
* an arbitrary rendering intent that allows to turn BPC both on and off.
|
||||||
|
*/
|
||||||
|
linear_device_to_pcs = cmsCreateTransformTHR(context_id,
|
||||||
|
linear_device, TYPE_RGB_FLT,
|
||||||
|
pcs, TYPE_XYZ_FLT,
|
||||||
|
INTENT_RELATIVE_COLORIMETRIC,
|
||||||
|
cmsFLAGS_NOOPTIMIZE);
|
||||||
|
pcs_to_linear_device = cmsCreateTransformTHR(context_id,
|
||||||
|
pcs, TYPE_XYZ_FLT,
|
||||||
|
linear_device, TYPE_RGB_FLT,
|
||||||
|
INTENT_RELATIVE_COLORIMETRIC,
|
||||||
|
cmsFLAGS_NOOPTIMIZE);
|
||||||
|
|
||||||
|
cmsCloseProfile(linear_device);
|
||||||
|
cmsCloseProfile(pcs);
|
||||||
|
|
||||||
hRGB = cmsCreateProfilePlaceholder(context_id);
|
hRGB = cmsCreateProfilePlaceholder(context_id);
|
||||||
cmsSetProfileVersion(hRGB, 4.3);
|
cmsSetProfileVersion(hRGB, 4.3);
|
||||||
|
@ -360,7 +394,8 @@ build_lcms_clut_profile_output(cmsContext context_id,
|
||||||
*/
|
*/
|
||||||
BToD0 = cmsPipelineAlloc(context_id, 3, 3);
|
BToD0 = cmsPipelineAlloc(context_id, 3, 3);
|
||||||
|
|
||||||
stage = create_cLUT_from_matrix(context_id, &mat2XYZ_inv, clut_dim_size);
|
stage = create_cLUT_from_transform(context_id, pcs_to_linear_device,
|
||||||
|
clut_dim_size);
|
||||||
cmsPipelineInsertStage(BToD0, cmsAT_END, stage);
|
cmsPipelineInsertStage(BToD0, cmsAT_END, stage);
|
||||||
cmsPipelineInsertStage(BToD0, cmsAT_END, cmsStageDup(stage_inv_eotf));
|
cmsPipelineInsertStage(BToD0, cmsAT_END, cmsStageDup(stage_inv_eotf));
|
||||||
|
|
||||||
|
@ -375,7 +410,8 @@ build_lcms_clut_profile_output(cmsContext context_id,
|
||||||
DToB0 = cmsPipelineAlloc(context_id, 3, 3);
|
DToB0 = cmsPipelineAlloc(context_id, 3, 3);
|
||||||
|
|
||||||
cmsPipelineInsertStage(DToB0, cmsAT_END, cmsStageDup(stage_eotf));
|
cmsPipelineInsertStage(DToB0, cmsAT_END, cmsStageDup(stage_eotf));
|
||||||
stage = create_cLUT_from_matrix(context_id, &pipeline->mat2XYZ, clut_dim_size);
|
stage = create_cLUT_from_transform(context_id, linear_device_to_pcs,
|
||||||
|
clut_dim_size);
|
||||||
cmsPipelineInsertStage(DToB0, cmsAT_END, stage);
|
cmsPipelineInsertStage(DToB0, cmsAT_END, stage);
|
||||||
|
|
||||||
cmsWriteTag(hRGB, cmsSigDToB0Tag, DToB0);
|
cmsWriteTag(hRGB, cmsSigDToB0Tag, DToB0);
|
||||||
|
@ -392,6 +428,9 @@ build_lcms_clut_profile_output(cmsContext context_id,
|
||||||
cmsStageFree(stage_eotf);
|
cmsStageFree(stage_eotf);
|
||||||
cmsStageFree(stage_inv_eotf);
|
cmsStageFree(stage_inv_eotf);
|
||||||
|
|
||||||
|
cmsDeleteTransform(linear_device_to_pcs);
|
||||||
|
cmsDeleteTransform(pcs_to_linear_device);
|
||||||
|
|
||||||
return hRGB;
|
return hRGB;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -36,6 +36,7 @@ struct lcms_pipeline {
|
||||||
const char *color_space;
|
const char *color_space;
|
||||||
/**
|
/**
|
||||||
* Chromaticities for output profile
|
* Chromaticities for output profile
|
||||||
|
* White point is assumed to be D65.
|
||||||
*/
|
*/
|
||||||
cmsCIExyYTRIPLE prim_output;
|
cmsCIExyYTRIPLE prim_output;
|
||||||
/**
|
/**
|
||||||
|
@ -46,11 +47,6 @@ struct lcms_pipeline {
|
||||||
* Transform matrix from sRGB to target chromaticities in prim_output
|
* Transform matrix from sRGB to target chromaticities in prim_output
|
||||||
*/
|
*/
|
||||||
struct lcmsMAT3 mat;
|
struct lcmsMAT3 mat;
|
||||||
/**
|
|
||||||
* matrix from prim_output to XYZ, for example matrix conversion
|
|
||||||
* sRGB->XYZ, adobeRGB->XYZ, bt2020->XYZ
|
|
||||||
*/
|
|
||||||
struct lcmsMAT3 mat2XYZ;
|
|
||||||
/**
|
/**
|
||||||
* tone curve enum
|
* tone curve enum
|
||||||
*/
|
*/
|
||||||
|
|
Loading…
Reference in a new issue