merge with dev

This commit is contained in:
Desmis 2018-02-01 11:42:17 +01:00
commit 92f6e0e1da
16 changed files with 332 additions and 380 deletions

View File

@ -9,10 +9,14 @@ image/x-canon-cr2;
image/x-canon-crf;
image/x-canon-crw;
image/x-fuji-raf;
image/x-hasselblad-3fr;
image/x-hasselblad-fff;
image/x-jpg;
image/x-kodak-dcr;
image/x-kodak-k25;
image/x-kodak-kdc;
image/x-leaf-mos;
image/x-leica-rwl;
image/x-mamiya-mef;
image/x-minolta-mrw;
image/x-nikon-nef;
@ -22,15 +26,14 @@ image/x-panasonic-raw;
image/x-panasonic-rw2;
image/x-pentax-pef;
image/x-pentax-raw;
image/x-phaseone-iiq;
image/x-raw;
image/x-rwz;
image/x-samsung-srw;
image/x-sigma-x3f;
image/x-sony-arq;
image/x-sony-arw;
image/x-sony-sr2;
image/x-sony-srf;
image/x-hasselblad-3fr;
image/x-hasselblad-fff;
image/x-leaf-mos;
image/x-phaseone-iiq;
image/x-tif;
inode/directory;

View File

@ -13,6 +13,6 @@ Comment[pl]=Zaawansowany program do wywoływania zdjęć typu raw
Icon=rawtherapee
Exec=rawtherapee %f
Terminal=false
MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-leaf-mos;image/x-phaseone-iiq;image/x-tif;
MimeType=image/jpeg;image/png;image/tiff;image/x-adobe-dng;image/x-canon-cr2;image/x-canon-crf;image/x-canon-crw;image/x-fuji-raf;image/x-hasselblad-3fr;image/x-hasselblad-fff;image/x-jpg;image/x-kodak-dcr;image/x-kodak-k25;image/x-kodak-kdc;image/x-leaf-mos;image/x-leica-rwl;image/x-mamiya-mef;image/x-minolta-mrw;image/x-nikon-nef;image/x-nikon-nrw;image/x-olympus-orf;image/x-panasonic-raw;image/x-panasonic-rw2;image/x-pentax-pef;image/x-pentax-raw;image/x-phaseone-iiq;image/x-raw;image/x-rwz;image/x-samsung-srw;image/x-sigma-x3f;image/x-sony-arq;image/x-sony-arw;image/x-sony-sr2;image/x-sony-srf;image/x-tif;
Categories=Photography;Graphics;2DGraphics;RasterGraphics;GTK;
Keywords=raw;photography;develop;pp3;graphics;

View File

