Add TRC to working profiles

This commit is contained in:
Desmis
2018-04-29 17:08:45 +02:00
parent 579c3ca770
commit 19b7a942af
15 changed files with 1576 additions and 881 deletions

View File

@@ -32,14 +32,15 @@ namespace rtengine
extern void filmlike_clip(float *r, float *g, float *b);
namespace {
namespace
{
inline void clipLAB(float iL, float ia, float ib, float &oL, float &oa, float &ob, const float scale, const float wp[3][3], const float wip[3][3])
{
if (iL < 0.f) {
oL = oa = ob = 0.f;
} else if (iL > 32768.f || min(ia, ib) < -42000.f || max(ia, ib) > 42000.f) {
float X, Y, Z;
float r, g, b;
Color::Lab2XYZ(iL, ia, ib, X, Y, Z);
@@ -50,7 +51,7 @@ inline void clipLAB(float iL, float ia, float ib, float &oL, float &oa, float &o
oL /= scale;
oa /= scale;
ob /= scale;
// oL = 32768.f / scale;
// oa = ob = 0.f;
} else {
@@ -88,7 +89,7 @@ extern const Settings* settings;
{static_cast<float> (wiprof[1][0]), static_cast<float> (wiprof[1][1]), static_cast<float> (wiprof[1][2])}, \
{static_cast<float> (wiprof[2][0]), static_cast<float> (wiprof[2][1]), static_cast<float> (wiprof[2][2])} \
}
// Used in ImProcCoordinator::updatePreviewImage (rtengine/improccoordinator.cc)
// Crop::update (rtengine/dcrop.cc)
@@ -96,10 +97,10 @@ extern const Settings* settings;
//
// If monitorTransform, divide by 327.68 then apply monitorTransform (which can integrate soft-proofing)
// otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
void ImProcFunctions::lab2monitorRgb(LabImage* lab, Image8* image)
{
DECLARE_WORKING_MATRICES_(params->icm.working);
if (monitorTransform) {
int W = lab->W;
@@ -115,11 +116,12 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
AlignedBuffer<float> gwBuf1;
AlignedBuffer<float> gwBuf2;
if (gamutWarning) {
gwBuf1.resize(3 * lab->W);
gwBuf2.resize(3 * lab->W);
}
float *buffer = pBuf.data;
#ifdef _OPENMP
@@ -136,11 +138,11 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
float* rb = lab->b[i];
for (int j = 0; j < W; j++) {
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy+1], buffer[iy+2], 327.68f, wp, wip);
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy + 1], buffer[iy + 2], 327.68f, wp, wip);
iy += 3;
}
cmsDoTransform (monitorTransform, buffer, data + ix, W);
cmsDoTransform(monitorTransform, buffer, data + ix, W);
if (gamutWarning) {
gamutWarning->markLine(image, i, buffer, gwBuf1.data, gwBuf2.data);
@@ -172,7 +174,7 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
//float L1=rL[j],a1=ra[j],b1=rb[j];//for testing
clipLAB(rL[j], ra[j], rb[j], L, a, b, 1.f, wp, wip);
Color::Lab2XYZ(L, a, b, x_, y_, z_ );
Color::Lab2XYZ(L, a, b, x_, y_, z_);
Color::xyz2srgb(x_, y_, z_, R, G, B);
@@ -195,10 +197,10 @@ void ImProcFunctions::lab2monitorRgb (LabImage* lab, Image8* image)
//
// If output profile used, divide by 327.68 then apply the "profile" profile (eventually with a standard gamma)
// otherwise divide by 327.68, convert to xyz and apply the RGB transform, before converting with gamma2curve
Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings)
Image8* ImProcFunctions::lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings)
{
DECLARE_WORKING_MATRICES_(icm.working);
//gamutmap(lab);
if (cx < 0) {
@@ -217,23 +219,25 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
ch = lab->H - cy;
}
Image8* image = new Image8 (cw, ch);
Image8* image = new Image8(cw, ch);
Glib::ustring profile;
bool standard_gamma;
if(settings->HistogramWorking && consider_histogram_settings) {
if (settings->HistogramWorking && consider_histogram_settings) {
profile = icm.working;
standard_gamma = true;
} else {
profile = icm.output;
if (icm.output.empty() || icm.output == ColorManagementParams::NoICMString) {
profile = "sRGB";
}
standard_gamma = false;
}
cmsHPROFILE oprof = ICCStore::getInstance()->getProfile (profile);
cmsHPROFILE oprof = ICCStore::getInstance()->getProfile(profile);
if (oprof) {
cmsHPROFILE oprofG = oprof;
@@ -243,14 +247,16 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
}
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
if (icm.outputBPC) {
flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
}
lcmsMutex->lock ();
lcmsMutex->lock();
cmsHPROFILE LabIProf = cmsCreateLab4Profile(nullptr);
cmsHTRANSFORM hTransform = cmsCreateTransform (LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, icm.outputIntent, flags); // NOCACHE is important for thread safety
cmsHTRANSFORM hTransform = cmsCreateTransform(LabIProf, TYPE_Lab_DBL, oprofG, TYPE_RGB_8, icm.outputIntent, flags); // NOCACHE is important for thread safety
cmsCloseProfile(LabIProf);
lcmsMutex->unlock ();
lcmsMutex->unlock();
unsigned char *data = image->data;
@@ -275,11 +281,11 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
float* rb = lab->b[i];
for (int j = cx; j < cx + cw; j++) {
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy+1], buffer[iy+2], 327.68f, wp, wip);
clipLAB(rL[j], ra[j], rb[j], buffer[iy], buffer[iy + 1], buffer[iy + 2], 327.68f, wp, wip);
iy += 3;
}
cmsDoTransform (hTransform, buffer, data + ix, cw);
cmsDoTransform(hTransform, buffer, data + ix, cw);
}
} // End of parallelization
@@ -290,7 +296,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
}
} else {
const auto xyz_rgb = ICCStore::getInstance()->workingSpaceInverseMatrix (profile);
const auto xyz_rgb = ICCStore::getInstance()->workingSpaceInverseMatrix(profile);
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16) if (multiThread)
@@ -338,7 +344,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
* If a custom gamma profile can be created, divide by 327.68, convert to xyz and apply the custom gamma transform
* otherwise divide by 327.68, convert to xyz and apply the sRGB transform, before converting with gamma2curve
*/
Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
Imagefloat* ImProcFunctions::lab2rgbOut(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga)
{
if (cx < 0) {
@@ -357,27 +363,30 @@ Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw,
ch = lab->H - cy;
}
Imagefloat* image = new Imagefloat (cw, ch);
Imagefloat* image = new Imagefloat(cw, ch);
cmsHPROFILE oprof = nullptr;
if (ga) {
lcmsMutex->lock ();
lcmsMutex->lock();
ICCStore::getInstance()->getGammaArray(icm, *ga);
oprof = ICCStore::getInstance()->createGammaProfile(icm, *ga);
lcmsMutex->unlock ();
lcmsMutex->unlock();
} else {
oprof = ICCStore::getInstance()->getProfile (icm.output);
oprof = ICCStore::getInstance()->getProfile(icm.output);
}
if (oprof) {
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
if (icm.outputBPC) {
flags |= cmsFLAGS_BLACKPOINTCOMPENSATION;
}
lcmsMutex->lock ();
lcmsMutex->lock();
cmsHPROFILE iprof = cmsCreateLab4Profile(nullptr);
cmsHTRANSFORM hTransform = cmsCreateTransform (iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_FLT, icm.outputIntent, flags);
lcmsMutex->unlock ();
cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_Lab_FLT, oprof, TYPE_RGB_FLT, icm.outputIntent, flags);
lcmsMutex->unlock();
image->ExecCMSTransform(hTransform, *lab, cx, cy);
cmsDeleteTransform(hTransform);
@@ -386,6 +395,7 @@ Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw,
#ifdef _OPENMP
#pragma omp parallel for schedule(dynamic,16) if (multiThread)
#endif
for (int i = cy; i < cy + ch; i++) {
float R, G, B;
float* rL = lab->L[i];
@@ -416,4 +426,248 @@ Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw,
return image;
}
Image16* ImProcFunctions::workingtrc(Imagefloat* working, int cw, int ch, int mul, Glib::ustring profi, double gampos, double slpos, double &ga0, double &ga1, double &ga2, double &ga3, double &ga4, double &ga5, double &ga6)
{
TMatrix wprof;
if (true) {
wprof = ICCStore::getInstance()->workingSpaceMatrix(params->icm.working);
} else {
wprof = ICCStore::getInstance()->workingSpaceMatrix("ProPhoto");
profi = "ProPhoto";
}
double dx = Color::D50x;
double dz = Color::D50z;
{
dx = dz = 1.0;
}
double toxyz[3][3] = {
{
(wprof[0][0] / dx), //I have suppressed / Color::D50x
(wprof[0][1] / dx),
(wprof[0][2] / dx)
}, {
(wprof[1][0]),
(wprof[1][1]),
(wprof[1][2])
}, {
(wprof[2][0] / dz), //I have suppressed / Color::D50z
(wprof[2][1] / dz),
(wprof[2][2] / dz)
}
};
Image16* image = new Image16(cw, ch);
double pwr;
double ts;
ts = slpos;
int five = mul;
ga6 = 0.0;
pwr = 1.0 / gampos;
if (gampos < 1.0) {
pwr = gampos;
gampos = 1. / gampos;
five = -mul;
// if(ts < 2.) five=-4;
}
// int select_temp = 1; //5003K
const double eps = 0.000000001; // not divide by zero
enum class ColorTemp {
D50 = 5003, // for Widegamut, Prophoto Best, Beta -> D50
D65 = 6504, // for sRGB, AdobeRGB, Bruce Rec2020 -> D65
D60 = 6005 //for ACESP0 and AcesP1
};
ColorTemp temp = ColorTemp::D50;
cmsHPROFILE oprofdef;
float p[6]; //primaries
if (true) {
//primaries for 10 working profiles ==> output profiles
if (profi == "WideGamut") {
p[0] = 0.7350; //Widegamut primaries
p[1] = 0.2650;
p[2] = 0.1150;
p[3] = 0.8260;
p[4] = 0.1570;
p[5] = 0.0180;
} else if (profi == "Adobe RGB") {
p[0] = 0.6400; //Adobe primaries
p[1] = 0.3300;
p[2] = 0.2100;
p[3] = 0.7100;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (profi == "sRGB") {
p[0] = 0.6400; // sRGB primaries
p[1] = 0.3300;
p[2] = 0.3000;
p[3] = 0.6000;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (profi == "BruceRGB") {
p[0] = 0.6400; // Bruce primaries
p[1] = 0.3300;
p[2] = 0.2800;
p[3] = 0.6500;
p[4] = 0.1500;
p[5] = 0.0600;
temp = ColorTemp::D65;
} else if (profi == "Beta RGB") {
p[0] = 0.6888; // Beta primaries
p[1] = 0.3112;
p[2] = 0.1986;
p[3] = 0.7551;
p[4] = 0.1265;
p[5] = 0.0352;
} else if (profi == "BestRGB") {
p[0] = 0.7347; // Best primaries
p[1] = 0.2653;
p[2] = 0.2150;
p[3] = 0.7750;
p[4] = 0.1300;
p[5] = 0.0350;
} else if (profi == "Rec2020") {
p[0] = 0.7080; // Rec2020 primaries
p[1] = 0.2920;
p[2] = 0.1700;
p[3] = 0.7970;
p[4] = 0.1310;
p[5] = 0.0460;
temp = ColorTemp::D65;
} else if (profi == "ACESp0") {
p[0] = 0.7347; // ACES P0 primaries
p[1] = 0.2653;
p[2] = 0.0000;
p[3] = 1.0;
p[4] = 0.0001;
p[5] = -0.0770;
temp = ColorTemp::D60;
} else if (profi == "ACESp1") {
p[0] = 0.713; // ACES P1 primaries
p[1] = 0.293;
p[2] = 0.165;
p[3] = 0.830;
p[4] = 0.128;
p[5] = 0.044;
temp = ColorTemp::D60;
} else if (profi == "ProPhoto") {
p[0] = 0.7347; //ProPhoto and default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
} else {
/*
p[0] = 0.7347; //default primaries
p[1] = 0.2653;
p[2] = 0.1596;
p[3] = 0.8404;
p[4] = 0.0366;
p[5] = 0.0001;
*/
}
if (slpos == 0) {
slpos = eps;
}
GammaValues g_a; //gamma parameters
int mode = 0;
Color::calcGamma(pwr, ts, mode, g_a); // call to calcGamma with selected gamma and slope : return parameters for LCMS2
ga4 = g_a[3] * ts;
ga0 = gampos;
ga1 = 1. / (1.0 + g_a[4]);
ga2 = g_a[4] / (1.0 + g_a[4]);
ga3 = 1. / slpos;
ga5 = 0.0;
printf("ga0=%f ga1=%f ga2=%f ga3=%f ga4=%f\n", ga0, ga1, ga2, ga3, ga4);
cmsCIExyY xyD;
cmsCIExyYTRIPLE Primaries = {
{p[0], p[1], 1.0}, // red
{p[2], p[3], 1.0}, // green
{p[4], p[5], 1.0} // blue
};
cmsToneCurve* GammaTRC[3];
cmsFloat64Number Parameters[7];
Parameters[0] = ga0;
Parameters[1] = ga1;
Parameters[2] = ga2;
Parameters[3] = ga3;
Parameters[4] = ga4;
Parameters[5] = ga5;
Parameters[6] = ga6;
// 7 parameters for smoother curves
cmsWhitePointFromTemp(&xyD, (double)temp);
GammaTRC[0] = GammaTRC[1] = GammaTRC[2] = cmsBuildParametricToneCurve(NULL, five, Parameters);//5 = more smoother than 4
oprofdef = cmsCreateRGBProfile(&xyD, &Primaries, GammaTRC);
cmsFreeToneCurve(GammaTRC[0]);
}
if (oprofdef) {
#pragma omp parallel for if (multiThread)
for (int i = 0; i < ch; i++) {
float* rr = working->r(i);
float* rg = working->g(i);
float* rb = working->b(i);
short* xa = (short*)image->r(i);
short* ya = (short*)image->g(i);
short* za = (short*)image->b(i);
for (int j = 0; j < cw; j++) {
float r1 = rr[j];
float g1 = rg[j];
float b1 = rb[j];
float x_ = toxyz[0][0] * r1 + toxyz[0][1] * g1 + toxyz[0][2] * b1;
float y_ = toxyz[1][0] * r1 + toxyz[1][1] * g1 + toxyz[1][2] * b1;
float z_ = toxyz[2][0] * r1 + toxyz[2][1] * g1 + toxyz[2][2] * b1;
xa[j] = CLIP((int) round(x_)) ;
ya[j] = CLIP((int) round(y_));
za[j] = CLIP((int) round(z_));
}
}
cmsUInt32Number flags = cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE;
cmsHPROFILE iprof = ICCStore::getInstance()->getXYZProfile();
lcmsMutex->lock();
cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_RGB_16, oprofdef, TYPE_RGB_16, params->icm.outputIntent, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_NOCACHE);
// cmsHTRANSFORM hTransform = cmsCreateTransform(iprof, TYPE_RGB_FLT, oprofdef, TYPE_RGB_FLT, params->icm.outputIntent, flags);
lcmsMutex->unlock();
image->ExecCMSTransform(hTransform);
cmsDeleteTransform(hTransform);
}
return image;
}
}