@ -34,6 +34,7 @@ extern const Settings* settings;
cmsToneCurve* Color::linearGammaTRC;
LUTf Color::cachef;
LUTf Color::cachefy;
LUTf Color::gamma2curve;
LUTf Color::gammatab;
@ -56,21 +57,6 @@ LUTf Color::igammatab_115_2;
LUTf Color::gammatab_145_3;
LUTf Color::igammatab_145_3;
// Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value.
// The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent
// and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3.
const double Color::sRGBGamma = 2.2;
const double Color::sRGBGammaCurve = 2.4;
const double Color::eps_max = 580.40756; //(MAXVALF* 216.0f/24389.0);
const double Color::eps = 216.0f / 24389.0; //0.008856
const double Color::kappa = 24389.0 / 27.0; //903.29630;
const float Color::D50x = 0.9642f; //0.96422;
const float Color::D50z = 0.8249f; //0.82521;
const double Color::u0 = 4.0 * D50x / (D50x + 15 + 3 * D50z);
const double Color::v0 = 9.0 / (D50x + 15 + 3 * D50z);
const double Color::epskap = 8.0;
/*
* Munsell Lch correction
* Copyright (c) 2011 Jacques Desmis <jdesmis@gmail.com>
@ -138,6 +124,7 @@ void Color::init()
constexpr auto maxindex = 65536;
cachef(maxindex, LUT_CLIP_BELOW);
cachefy(maxindex, LUT_CLIP_BELOW);
gammatab(maxindex, 0);
gammatabThumb(maxindex, 0);
@ -182,6 +169,23 @@ void Color::init()
}
#ifdef _OPENMP
#pragma omp section
#endif
{
int i = 0;
int epsmaxint = eps_max;
for (; i <= epsmaxint; i++)
{
cachefy[i] = 327.68 * (kappa * i / MAXVALF);
}
for(; i < maxindex; i++)
{
cachefy[i] = 327.68 * (116.0 * std::cbrt((double)i / MAXVALF) - 16.0);
}
}
#ifdef _OPENMP
#pragma omp section
#endif
{
for (int i = 0; i < maxindex; i++)
@ -375,150 +379,141 @@ void Color::cleanup()
}
}
void Color::rgb2lab(Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace)
{
double xyz_rgb[3][3];
const double ep = 216.0 / 24389.0;
const double ka = 24389.0 / 27.0;
void Color::rgb2lab01 (const Glib::ustring &profile, const Glib::ustring &profileW, float r, float g, float b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace)
{ // do not use this function in a loop. It really eats processing time caused by Glib::ustring comparisons
double var_R = r / 65535.0;
double var_G = g / 65535.0;
double var_B = b / 65535.0;
Glib::ustring profileCalc = "sRGB"; //default
Glib::ustring profileCalc;
profileCalc = "sRGB"; //default
if (workingSpace) {
profileCalc = profileW; //display working
}
else {// if you want display = output space
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
profileCalc = "sRGB";
}
if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
profileCalc = "ProPhoto";
}
if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
profileCalc = "Adobe RGB";
}
if (profile == "WideGamutRGB") {
profileCalc = "WideGamut";
}
}
if (workingSpace) {//display working
if (workingSpace) {//display working profile
profileCalc = profileW;
if (profileW == "sRGB") { //apply sRGB inverse gamma
if (var_R > 0.04045) {
var_R = pow(((var_R + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (r > 0.04045f) {
r = pow_F(((r + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
r /= 12.92f;
}
if (var_G > 0.04045) {
var_G = pow(((var_G + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (g > 0.04045f) {
g = pow_F(((g + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
g /= 12.92f;
}
if (var_B > 0.04045) {
var_B = pow(((var_B + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (b > 0.04045f) {
b = pow_F(((b + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
b /= 12.92f;
}
} else if (profileW == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow(var_R, 1.8);
var_G = pow(var_G, 1.8);
var_B = pow(var_B, 1.8);
r = pow_F(r, 1.8f);
g = pow_F(g, 1.8f);
b = pow_F(b, 1.8f);
} else if (profile == "Rec2020") {
if (r > 0.0795f) {
r = pow_F(((r + 0.0954f) / 1.0954f), 2.2f);
} else {
r /= 4.5f;
}
if (g > 0.0795f) {
g = pow_F(((g + 0.0954f) / 1.0954f), 2.2f);
} else {
g /= 4.5f;
}
if (b > 0.0795f) {
b = pow_F(((b + 0.0954f) / 1.0954f), 2.2f);
} else {
b /= 4.5f;
}
} else { // apply inverse gamma 2.2
var_R = pow(var_R, 2.2);
var_G = pow(var_G, 2.2);
var_B = pow(var_B, 2.2);
r = pow_F(r, 2.2f);
g = pow_F(g, 2.2f);
b = pow_F(b, 2.2f);
}
} else { //display output profile
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
// use default "sRGB"
} else if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
profileCalc = "ProPhoto";
} else if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
profileCalc = "Adobe RGB";
} else if (profile == "WideGamutRGB") {
profileCalc = "WideGamut";
}
} else { //display outout profile
if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma
if (var_R > 0.04045) {
var_R = pow(((var_R + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (r > 0.04045f) {
r = pow_F(((r + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
r /= 12.92f;
}
if (var_G > 0.04045) {
var_G = pow(((var_G + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (g > 0.04045f) {
g = pow_F(((g + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
g /= 12.92f;
}
if (var_B > 0.04045) {
var_B = pow(((var_B + 0.055) / 1.055), rtengine::Color::sRGBGammaCurve);
if (b > 0.04045f) {
b = pow_F(((b + 0.055f) / 1.055f), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
b /= 12.92f;
}
}
else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { //
if (var_R > 0.0795) {
var_R = pow(((var_R + 0.0954) / 1.0954), 2.2);
} else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709" || profile == "Rec2020") {
if (r > 0.0795f) {
r = pow_F(((r + 0.0954f) / 1.0954f), 2.2f);
} else {
var_R = var_R / 4.5;
r /= 4.5f;
}
if (var_G > 0.0795) {
var_G = pow(((var_G + 0.0954) / 1.0954), 2.2);
if (g > 0.0795f) {
g = pow_F(((g + 0.0954f) / 1.0954f), 2.2f);
} else {
var_G = var_G / 4.5;
g /= 4.5f;
}
if (var_B > 0.0795) {
var_B = pow(((var_B + 0.0954) / 1.0954), 2.2);
if (b > 0.0795f) {
b = pow_F(((b + 0.0954f) / 1.0954f), 2.2f);
} else {
var_B = var_B / 4.5;
b /= 4.5f;
}
} else if (profile == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow(var_R, 1.8);
var_G = pow(var_G, 1.8);
var_B = pow(var_B, 1.8);
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8
r = pow_F(r, 1.8f);
g = pow_F(g, 1.8f);
b = pow_F(b, 1.8f);
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") {
// gamma 1.0, do nothing
var_R = pow(var_R, 1.);
var_G = pow(var_G, 1.);
var_B = pow(var_B, 1.);
}
} else {// apply inverse gamma 2.2
else {// apply inverse gamma 2.2
var_R = pow(var_R, 2.2);
var_G = pow(var_G, 2.2);
var_B = pow(var_B, 2.2);
r = pow_F(r, 2.2f);
g = pow_F(g, 2.2f);
b = pow_F(b, 2.2f);
}
}
// TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW);
const TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix(profileCalc);
TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix(profileCalc);
const float xyz_rgb[3][3] = { {static_cast<float>(wprof[0][0]), static_cast<float>(wprof[0][1]), static_cast<float>(wprof[0][2])},
{static_cast<float>(wprof[1][0]), static_cast<float>(wprof[1][1]), static_cast<float>(wprof[1][2])},
{static_cast<float>(wprof[2][0]), static_cast<float>(wprof[2][1]), static_cast<float>(wprof[2][2])}
};
for (int m = 0; m < 3; m++)
for (int n = 0; n < 3; n++) {
xyz_rgb[m][n] = wprof[m][n];
}
const float var_X = (xyz_rgb[0][0] * r + xyz_rgb[0][1] * g + xyz_rgb[0][2] * b) / Color::D50x;
const float var_Y = (xyz_rgb[1][0] * r + xyz_rgb[1][1] * g + xyz_rgb[1][2] * b);
const float var_Z = (xyz_rgb[2][0] * r + xyz_rgb[2][1] * g + xyz_rgb[2][2] * b) / Color::D50z;
double varxx, varyy, varzz;
double var_X = (xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B) / Color::D50x;
double var_Y = (xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B) ;
double var_Z = (xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B) / Color::D50z;
const float varxx = var_X > epsf ? xcbrtf(var_X) : (kappaf * var_X + 16.f) / 116.f ;
const float varyy = var_Y > epsf ? xcbrtf(var_Y) : (kappaf * var_Y + 16.f) / 116.f ;
const float varzz = var_Z > epsf ? xcbrtf(var_Z) : (kappaf * var_Z + 16.f) / 116.f ;
varxx = var_X > ep ? cbrt(var_X) : (ka * var_X + 16.0) / 116.0 ;
varyy = var_Y > ep ? cbrt(var_Y) : (ka * var_Y + 16.0) / 116.0 ;
varzz = var_Z > ep ? cbrt(var_Z) : (ka * var_Z + 16.0) / 116.0 ;
LAB_l = (116 * varyy) - 16;
LAB_a = 500 * (varxx - varyy);
LAB_b = 200 * (varyy - varzz);
LAB_l = var_Y > epsf ? (xcbrtf(var_Y) * 116.f) - 16.f : kappaf * var_Y;
LAB_a = 500.f * (varxx - varyy);
LAB_b = 200.f * (varyy - varzz);
}
@ -761,6 +756,36 @@ void Color::rgb2hsv(float r, float g, float b, float &h, float &s, float &v)
}
}
void Color::rgb2hsv01(float r, float g, float b, float &h, float &s, float &v)
{
const float minVal = min(r, g, b);
v = max(r, g, b);
const float delta = v - minVal;
h = 0.f;
if (delta < 0.00001f) {
s = 0.f;
} else {
s = delta / (v == 0.f ? 1.f : v);
if (r == v) {
h = (g - b) / delta;
} else if (g == v) {
h = 2.f + (b - r) / delta;
} else if (b == v) {
h = 4.f + (r - g) / delta;
}
h /= 6.f;
if (h < 0.f) {
h += 1.f;
}
}
}
void Color::hsv2rgb(float h, float s, float v, float &r, float &g, float &b)
{
@ -1700,7 +1725,7 @@ void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z)
float LL = L / 327.68f;
float aa = a / 327.68f;
float bb = b / 327.68f;
float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116
float fy = (c1By116 * LL) + c16By116; // (L+16)/116
float fx = (0.002f * aa) + fy;
float fz = fy - (0.005f * bb);
x = 65535.0f * f2xyz(fx) * D50x;
@ -1711,7 +1736,7 @@ void Color::Lab2XYZ(float L, float a, float b, float &x, float &y, float &z)
void Color::L2XYZ(float L, float &x, float &y, float &z) // for black & white
{
float LL = L / 327.68f;
float fy = (0.00862069f * LL) + 0.137932f; // (L+16)/116
float fy = (c1By116 * LL) + c16By116; // (L+16)/116
float fxz = 65535.f * f2xyz(fy);
x = fxz * D50x;
z = fxz * D50z;
@ -1726,7 +1751,7 @@ void Color::Lab2XYZ(vfloat L, vfloat a, vfloat b, vfloat &x, vfloat &y, vfloat &
L /= c327d68;
a /= c327d68;
b /= c327d68;
vfloat fy = F2V(0.00862069f) * L + F2V(0.137932f);
vfloat fy = F2V(c1By116) * L + F2V(c16By116);
vfloat fx = F2V(0.002f) * a + fy;
vfloat fz = fy - (F2V(0.005f) * b);
vfloat c65535 = F2V(65535.f);
@ -1744,8 +1769,6 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
#ifdef __SSE2__
vfloat maxvalfv = F2V(MAXVALF);
vfloat c116v = F2V(116.f);
vfloat c5242d88v = F2V(5242.88f);
vfloat c500v = F2V(500.f);
vfloat c200v = F2V(200.f);
#endif
@ -1772,7 +1795,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
float fy = (y <= 65535.f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
float fz = (z <= 65535.f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
L[i + k] = (116.f * fy - 5242.88f); //5242.88=16.0*327.68;
L[i + k] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
a[i + k] = (500.f * (fx - fy));
b[i + k] = (200.f * (fy - fz));
}
@ -1781,7 +1804,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
const vfloat fy = cachef[yv];
const vfloat fz = cachef[zv];
STVFU(L[i], c116v * fy - c5242d88v); //5242.88=16.0*327.68;
STVFU(L[i], cachefy[yv]);
STVFU(a[i], c500v * (fx - fy));
STVFU(b[i], c200v * (fy - fz));
}
@ -1802,7 +1825,7 @@ void Color::RGB2Lab(float *R, float *G, float *B, float *L, float *a, float *b,
fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
L[i] = 116.0f * fy - 5242.88f; //5242.88=16.0*327.68;
L[i] = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
a[i] = 500.0f * (fx - fy);
b[i] = 200.0f * (fy - fz);
}
@ -1820,14 +1843,14 @@ void Color::XYZ2Lab(float X, float Y, float Z, float &L, float &a, float &b)
fy = (y <= 65535.0f ? cachef[y] : (327.68f * xcbrtf(y / MAXVALF)));
fz = (z <= 65535.0f ? cachef[z] : (327.68f * xcbrtf(z / MAXVALF)));
L = (116.0f * fy - 5242.88f); //5242.88=16.0*327.68;
L = (y <= 65535.0f ? cachefy[y] : 327.68f * (116.f * xcbrtf(y / MAXVALF) - 16.f));
a = (500.0f * (fx - fy));
b = (200.0f * (fy - fz));
}
void Color::Lab2Yuv(float L, float a, float b, float &Y, float &u, float &v)
{
float fy = (0.00862069 * L / 327.68) + 0.137932; // (L+16)/116
float fy = (c1By116 * L / 327.68) + c16By116; // (L+16)/116
float fx = (0.002 * a / 327.68) + fy;
float fz = fy - (0.005 * b / 327.68);
float LL = L / 327.68;
@ -1856,7 +1879,7 @@ void Color::Yuv2Lab(float Yin, float u, float v, float &L, float &a, float &b, c
float fy = (Y <= 65535.0 ? cachef[Y] : (327.68 * std::cbrt(Y / MAXVALF)));
float fz = (Z <= 65535.0 ? cachef[Z] : (327.68 * std::cbrt(Z / MAXVALF)));
L = (116.0 * fy - 5242.88); //5242.88=16.0*327.68;
L = (Y <= 65535.0f ? cachefy[Y] : 327.68f * (116.f * xcbrtf(Y / MAXVALF) - 16.f));
a = (500.0 * (fx - fy));
b = (200.0 * (fy - fz));
}
@ -2325,7 +2348,7 @@ void Color::gamutLchonly(float HH, float &Lprov1, float &Chprov1, float &R, floa
float bprov1 = Chprov1 * sincosval.x;
//conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction
float fy = (0.00862069f * Lprov1) + 0.137932f;
float fy = (c1By116 * Lprov1 ) + c16By116;
float fx = (0.002f * aprov1) + fy;
float fz = fy - (0.005f * bprov1);
@ -2445,7 +2468,7 @@ void Color::gamutLchonly(float HH, float2 sincosval, float &Lprov1, float &Chpro
float bprov1 = Chprov1 * sincosval.x;
//conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction
float fy = (0.00862069f * Lprov1) + 0.137932f;
float fy = (c1By116 * Lprov1 ) + c16By116;
float fx = (0.002f * aprov1) + fy;
float fz = fy - (0.005f * bprov1);
@ -2554,7 +2577,7 @@ void Color::gamutLchonly(float2 sincosval, float &Lprov1, float &Chprov1, const
float bprov1 = Chprov1 * sincosval.x;
//conversion Lab RGB to limit Lab values - this conversion is useful before Munsell correction
float fy = (0.00862069f * Lprov1) + 0.137932f;
float fy = (c1By116 * Lprov1 ) + c16By116;
float fx = (0.002f * aprov1) + fy;
float fz = fy - (0.005f * bprov1);

View File

@ -120,15 +120,36 @@ public:
ID_DOWN /// Interpolate color by decreasing the hue value, crossing the lower limit
} eInterpolationDirection;
const static double sRGBGamma; // standard average gamma
const static double sRGBGammaCurve; // 2.4 in the curve
const static double eps, eps_max, kappa, epskap;
const static float D50x, D50z;
const static double u0, v0;
// Wikipedia sRGB: Unlike most other RGB color spaces, the sRGB gamma cannot be expressed as a single numerical value.
// The overall gamma is approximately 2.2, consisting of a linear (gamma 1.0) section near black, and a non-linear section elsewhere involving a 2.4 exponent
// and a gamma (slope of log output versus log input) changing from 1.0 through about 2.3.
constexpr static double sRGBGamma = 2.2;
constexpr static double sRGBGammaCurve = 2.4;
constexpr static double eps = 216.0 / 24389.0; //0.008856
constexpr static double eps_max = MAXVALF * eps; //580.40756;
constexpr static double kappa = 24389.0 / 27.0; //903.29630;
constexpr static double kappaInv = 27.0 / 24389.0;
constexpr static double epsilonExpInv3 = 6.0 / 29.0;
constexpr static float epsf = eps;
constexpr static float kappaf = kappa;
constexpr static float kappaInvf = kappaInv;
constexpr static float epsilonExpInv3f = epsilonExpInv3;
constexpr static float D50x = 0.9642f; //0.96422;
constexpr static float D50z = 0.8249f; //0.82521;
constexpr static double u0 = 4.0 * D50x / (D50x + 15 + 3 * D50z);
constexpr static double v0 = 9.0 / (D50x + 15 + 3 * D50z);
constexpr static double epskap = 8.0;
constexpr static float c1By116 = 1.0 / 116.0;
constexpr static float c16By116 = 16.0 / 116.0;
static cmsToneCurve* linearGammaTRC;
static LUTf cachef;
static LUTf cachefy;
static LUTf gamma2curve;
// look-up tables for the standard srgb gamma and its inverse (filled by init())
@ -185,16 +206,16 @@ public:
* @brief Convert red/green/blue to hue/saturation/luminance
* @param profile output profile name
* @param profileW working profile name
* @param r red channel [0 ; 65535]
* @param g green channel [0 ; 65535]
* @param b blue channel [0 ; 65535]
* @param r red channel [0 ; 1]
* @param g green channel [0 ; 1]
* @param b blue channel [0 ; 1]
* @param L Lab L channel [0 ; 1] (return value)
* @param a Lab a channel [0 ; 1] (return value)
* @param a Lab a channel [0 ; 1] (return value)
* @param b Lab b channel [0; 1] (return value)
* @param workingSpace true: compute the Lab value using the Working color space ; false: use the Output color space
*/
static void rgb2lab(Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace);
// do not use this function in a loop. It really eats processing time caused by Glib::ustring comparisons
static void rgb2lab01 (const Glib::ustring &profile, const Glib::ustring &profileW, float r, float g, float b, float &LAB_l, float &LAB_a, float &LAB_b, bool workingSpace);
/**
* @brief Convert red/green/blue to hue/saturation/luminance
@ -328,6 +349,17 @@ public:
*/
static void rgb2hsv(float r, float g, float b, float &h, float &s, float &v);
/**
* @brief Convert red green blue to hue saturation value
* @param r red channel [0 ; 1]
* @param g green channel [0 ; 1]
* @param b blue channel [0 ; 1]
* @param h hue channel [0 ; 1] (return value)
* @param s saturation channel [0 ; 1] (return value)
* @param v value channel [0 ; 1] (return value)
*/
static void rgb2hsv01 (float r, float g, float b, float &h, float &s, float &v);
static inline float rgb2s(float r, float g, float b) // fast version if only saturation is needed
{
float var_Min = min(r, g, b);
@ -676,27 +708,21 @@ public:
*/
static inline double f2xyz(double f)
{
const double epsilonExpInv3 = 6.0 / 29.0;
const double kappaInv = 27.0 / 24389.0; // inverse of kappa
return (f > epsilonExpInv3) ? f * f * f : (116. * f - 16.) * kappaInv;
}
static inline float f2xyz(float f)
{
const float epsilonExpInv3 = 0.20689655f; // 6.0f/29.0f;
const float kappaInv = 0.0011070565f; // 27.0f/24389.0f; // inverse of kappa
return (f > epsilonExpInv3) ? f * f * f : (116.f * f - 16.f) * kappaInv;
return (f > epsilonExpInv3f) ? f * f * f : (116.f * f - 16.f) * kappaInvf;
}
#ifdef __SSE2__
static inline vfloat f2xyz(vfloat f)
{
const vfloat epsilonExpInv3 = F2V(0.20689655f); // 6.0f/29.0f;
const vfloat kappaInv = F2V(0.0011070565f); // 27.0f/24389.0f; // inverse of kappa
const vfloat epsilonExpInv3v = F2V(epsilonExpInv3f);
const vfloat kappaInvv = F2V(kappaInvf);
vfloat res1 = f * f * f;
vfloat res2 = (F2V(116.f) * f - F2V(16.f)) * kappaInv;
return vself(vmaskf_gt(f, epsilonExpInv3), res1, res2);
vfloat res2 = (F2V(116.f) * f - F2V(16.f)) * kappaInvv;
return vself(vmaskf_gt(f, epsilonExpInv3v), res1, res2);
}
#endif

View File

@ -3861,7 +3861,7 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b
if(!cbrtinit) {
for (int i = 0; i < 0x14000; i++) {
double r = i / 65535.0;
cbrt[i] = r > 0.008856f ? std::cbrt(r) : 7.787f * r + 16.f / 116.f;
cbrt[i] = r > Color::eps ? std::cbrt(r) : (Color::kappa * r + 16.0) / 116.0;
}
cbrtinit = true;
@ -3871,7 +3871,6 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b
}
#ifdef __SSE2__
vfloat zd5v = F2V(0.5f);
vfloat c116v = F2V(116.f);
vfloat c16v = F2V(16.f);
vfloat c500v = F2V(500.f);
@ -3892,12 +3891,12 @@ void RawImageSource::cielab (const float (*rgb)[3], float* l, float* a, float *b
for(; j < labWidth - 3; j += 4) {
vfloat redv, greenv, bluev;
vconvertrgbrgbrgbrgb2rrrrggggbbbb(rgb[i * width + j], redv, greenv, bluev);
vfloat xyz0v = zd5v + redv * xyz_camv[0][0] + greenv * xyz_camv[0][1] + bluev * xyz_camv[0][2];
vfloat xyz1v = zd5v + redv * xyz_camv[1][0] + greenv * xyz_camv[1][1] + bluev * xyz_camv[1][2];
vfloat xyz2v = zd5v + redv * xyz_camv[2][0] + greenv * xyz_camv[2][1] + bluev * xyz_camv[2][2];
xyz0v = cbrt[_mm_cvttps_epi32(xyz0v)];
xyz1v = cbrt[_mm_cvttps_epi32(xyz1v)];
xyz2v = cbrt[_mm_cvttps_epi32(xyz2v)];
vfloat xyz0v = redv * xyz_camv[0][0] + greenv * xyz_camv[0][1] + bluev * xyz_camv[0][2];
vfloat xyz1v = redv * xyz_camv[1][0] + greenv * xyz_camv[1][1] + bluev * xyz_camv[1][2];
vfloat xyz2v = redv * xyz_camv[2][0] + greenv * xyz_camv[2][1] + bluev * xyz_camv[2][2];
xyz0v = cbrt[_mm_cvtps_epi32(xyz0v)];
xyz1v = cbrt[_mm_cvtps_epi32(xyz1v)];
xyz2v = cbrt[_mm_cvtps_epi32(xyz2v)];
STVFU(l[i * labWidth + j], c116v * xyz1v - c16v);
STVFU(a[i * labWidth + j], c500v * (xyz0v - xyz1v));

View File

@ -28,7 +28,6 @@
#include "improcfun.h"
#include "StopWatch.h"
#include <iostream>
#include <iomanip>
namespace rtengine {
@ -37,20 +36,36 @@ extern const Settings *settings;
namespace {
std::vector<int> getCdf(const IImage8 &img)
struct CdfInfo {
std::vector<int> cdf;
int min_val;
int max_val;
CdfInfo(): cdf(256), min_val(-1), max_val(-1) {}
};
CdfInfo getCdf(const IImage8 &img)
{
std::vector<int> ret(256);
CdfInfo ret;
for (int y = 0; y < img.getHeight(); ++y) {
for (int x = 0; x < img.getWidth(); ++x) {
int lum = LIM(0, int(Color::rgbLuminance(float(img.r(y, x)), float(img.g(y, x)), float(img.b(y, x)))), 255);
++ret[lum];
++ret.cdf[lum];
}
}
int sum = 0;
for (size_t i = 0; i < ret.size(); ++i) {
sum += ret[i];
ret[i] = sum;
for (size_t i = 0; i < ret.cdf.size(); ++i) {
if (ret.cdf[i] > 0) {
if (ret.min_val < 0) {
ret.min_val = i;
}
ret.max_val = i;
}
sum += ret.cdf[i];
ret.cdf[i] = sum;
}
return ret;
@ -86,25 +101,35 @@ void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
curve.clear();
const int npoints = 8;
int idx = 1;
int idx = 15;
for (; idx < int(mapping.size()); ++idx) {
if (mapping[idx] >= idx) {
break;
}
}
int step = max(int(mapping.size())/npoints, 1);
if (idx == int(mapping.size())) {
for (idx = 1; idx < int(mapping.size()); ++idx) {
if (mapping[idx] >= idx) {
break;
}
}
}
int step = std::max(int(mapping.size())/npoints, 1);
auto coord = [](int v) -> double { return double(v)/255.0; };
auto doit =
[&](int start, int stop, int step, bool addstart) -> void
{
int prev = start;
if (addstart) {
if (addstart && mapping[start] >= 0) {
curve.push_back(coord(start));
curve.push_back(coord(mapping[start]));
}
for (int i = start; i < stop; ++i) {
int v = mapping[i];
if (v < 0) {
continue;
}
bool change = i > 0 && v != mapping[i-1];
int diff = i - prev;
if ((change && std::abs(diff - step) <= 1) || diff > step * 2) {
@ -114,12 +139,23 @@ void mappingToCurve(const std::vector<int> &mapping, std::vector<double> &curve)
}
}
};
doit(0, idx, idx > step ? step : idx / 2, true);
doit(idx, int(mapping.size()), step, idx - step > step / 2);
curve.push_back(0.0);
curve.push_back(0.0);
int start = 0;
while (start < idx && (mapping[start] < 0 || start < idx / 2)) {
++start;
}
doit(start, idx, idx > step ? step : idx / 2, true);
doit(idx, int(mapping.size()), step, idx - step > step / 2 && std::abs(curve[curve.size()-2] - coord(idx)) > 0.01);
if (curve.size() > 2 && (1 - curve[curve.size()-2] <= step / (256.0 * 3))) {
curve.pop_back();
curve.pop_back();
}
curve.push_back(1.0);
curve.push_back(1.0);
@ -153,7 +189,7 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector<double> &outCurve)
int fw, fh;
getFullSize(fw, fh, TR_NONE);
int skip = 10;
int skip = 3;
if (settings->verbose) {
std::cout << "histogram matching: full raw image size is " << fw << "x" << fh << std::endl;
@ -162,6 +198,7 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector<double> &outCurve)
ProcParams neutral;
neutral.raw.bayersensor.method = RAWParams::BayerSensor::getMethodString(RAWParams::BayerSensor::Method::FAST);
neutral.raw.xtranssensor.method = RAWParams::XTransSensor::getMethodString(RAWParams::XTransSensor::Method::FAST);
neutral.icm.output = "sRGB";
std::unique_ptr<IImage8> source;
{
@ -176,6 +213,7 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector<double> &outCurve)
histMatchingCache = outCurve;
return;
}
skip = LIM(skip * fh / h, 6, 10); // adjust the skip factor -- the larger the thumbnail, the less we should skip to get a good match
source.reset(thumb->quickProcessImage(neutral, fh / skip, TI_Nearest));
if (settings->verbose) {
@ -185,49 +223,56 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector<double> &outCurve)
std::unique_ptr<IImage8> target;
{
int tw = source->getWidth(), th = source->getHeight();
float thumb_ratio = float(std::max(tw, th)) / float(std::min(tw, th));
float target_ratio = float(std::max(fw, fh)) / float(std::min(fw, fh));
RawMetaDataLocation rml;
eSensorType sensor_type;
double scale;
int w = fw / skip, h = fh / skip;
std::unique_ptr<Thumbnail> thumb(Thumbnail::loadFromRaw(getFileName(), rml, sensor_type, w, h, 1, false, false));
if (!thumb) {
if (settings->verbose) {
std::cout << "histogram matching: raw decoding failed, generating a neutral curve" << std::endl;
}
histMatchingCache = outCurve;
return;
}
target.reset(thumb->processImage(neutral, sensor_type, fh / skip, TI_Nearest, getMetaData(), scale, false));
int sw = source->getWidth(), sh = source->getHeight();
int tw = target->getWidth(), th = target->getHeight();
float thumb_ratio = float(std::max(sw, sh)) / float(std::min(sw, sh));
float target_ratio = float(std::max(tw, th)) / float(std::min(tw, th));
int cx = 0, cy = 0;
if (std::abs(thumb_ratio - target_ratio) > 0.01) {
if (thumb_ratio > target_ratio) {
// crop the height
int ch = fh - (fw * float(th) / float(tw));
int ch = th - (tw * float(sh) / float(sw));
cy += ch / 2;
fh -= ch;
th -= ch;
} else {
// crop the width
int cw = fw - (fh * float(tw) / float(th));
int cw = tw - (th * float(sw) / float(sh));
cx += cw / 2;
fw -= cw;
tw -= cw;
}
if (settings->verbose) {
std::cout << "histogram matching: cropping target to get an aspect ratio of " << std::fixed << std::setprecision(2) << thumb_ratio << ":1, new full size is " << fw << "x" << fh << std::endl;
std::cout << "histogram matching: cropping target to get an aspect ratio of " << round(thumb_ratio * 100)/100.0 << ":1, new size is " << tw << "x" << th << std::endl;
}
if (cx || cy) {
Image8 *tmp = new Image8(tw, th);
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int y = 0; y < th; ++y) {
for (int x = 0; x < tw; ++x) {
tmp->r(y, x) = target->r(y+cy, x+cx);
tmp->g(y, x) = target->g(y+cy, x+cx);
tmp->b(y, x) = target->b(y+cy, x+cx);
}
}
target.reset(tmp);
}
}
PreviewProps pp(cx, cy, fw, fh, skip);
ColorTemp currWB = getWB();
std::unique_ptr<Imagefloat> image(new Imagefloat(int(fw / skip), int(fh / skip)));
{
RawImageSource rsrc;
rsrc.load(getFileName());
rsrc.preprocess(neutral.raw, neutral.lensProf, neutral.coarse, false);
rsrc.demosaic(neutral.raw);
rsrc.getImage(currWB, TR_NONE, image.get(), pp, neutral.toneCurve, neutral.raw);
}
// this could probably be made faster -- ideally we would need to just
// perform the transformation from camera space to the output space
// (taking gamma into account), but I couldn't find anything
// ready-made, so for now this will do. Remember the famous quote:
// "premature optimization is the root of all evil" :-)
convertColorSpace(image.get(), neutral.icm, currWB);
ImProcFunctions ipf(&neutral);
LabImage tmplab(image->getWidth(), image->getHeight());
ipf.rgb2lab(*image, tmplab, neutral.icm.working);
image.reset(ipf.lab2rgbOut(&tmplab, 0, 0, tmplab.W, tmplab.H, neutral.icm));
target.reset(image->to8());
if (settings->verbose) {
std::cout << "histogram matching: generated neutral rendering" << std::endl;
@ -238,14 +283,18 @@ void RawImageSource::getAutoMatchedToneCurve(std::vector<double> &outCurve)
target->resizeImgTo(source->getWidth(), source->getHeight(), TI_Nearest, tmp);
target.reset(tmp);
}
std::vector<int> scdf = getCdf(*source);
std::vector<int> tcdf = getCdf(*target);
CdfInfo scdf = getCdf(*source);
CdfInfo tcdf = getCdf(*target);
std::vector<int> mapping;
int j = 0;
for (size_t i = 0; i < tcdf.size(); ++i) {
j = findMatch(tcdf[i], scdf, j);
mapping.push_back(j);
for (int i = 0; i < int(tcdf.cdf.size()); ++i) {
j = findMatch(tcdf.cdf[i], scdf.cdf, j);
if (i >= tcdf.min_val && i <= tcdf.max_val && j >= scdf.min_val && j <= scdf.max_val) {
mapping.push_back(j);
} else {
mapping.push_back(-1);
}
}
mappingToCurve(mapping, outCurve);

View File

@ -3908,8 +3908,7 @@ void ImProcFunctions::rgbProc(Imagefloat* working, LabImage* lab, PipetteBuffer
// Luminosity after
// only Luminance in Lab
float newy = toxyz[1][0] * r + toxyz[1][1] * g + toxyz[1][2] * b;
float newfy = newy < MAXVALF ? Color::cachef[newy] : 327.68f * std::cbrt(newy / MAXVALF);
float L_2 = 116.0f * newfy - 5242.88f;
float L_2 = newy <= MAXVALF ? Color::cachefy[newy] : 327.68f * (116.f * xcbrtf(newy / MAXVALF) - 16.f);
//gamut control
if (settings->rgbcurveslumamode_gamut) {
@ -5810,7 +5809,7 @@ void ImProcFunctions::chromiLuminanceCurve (PipetteBuffer *pipetteBuffer, int pW
float aprov1 = Chprov2 * sincosval.y;
float bprov1 = Chprov2 * sincosval.x;
float fy = (0.00862069f * Lprov1) + 0.137932f;
float fy = (Color::c1By116 * Lprov1 ) + Color::c1By116;
float fx = (0.002f * aprov1) + fy;
float fz = fy - (0.005f * bprov1);

View File

@ -408,7 +408,7 @@ public:
void localContrast(LabImage *lab);
void colorToningLabGrid(LabImage *lab, int xstart, int xend, int ystart, int yend, bool MultiThread);
Image8* lab2rgb(LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm);
Image8* lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings=true);
Imagefloat* lab2rgbOut (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, GammaValues *ga = nullptr);
// CieImage *ciec;

View File

@ -122,7 +122,7 @@ 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)
Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch, const procparams::ColorManagementParams &icm, bool consider_histogram_settings)
{
//gamutmap(lab);
@ -147,7 +147,7 @@ Image8* ImProcFunctions::lab2rgb (LabImage* lab, int cx, int cy, int cw, int ch,
bool standard_gamma;
if(settings->HistogramWorking) {
if(settings->HistogramWorking && consider_histogram_settings) {
profile = icm.working;
standard_gamma = true;
} else {
@ -318,7 +318,7 @@ Imagefloat* ImProcFunctions::lab2rgbOut (LabImage* lab, int cx, int cy, int cw,
for (int j = cx; j < cx + cw; j++) {
float fy = (0.0086206897f * rL[j]) / 327.68f + 0.1379310345f; // (L+16)/116
float fy = (Color::c1By116 * rL[j]) / 327.68f + Color::c16By116; // (L+16)/116
float fx = (0.002f * ra[j]) / 327.68f + fy;
float fz = fy - (0.005f * rb[j]) / 327.68f;
float LL = rL[j] / 327.68f;

View File

@ -700,7 +700,7 @@ void ImProcFunctions::vibrance (LabImage* lab)
aprovn = Chprov * sincosval.y;
bprovn = Chprov * sincosval.x;
float fyy = (0.00862069f * Lprov ) + 0.137932f;
float fyy = (Color::c1By116 * Lprov ) + Color::c16By116;
float fxx = (0.002f * aprovn) + fyy;
float fzz = fyy - (0.005f * bprovn);
float xx_ = 65535.f * Color::f2xyz (fxx) * Color::D50x;

View File

@ -74,9 +74,9 @@ constexpr const T& max(const T& a, const T& b, const ARGS&... args)
}
template<typename T>
constexpr const T& LIM(const T& a, const T& b, const T& c)
constexpr const T& LIM(const T& val, const T& low, const T& high)
{
return max(b, min(a, c));
return max(low, min(val, high));
}
template<typename T>

View File

@ -137,6 +137,7 @@ extern Options options;
namespace rtengine
{
using namespace procparams;
Thumbnail* Thumbnail::loadFromImage (const Glib::ustring& fname, int &w, int &h, int fixwh, double wbEq, bool inspectorMode)
@ -465,8 +466,8 @@ Thumbnail* Thumbnail::loadFromRaw (const Glib::ustring& fname, RawMetaDataLocati
skip--;
}
if (skip < 1) {
skip = 1;
if (skip < 2) {
skip = 2;
}
int hskip = skip, vskip = skip;
@ -1304,7 +1305,7 @@ IImage8* Thumbnail::processImage (const procparams::ProcParams& params, eSensorT
readyImg = new Image8 (fw, fh);
ipf.lab2monitorRgb (labView, readyImg);
} else {
readyImg = ipf.lab2rgb(labView, 0, 0, fw, fh, params.icm);
readyImg = ipf.lab2rgb(labView, 0, 0, fw, fh, params.icm, false);
}
delete labView;
delete baseImg;

View File

@ -476,7 +476,7 @@ void HistogramRGBArea::updateFreeze (bool f)
return;
}
void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring profile, Glib::ustring profileW)
void HistogramRGBArea::updateBackBuffer (int r, int g, int b, const Glib::ustring &profile, const Glib::ustring &profileW)
{
if (!get_realized () || frozen || !showMode) {
return;
@ -531,7 +531,7 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring prof
if(needLuma || needChroma) {
float Lab_L, Lab_a, Lab_b;
rgb2lab( profile, profileW, r, g, b, Lab_L, Lab_a, Lab_b);
rtengine::Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, Lab_L, Lab_a, Lab_b, options.rtSettings.HistogramWorking);
if (needLuma) {
// Luma
@ -557,153 +557,6 @@ void HistogramRGBArea::updateBackBuffer (int r, int g, int b, Glib::ustring prof
setDirty(false);
}
void HistogramRGBArea::rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b)
{
double xyz_rgb[3][3];
const double ep = 216.0 / 24389.0;
const double ka = 24389.0 / 27.0;
double var_R = r / 255.0;
double var_G = g / 255.0;
double var_B = b / 255.0;
Glib::ustring profileCalc;
profileCalc = "sRGB"; //default
if(options.rtSettings.HistogramWorking) {
profileCalc = profileW; //display working
}
else {// if you want display = output space
if (profile == "RT_sRGB" || profile == "RT_sRGB_gBT709" || profile == "RT_sRGB_g10") {
profileCalc = "sRGB";
}
if (profile == "ProPhoto" || profile == "RT_Large_gBT709" || profile == "RT_Large_g10" || profile == "RT_Large_gsRGB") {
profileCalc = "ProPhoto";
}
if (profile == "AdobeRGB1998" || profile == "RT_Medium_gsRGB") {
profileCalc = "Adobe RGB";
}
if (profile == "WideGamutRGB") {
profileCalc = "WideGamut";
}
}
if(options.rtSettings.HistogramWorking) {//display working
if (profileW == "sRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
} else if (profileW == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else { // apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
} else { //display outout profile
if (profile == "RT_sRGB" || profile == "RT_Large_gsRGB" || profile == "RT_Medium_gsRGB") { //apply sRGB inverse gamma
if ( var_R > 0.04045 ) {
var_R = pow ( ( ( var_R + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_R = var_R / 12.92;
}
if ( var_G > 0.04045 ) {
var_G = pow ( ( ( var_G + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_G = var_G / 12.92;
}
if ( var_B > 0.04045 ) {
var_B = pow ( ( ( var_B + 0.055 ) / 1.055 ), rtengine::Color::sRGBGammaCurve);
} else {
var_B = var_B / 12.92;
}
}
else if (profile == "RT_sRGB_gBT709" || profile == "RT_Large_gBT709") { //
if ( var_R > 0.0795 ) {
var_R = pow ( ( ( var_R + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_R = var_R / 4.5;
}
if ( var_G > 0.0795 ) {
var_G = pow ( ( ( var_G + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_G = var_G / 4.5;
}
if ( var_B > 0.0795 ) {
var_B = pow ( ( ( var_B + 0.0954 ) / 1.0954 ), 2.2);
} else {
var_B = var_B / 4.5;
}
} else if (profile == "ProPhoto") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.8);
var_G = pow ( var_G, 1.8);
var_B = pow ( var_B, 1.8);
} else if (profile == "RT_sRGB_g10" || profile == "RT_Large_g10") { // apply inverse gamma 1.8
var_R = pow ( var_R, 1.);
var_G = pow ( var_G, 1.);
var_B = pow ( var_B, 1.);
}
else {// apply inverse gamma 2.2
var_R = pow ( var_R, 2.2);
var_G = pow ( var_G, 2.2);
var_B = pow ( var_B, 2.2);
}
}
// TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileW);
TMatrix wprof = rtengine::ICCStore::getInstance()->workingSpaceMatrix (profileCalc);
for (int m = 0; m < 3; m++)
for (int n = 0; n < 3; n++) {
xyz_rgb[m][n] = wprof[m][n];
}
double varxx, varyy, varzz;
double var_X = ( xyz_rgb[0][0] * var_R + xyz_rgb[0][1] * var_G + xyz_rgb[0][2] * var_B ) / Color::D50x;
double var_Y = ( xyz_rgb[1][0] * var_R + xyz_rgb[1][1] * var_G + xyz_rgb[1][2] * var_B ) ;
double var_Z = ( xyz_rgb[2][0] * var_R + xyz_rgb[2][1] * var_G + xyz_rgb[2][2] * var_B ) / Color::D50z;
varxx = var_X > ep ? cbrt(var_X) : ( ka * var_X + 16.0) / 116.0 ;
varyy = var_Y > ep ? cbrt(var_Y) : ( ka * var_Y + 16.0) / 116.0 ;
varzz = var_Z > ep ? cbrt(var_Z) : ( ka * var_Z + 16.0) / 116.0 ;
LAB_l = ( 116 * varyy ) - 16;
LAB_a = 500 * ( varxx - varyy );
LAB_b = 200 * ( varyy - varzz );
}
void HistogramRGBArea::update (int valh, int rh, int gh, int bh)
{

View File

@ -76,7 +76,7 @@ public:
HistogramRGBArea();
~HistogramRGBArea();
void updateBackBuffer (int r, int g, int b, Glib::ustring profile = "", Glib::ustring profileW = "");
void updateBackBuffer (int r, int g, int b, const Glib::ustring &profile = "", const Glib::ustring &profileW = "");
void updateFreeze (bool f);
bool getFreeze ();
bool getShow ();
@ -92,7 +92,6 @@ public:
bool on_draw(const ::Cairo::RefPtr< Cairo::Context> &cr);
bool on_button_press_event (GdkEventButton* event);
private:
void rgb2lab (Glib::ustring profile, Glib::ustring profileW, int r, int g, int b, float &LAB_l, float &LAB_a, float &LAB_b);
Gtk::SizeRequestMode get_request_mode_vfunc () const;
void get_preferred_height_vfunc (int& minimum_height, int& natural_height) const;
void get_preferred_width_vfunc (int &minimum_width, int &natural_width) const;

View File

@ -277,8 +277,8 @@ void LockableColorPicker::setRGB (const float R, const float G, const float B, c
gpreview = previewG;
bpreview = previewB;
rtengine::Color::rgb2hsv(r*65535.f, g*65535.f, b*65535.f, hue, sat, val);
rtengine::Color::rgb2lab (*outputProfile, *workingProfile, r * 65535.f, g * 65535.f, b * 65535.f, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
rtengine::Color::rgb2hsv01(r, g, b, hue, sat, val);
rtengine::Color::rgb2lab01(*outputProfile, *workingProfile, r, g, b, L, a, bb, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
if (validity != Validity::OUTSIDE) {
setDirty(true);

View File

@ -290,13 +290,13 @@ void Navigator::pointerMoved (bool validPos, Glib::ustring profile, Glib::ustrin
G->set_text (s2);
B->set_text (s3);
Color::rgb2hsv (r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, h, s, v);
Color::rgb2hsv01(r / 255.f, g / 255.f, b / 255.f, h, s, v);
getHSVText (h, s, v, s1, s2, s3);
H->set_text (s1);
S->set_text (s2);
V->set_text (s3);
Color::rgb2lab (profile, profileW, r * 0xffff / 0xff, g * 0xffff / 0xff, b * 0xffff / 0xff, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
Color::rgb2lab01(profile, profileW, r / 255.f, g / 255.f, b / 255.f, LAB_l, LAB_a, LAB_b, options.rtSettings.HistogramWorking); // TODO: Really sure this function works?
getLABText (LAB_l, LAB_a, LAB_b, s1, s2, s3);
LAB_L->set_text (s1);
LAB_A->set_text (s2);