Merge branch 'master' into gtk3

This commit is contained in:
Morgan Hardwood 2016-06-15 11:09:57 +02:00
commit ed4f439f94
7 changed files with 458 additions and 403 deletions

View File

@ -38,7 +38,9 @@ LUTf Color::gamma2curve;
LUTf Color::gammatab;
LUTuc Color::gammatabThumb;
LUTf Color::igammatab_srgb;
LUTf Color::igammatab_srgb1;
LUTf Color::gammatab_srgb;
LUTf Color::gammatab_srgb1;
// LUTf Color::igammatab_709;
// LUTf Color::gammatab_709;
LUTf Color::igammatab_55;
@ -143,7 +145,9 @@ void Color::init ()
gammatabThumb(maxindex, 0);
igammatab_srgb(maxindex, 0);
igammatab_srgb1(maxindex, 0);
gammatab_srgb(maxindex, 0);
gammatab_srgb1(maxindex, 0);
igammatab_55(maxindex, 0);
gammatab_55(maxindex, 0);
igammatab_4(maxindex, 0);
@ -187,19 +191,20 @@ void Color::init ()
{
for (int i = 0; i < maxindex; i++)
{
gammatab_srgb[i] = 65535.0 * gamma2(i / 65535.0);
gammatab_srgb[i] = gammatab_srgb1[i] = gamma2(i / 65535.0);
}
gammatab_srgb *= 65535.f;
gamma2curve.share(gammatab_srgb, LUT_CLIP_BELOW | LUT_CLIP_ABOVE); // shares the buffer with gammatab_srgb but has different clip flags
}
#ifdef _OPENMP
#pragma omp section
#endif
{
for (int i = 0; i < maxindex; i++) {
igammatab_srgb[i] = 65535.0 * igamma2 (i / 65535.0);
igammatab_srgb[i] = igammatab_srgb1[i] = igamma2 (i / 65535.0);
}
igammatab_srgb *= 65535.f;
}
#ifdef _OPENMP
#pragma omp section
#endif

View File

@ -129,7 +129,9 @@ public:
// look-up tables for the standard srgb gamma and its inverse (filled by init())
static LUTf igammatab_srgb;
static LUTf igammatab_srgb1;
static LUTf gammatab_srgb;
static LUTf gammatab_srgb1;
static LUTf igammatab_55;
static LUTf gammatab_55;
static LUTf igammatab_4;
@ -229,6 +231,42 @@ public:
*/
static void rgb2hsv (float r, float g, float b, float &h, float &s, float &v);
static inline bool rgb2hsvdcp(float r, float g, float b, float &h, float &s, float &v)
{
float var_Min = min(r, g, b);
if(var_Min < 0.f) {
return false;
} else {
float var_Max = max(r, g, b);
float del_Max = var_Max - var_Min;
v = var_Max / 65535.f;
if (fabsf(del_Max) < 0.00001f) {
h = 0.f;
s = 0.f;
} else {
s = del_Max / var_Max;
if ( r == var_Max ) {
h = (g - b) / del_Max;
} else if ( g == var_Max ) {
h = 2.f + (b - r) / del_Max;
} else { /*if ( b == var_Max ) */
h = 4.f + (r - g) / del_Max;
}
if ( h < 0.f ) {
h += 6.f;
} else if ( h > 6.f ) {
h -= 6.f;
}
}
return true;
}
}
/**
* @brief Convert hue saturation value in red green blue
@ -240,6 +278,57 @@ public:
* @param b blue channel [0 ; 65535] (return value)
*/
static void hsv2rgb (float h, float s, float v, float &r, float &g, float &b);
static inline void hsv2rgbdcp (float h, float s, float v, float &r, float &g, float &b)
{
// special version for dcp which saves 1 division (in caller) and six multiplications (inside this function)
int sector = h; // sector 0 to 5, floor() is very slow, and h is always >0
float f = h - sector; // fractional part of h
v *= 65535.f;
float vs = v * s;
float p = v - vs;
float q = v - f * vs;
float t = p + v - q;
switch (sector) {
case 1:
r = q;
g = v;
b = p;
break;
case 2:
r = p;
g = v;
b = t;
break;
case 3:
r = p;
g = q;
b = v;
break;
case 4:
r = t;
g = p;
b = v;
break;
case 5:
r = v;
g = p;
b = q;
break;
default:
r = v;
g = t;
b = p;
}
}
static void hsv2rgb (float h, float s, float v, int &r, int &g, int &b);

View File

@ -17,6 +17,7 @@
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <cstring>
#include "dcp.h"
@ -33,123 +34,93 @@ namespace
{
// This sRGB gamma is taken from DNG reference code, with the added linear extension past 1.0, as we run clipless here
float srgbGammaForward(float x)
DCPProfile::Matrix invert3x3(const DCPProfile::Matrix& a)
{
return
x <= 0.0031308f
? x * 12.92f
: x > 1.0f
? 1.0f + (x - 1.0f) * (1.055f * (1.0f / 2.4f)) // Linear extension
: 1.055f * pow(x, 1.0f / 2.4f) - 0.055f;
}
const double res00 = a[1][1] * a[2][2] - a[2][1] * a[1][2];
const double res10 = a[2][0] * a[1][2] - a[1][0] * a[2][2];
const double res20 = a[1][0] * a[2][1] - a[2][0] * a[1][1];
float srgbGammaInverse(float y)
{
return
y <= 0.0031308f * 12.92f
? y * (1.0f / 12.92f)
: y > 1.0f
? 1.0f + (y - 1.0f) / (1.055f * (1.0f / 2.4f))
: pow ((y + 0.055f) * (1.0f / 1.055f), 2.4f);
}
void invert3x3(const DCPProfile::Matrix& a, DCPProfile::Matrix& b)
{
const double& a00 = a[0][0];
const double& a01 = a[0][1];
const double& a02 = a[0][2];
const double& a10 = a[1][0];
const double& a11 = a[1][1];
const double& a12 = a[1][2];
const double& a20 = a[2][0];
const double& a21 = a[2][1];
const double& a22 = a[2][2];
double temp[3][3];
temp[0][0] = a11 * a22 - a21 * a12;
temp[0][1] = a21 * a02 - a01 * a22;
temp[0][2] = a01 * a12 - a11 * a02;
temp[1][0] = a20 * a12 - a10 * a22;
temp[1][1] = a00 * a22 - a20 * a02;
temp[1][2] = a10 * a02 - a00 * a12;
temp[2][0] = a10 * a21 - a20 * a11;
temp[2][1] = a20 * a01 - a00 * a21;
temp[2][2] = a00 * a11 - a10 * a01;
const double det = a00 * temp[0][0] + a01 * temp[1][0] + a02 * temp[2][0];
const double det = a[0][0] * res00 + a[0][1] * res10 + a[0][2] * res20;
if (std::fabs(det) < 1.0e-10) {
abort(); // Can't be inverted, we shouldn't be dealing with such matrices
std::cerr << "DCP matrix cannot be inverted! Expect weird output." << std::endl;
return a;
}
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
b[j][k] = temp[j][k] / det;
}
}
DCPProfile::Matrix res;
res[0][0] = res00 / det;
res[0][1] = (a[2][1] * a[0][2] - a[0][1] * a[2][2]) / det;
res[0][2] = (a[0][1] * a[1][2] - a[1][1] * a[0][2]) / det;
res[1][0] = res10 / det;
res[1][1] = (a[0][0] * a[2][2] - a[2][0] * a[0][2]) / det;
res[1][2] = (a[1][0] * a[0][2] - a[0][0] * a[1][2]) / det;
res[2][0] = res20 / det;
res[2][1] = (a[2][0] * a[0][1] - a[0][0] * a[2][1]) / det;
res[2][2] = (a[0][0] * a[1][1] - a[1][0] * a[0][1]) / det;
return res;
}
void multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b, DCPProfile::Matrix& c)
DCPProfile::Matrix multiply3x3(const DCPProfile::Matrix& a, const DCPProfile::Matrix& b)
{
// Use temp to support having output same as input
DCPProfile::Matrix m;
DCPProfile::Matrix res;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
m[i][j] = 0;
res[i][j] = 0;
for (int k = 0; k < 3; ++k) {
m[i][j] += a[i][k] * b[k][j];
res[i][j] += a[i][k] * b[k][j];
}
}
}
c = m;
return res;
}
void multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b, DCPProfile::Triple& c)
DCPProfile::Triple multiply3x3_v3(const DCPProfile::Matrix& a, const DCPProfile::Triple& b)
{
// Use temp to support having output same as input
DCPProfile::Triple m = {};
DCPProfile::Triple res = {};
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
m[i] += a[i][j] * b[j];
res[i] += a[i][j] * b[j];
}
}
c = m;
return res;
}
void mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b, DCPProfile::Matrix& c)
DCPProfile::Matrix mix3x3(const DCPProfile::Matrix& a, double mul_a, const DCPProfile::Matrix& b, double mul_b)
{
DCPProfile::Matrix m;
DCPProfile::Matrix res;
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
m[i][j] = a[i][j] * mul_a + b[i][j] * mul_b;
res[i][j] = a[i][j] * mul_a + b[i][j] * mul_b;
}
}
c = m;
return res;
}
void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2, DCPProfile::Matrix& b)
DCPProfile::Matrix mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple& white2)
{
// Code adapted from dng_color_spec::MapWhiteMatrix
// Use the linearized Bradford adaptation matrix
const DCPProfile::Matrix mb = {{
{ 0.8951, 0.2664, -0.1614 },
{ -0.7502, 1.7135, 0.0367 },
{ 0.0389, -0.0685, 1.0296 }
}};
const DCPProfile::Matrix mb = {
{
{ 0.8951, 0.2664, -0.1614 },
{ -0.7502, 1.7135, 0.0367 },
{ 0.0389, -0.0685, 1.0296 }
}
};
DCPProfile::Triple w1;
multiply3x3_v3(mb, white1, w1);
DCPProfile::Triple w2;
multiply3x3_v3(mb, white2, w2);
DCPProfile::Triple w1 = multiply3x3_v3(mb, white1);
DCPProfile::Triple w2 = multiply3x3_v3(mb, white2);
// Negative white coordinates are kind of meaningless.
w1[0] = std::max(w1[0], 0.0);
@ -165,44 +136,46 @@ void mapWhiteMatrix(const DCPProfile::Triple& white1, const DCPProfile::Triple&
a[1][1] = std::max(0.1, std::min(w1[1] > 0.0 ? w2[1] / w1[1] : 10.0, 10.0));
a[2][2] = std::max(0.1, std::min(w1[2] > 0.0 ? w2[2] / w1[2] : 10.0, 10.0));
DCPProfile::Matrix temp;
invert3x3(mb, temp);
multiply3x3(temp, a, temp);
multiply3x3(temp, mb, b);
return multiply3x3(multiply3x3(invert3x3(mb), a), mb);
}
void xyzToXy(const DCPProfile::Triple& xyz, double xy[2])
std::array<double, 2> xyzToXy(const DCPProfile::Triple& xyz)
{
const double total = xyz[0] + xyz[1] + xyz[2];
if (total > 0.0) {
xy[0] = xyz[0] / total;
xy[1] = xyz[1] / total;
} else {
xy[0] = 0.3457;
xy[1] = 0.3585;
}
return
total > 0.0
? std::array<double, 2>{
xyz[0] / total,
xyz[1] / total
}
: std::array<double, 2>{
0.3457,
0.3585
};
}
void xyToXyz(const double xy[2], DCPProfile::Triple& xyz)
DCPProfile::Triple xyToXyz(std::array<double, 2> xy)
{
double temp[2] = {xy[0], xy[1]};
// Restrict xy coord to someplace inside the range of real xy coordinates.
// This prevents math from doing strange things when users specify
// extreme temperature/tint coordinates.
temp[0] = std::max(0.000001, std::min(temp[0], 0.999999));
temp[1] = std::max(0.000001, std::min(temp[1], 0.999999));
xy[0] = std::max(0.000001, std::min(xy[0], 0.999999));
xy[1] = std::max(0.000001, std::min(xy[1], 0.999999));
if (temp[0] + temp[1] > 0.999999) {
double scale = 0.999999 / (temp[0] + temp[1]);
temp[0] *= scale;
temp[1] *= scale;
const double sum = xy[0] + xy[1];
if (sum > 0.999999) {
const double scale = 0.999999 / sum;
xy[0] *= scale;
xy[1] *= scale;
}
xyz[0] = temp[0] / temp[1];
xyz[1] = 1.0;
xyz[2] = (1.0 - temp[0] - temp[1]) / temp[1];
return {
xy[0] / xy[1],
1.0,
(1.0 - xy[0] - xy[1]) / xy[1]
};
}
double calibrationIlluminantToTemperature(int light)
@ -293,7 +266,7 @@ double calibrationIlluminantToTemperature(int light)
}
}
void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint)
double xyCoordToTemperature(const std::array<double, 2>& white_xy)
{
struct Ruvt {
double r;
@ -338,8 +311,7 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint)
constexpr double tint_scale = -3000.0;
double temperature = 0;
double computed_tint = 0;
double res = 0;
// Convert to uv space.
double u = 2.0 * white_xy[0] / (1.5 - white_xy[0] + 6.0 * white_xy[1]);
@ -383,7 +355,7 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint)
}
// Interpolate the temperature.
temperature = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f));
res = 1.0e6 / (temp_table[index - 1].r * f + temp_table[index].r * (1.0 - f));
// Find delta from black body point to test coordinate.
uu = u - (temp_table [index - 1].u * f + temp_table [index].u * (1.0 - f));
@ -394,9 +366,6 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint)
len = sqrt (du * du + dv * dv);
du /= len;
dv /= len;
// Find distance along slope.
computed_tint = (uu * du + vv * dv) * tint_scale;
break;
}
@ -406,20 +375,14 @@ void xyCoordToTemperature(const double white_xy[2], double* temp, double* tint)
last_dv = dv;
}
if (temp != nullptr) {
*temp = temperature;
}
if (tint != nullptr) {
*tint = computed_tint;
}
return res;
}
}
struct DCPProfile::ApplyState::Data {
double pro_photo[3][3];
double work[3][3];
float pro_photo[3][3];
float work[3][3];
bool already_pro_photo;
bool use_tone_curve;
bool apply_look_table;
@ -733,13 +696,13 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
Tag* tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_1));
light_source_1 =
tag
? tag->toInt(0, rtexif::SHORT)
: -1;
? tag->toInt(0, rtexif::SHORT)
: -1;
tag = tagDir->getTag(toUnderlying(TagKey::CALIBRATION_ILLUMINANT_2));
light_source_2 =
tag
? tag->toInt(0, rtexif::SHORT)
: -1;
? tag->toInt(0, rtexif::SHORT)
: -1;
temperature_1 = calibrationIlluminantToTemperature(light_source_1);
temperature_2 = calibrationIlluminantToTemperature(light_source_2);
@ -774,9 +737,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
tag = tagDir->getTag(toUnderlying(TagKey::COLOR_MATRIX_1));
if (!tag) {
// FIXME: better error handling
fprintf(stderr, "Bad DCP, no ColorMatrix1\n");
abort();
std::cerr << "DCP '" << filename << "' is missing 'ColorMatrix1'. Skipped." << std::endl;
return;
}
has_color_matrix_1 = true;
@ -811,8 +773,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
// Precalculated constants for table application
look_info.pc.h_scale =
look_info.hue_divisions < 2
? 0.0f
: static_cast<float>(look_info.hue_divisions) / 6.0f;
? 0.0f
: static_cast<float>(look_info.hue_divisions) / 6.0f;
look_info.pc.s_scale = look_info.sat_divisions - 1;
look_info.pc.v_scale = look_info.val_divisions - 1;
look_info.pc.max_hue_index0 = look_info.hue_divisions - 1;
@ -845,8 +807,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
delta_info.pc.h_scale =
delta_info.hue_divisions < 2
? 0.0f
: static_cast<float>(delta_info.hue_divisions) / 6.0f;
? 0.0f
: static_cast<float>(delta_info.hue_divisions) / 6.0f;
delta_info.pc.s_scale = delta_info.sat_divisions - 1;
delta_info.pc.v_scale = delta_info.val_divisions - 1;
delta_info.pc.max_hue_index0 = delta_info.hue_divisions - 1;
@ -866,8 +828,8 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
for (int col = 0; col < 3; ++col) {
color_matrix_2[row][col] =
tag
? tag->toDouble((col + row * 3) * 8)
: color_matrix_1[row][col];
? tag->toDouble((col + row * 3) * 8)
: color_matrix_1[row][col];
}
}
@ -979,6 +941,11 @@ DCPProfile::~DCPProfile()
{
}
DCPProfile::operator bool() const
{
return has_color_matrix_1;
}
bool DCPProfile::getHasToneCurve() const
{
return has_tone_curve;
@ -1017,15 +984,13 @@ void DCPProfile::apply(
const ColorTemp& white_balance,
const Triple& pre_mul,
const Matrix& cam_wb_matrix,
bool use_tone_curve,
bool apply_hue_sat_map,
bool apply_look_table
bool apply_hue_sat_map
) const
{
const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space);
Matrix xyz_cam; // Camera RGB to XYZ D50 matrix
makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam);
const Matrix xyz_cam = makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant); // Camera RGB to XYZ D50 matrix
const std::vector<HsbModify> delta_base = makeHueSatMap(white_balance, preferred_illuminant);
@ -1033,15 +998,9 @@ void DCPProfile::apply(
apply_hue_sat_map = false;
}
if (look_table.empty()) {
apply_look_table = false;
}
use_tone_curve = use_tone_curve && tone_curve;
if (!apply_hue_sat_map && !apply_look_table && !use_tone_curve) {
// The fast path: No LUT and not tone curve --> Calculate matrix for direct conversion raw>working space
double mat[3][3] = {};
if (!apply_hue_sat_map) {
// The fast path: No LUT --> Calculate matrix for direct conversion raw -> working space
float mat[3][3] = {};
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -1055,6 +1014,7 @@ void DCPProfile::apply(
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int y = 0; y < img->height; ++y) {
for (int x = 0; x < img->width; x++) {
const float& newr = mat[0][0] * img->r(y, x) + mat[0][1] * img->g(y, x) + mat[0][2] * img->b(y, x);
@ -1068,7 +1028,7 @@ void DCPProfile::apply(
}
} else {
// LUT available --> Calculate matrix for conversion raw>ProPhoto
double pro_photo[3][3] = {};
float pro_photo[3][3] = {};
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -1078,7 +1038,7 @@ void DCPProfile::apply(
}
}
double work[3][3] = {};
float work[3][3] = {};
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
@ -1090,56 +1050,32 @@ void DCPProfile::apply(
// Convert to ProPhoto and apply LUT
#ifdef _OPENMP
#pragma omp parallel for
#pragma omp parallel for schedule(dynamic,16)
#endif
for (int y = 0; y < img->height; ++y) {
float h, s, v, hs, ss, vs;
for (int y = 0; y < img->height; ++y) {
for (int x = 0; x < img->width; x++) {
float newr = pro_photo[0][0] * img->r(y, x) + pro_photo[0][1] * img->g(y, x) + pro_photo[0][2] * img->b(y, x);
float newg = pro_photo[1][0] * img->r(y, x) + pro_photo[1][1] * img->g(y, x) + pro_photo[1][2] * img->b(y, x);
float newb = pro_photo[2][0] * img->r(y, x) + pro_photo[2][1] * img->g(y, x) + pro_photo[2][2] * img->b(y, x);
// If point is in negative area, just the matrix, but not the LUT
if (
(
apply_hue_sat_map
|| apply_look_table
)
&& newr >= 0
&& newg >= 0
&& newb >= 0
) {
float h;
float s;
float v;
Color::rgb2hsv(newr, newg, newb, h , s, v);
h *= 6.0f; // RT calculates in [0,1]
// If point is in negative area, just the matrix, but not the LUT. This is checked inside Color::rgb2hsvdcp
float h;
float s;
float v;
if (apply_hue_sat_map) {
hsdApply(delta_info, delta_base, h, s, v);
}
if(Color::rgb2hsvdcp(newr, newg, newb, h , s, v)) {
if (apply_look_table) {
hsdApply(look_info, look_table, h, s, v);
}
hsdApply(delta_info, delta_base, h, s, v);
// RT range correction
if (h < 0.0f) {
h += 6.0f;
}
if (h >= 6.0f) {
} else if (h >= 6.0f) {
h -= 6.0f;
}
h /= 6.f;
Color::hsv2rgb(h, s, v, newr, newg, newb);
}
if (use_tone_curve) {
tone_curve.Apply(newr, newg, newb);
Color::hsv2rgbdcp(h, s, v, newr, newg, newb);
}
img->r(y, x) = work[0][0] * newr + work[0][1] * newg + work[0][2] * newb;
@ -1200,11 +1136,10 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
#define FCLIP(a) ((a)>0.0?((a)<65535.5?(a):65535.5):0.0)
#define CLIP01(a) ((a)>0?((a)<1?(a):1):0)
float exp_scale = 1.0;
exp_scale *= as_in.data->bl_scale;
float exp_scale = as_in.data->bl_scale;
if (!as_in.data->use_tone_curve && !as_in.data->apply_look_table) {
if (exp_scale == 1.0) {
if (exp_scale == 1.f) {
return;
}
@ -1222,11 +1157,9 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
float g = gc[y * tile_width + x];
float b = bc[y * tile_width + x];
if (exp_scale != 1.0) {
r *= exp_scale;
g *= exp_scale;
b *= exp_scale;
}
r *= exp_scale;
g *= exp_scale;
b *= exp_scale;
float newr, newg, newb;
@ -1247,8 +1180,7 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
if (as_in.data->apply_look_table) {
float h, s, v;
Color::rgb2hsv(newr, newg, newb, h, s, v);
h *= 6.f; // RT calculates in [0,1]
Color::rgb2hsvdcp(newr, newg, newb, h, s, v);
hsdApply(look_info, look_table, h, s, v);
s = CLIP01(s);
@ -1257,14 +1189,11 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
// RT range correction
if (h < 0.0f) {
h += 6.0f;
}
if (h >= 6.0f) {
} else if (h >= 6.0f) {
h -= 6.0f;
}
h /= 6.f;
Color::hsv2rgb( h, s, v, newr, newg, newb);
Color::hsv2rgbdcp( h, s, v, newr, newg, newb);
}
if (as_in.data->use_tone_curve) {
@ -1285,7 +1214,7 @@ void DCPProfile::step2ApplyTile(float* rc, float* gc, float* bc, int width, int
}
}
void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const
DCPProfile::Matrix DCPProfile::findXyztoCamera(const std::array<double, 2>& white_xy, int preferred_illuminant) const
{
bool has_col_1 = has_color_matrix_1;
bool has_col_2 = has_color_matrix_2;
@ -1301,17 +1230,14 @@ void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illumin
}
// Mix if we have two matrices
double mix;
Matrix col;
if (has_col_1 && has_col_2) {
double wbtemp;
/*
Note: We're using DNG SDK reference code for XY to temperature translation to get the exact same mix as
the reference code does.
*/
xyCoordToTemperature(white_xy, &wbtemp, nullptr);
const double wbtemp = xyCoordToTemperature(white_xy);
double mix;
if (wbtemp <= temperature_1) {
mix = 1.0;
} else if (wbtemp >= temperature_2) {
@ -1323,44 +1249,36 @@ void DCPProfile::findXyztoCamera(const double white_xy[2], int preferred_illumin
// Interpolate
if (mix >= 1.0) {
col = color_matrix_1;
return color_matrix_1;
} else if (mix <= 0.0) {
col = color_matrix_2;
return color_matrix_2;
} else {
mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, col);
return mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix);
}
} else if (has_col_1) {
col = color_matrix_1;
return color_matrix_1;
} else {
col = color_matrix_2;
return color_matrix_2;
}
xyz_to_camera = col;
}
void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const
std::array<double, 2> DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant) const
{
enum {
MAX_PASSES = 30
};
double last_xy[2] = {0.3457, 0.3585}; // D50
std::array<double, 2> last_xy = {0.3457, 0.3585}; // D50
for (unsigned int pass = 0; pass < MAX_PASSES; ++pass) {
Matrix xyz_to_camera;
findXyztoCamera(last_xy, preferred_illuminant, xyz_to_camera);
const Matrix& xyz_to_camera = findXyztoCamera(last_xy, preferred_illuminant);
const Matrix& inv_m = invert3x3(xyz_to_camera);
const Triple& next_xyz = multiply3x3_v3(inv_m, neutral);
Matrix inv_m;
Triple next_xyz;
double next_xy[2];
invert3x3(xyz_to_camera, inv_m);
multiply3x3_v3(inv_m, neutral, next_xyz);
xyzToXy(next_xyz, next_xy);
std::array<double, 2> next_xy = xyzToXy(next_xyz);
if (std::fabs(next_xy[0] - last_xy[0]) + std::fabs(next_xy[1] - last_xy[1]) < 0.0000001) {
xy[0] = next_xy[0];
xy[1] = next_xy[1];
return;
return next_xy;
}
// If we reach the limit without converging, we are most likely
@ -1371,15 +1289,13 @@ void DCPProfile::neutralToXy(const Triple& neutral, int preferred_illuminant, do
next_xy[1] = (last_xy[1] + next_xy[1]) * 0.5;
}
last_xy[0] = next_xy[0];
last_xy[1] = next_xy[1];
last_xy = next_xy;
}
xy[0] = last_xy[0];
xy[1] = last_xy[1];
return last_xy;
}
void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const
DCPProfile::Matrix DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant) const
{
// Code adapted from dng_color_spec::FindXYZtoCamera.
// Note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support),
@ -1392,31 +1308,24 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
double r, g, b;
white_balance.getMultipliers(r, g, b);
// camWbMatrix == imatrices.xyz_cam
Matrix cam_xyz;
invert3x3(cam_wb_matrix, cam_xyz);
Matrix cam_rgb;
constexpr Matrix xyz_srgb = {{
{xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]},
{xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]},
{xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]}
}};
multiply3x3(cam_xyz, xyz_srgb, cam_rgb);
constexpr Matrix xyz_srgb = {
{
{xyz_sRGB[0][0], xyz_sRGB[0][1], xyz_sRGB[0][2]},
{xyz_sRGB[1][0], xyz_sRGB[1][1], xyz_sRGB[1][2]},
{xyz_sRGB[2][0], xyz_sRGB[2][1], xyz_sRGB[2][2]}
}
};
const Matrix cam_rgb = multiply3x3(invert3x3(cam_wb_matrix), xyz_srgb);
double camwb_red = cam_rgb[0][0] * r + cam_rgb[0][1] * g + cam_rgb[0][2] * b;
double camwb_green = cam_rgb[1][0] * r + cam_rgb[1][1] * g + cam_rgb[1][2] * b;
double camwb_blue = cam_rgb[2][0] * r + cam_rgb[2][1] * g + cam_rgb[2][2] * b;
neutral[0] = camwb_red / pre_mul[0];
neutral[1] = camwb_green / pre_mul[1];
neutral[2] = camwb_blue / pre_mul[2];
double maxentry = 0;
for (int i = 0; i < 3; i++) {
if (neutral[i] > maxentry) {
maxentry = neutral[i];
}
}
const double maxentry = std::max({neutral[0], neutral[1], neutral[2]});
for (int i = 0; i < 3; i++) {
for (int i = 0; i < 3; ++i) {
neutral[i] /= maxentry;
}
}
@ -1425,8 +1334,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
DCP ColorMatrix or ColorMatrices if dual-illuminant. This is the DNG reference code way to
do it, which is a bit different from RT's own white balance model at the time of writing.
When RT's white balance can make use of the DCP color matrices we could use that instead. */
double white_xy[2];
neutralToXy(neutral, preferred_illuminant, white_xy);
const std::array<double, 2> white_xy = neutralToXy(neutral, preferred_illuminant);
bool has_fwd_1 = has_forward_matrix_1;
bool has_fwd_2 = has_forward_matrix_2;
@ -1455,18 +1363,17 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
double mix = 1.0;
if ((has_col_1 && has_col_2) || (has_fwd_1 && has_fwd_2)) {
double wbtemp;
/* DNG ref way to convert XY to temperature, which affect matrix mixing. A different model here
typically does not affect the result too much, ie it's probably not strictly necessary to
use the DNG reference code here, but we do it for now. */
xyCoordToTemperature(white_xy, &wbtemp, nullptr);
const double wbtemp = xyCoordToTemperature(white_xy);
if (wbtemp <= temperature_1) {
mix = 1.0;
} else if (wbtemp >= temperature_2) {
mix = 0.0;
} else {
double invT = 1.0 / wbtemp;
const double& invT = 1.0 / wbtemp;
mix = (invT - (1.0 / temperature_2)) / ((1.0 / temperature_1) - (1.0 / temperature_2));
}
}
@ -1481,7 +1388,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
} else if (mix <= 0.0) {
color_matrix = color_matrix_2;
} else {
mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix, color_matrix);
color_matrix = mix3x3(color_matrix_1, mix, color_matrix_2, 1.0 - mix);
}
} else if (has_col_1) {
color_matrix = color_matrix_1;
@ -1497,8 +1404,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
will show incorrect color.
*/
Triple white_xyz;
xyToXyz(white_xy, white_xyz);
const Triple white_xyz = xyToXyz(white_xy);
Matrix cam_xyz;
@ -1513,7 +1419,7 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
} else if (mix <= 0.0) {
fwd = forward_matrix_2;
} else {
mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix, fwd);
fwd = mix3x3(forward_matrix_1, mix, forward_matrix_2, 1.0 - mix);
}
} else if (has_fwd_1) {
fwd = forward_matrix_1;
@ -1522,75 +1428,66 @@ void DCPProfile::makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mu
}
// adapted from dng_color_spec::SetWhiteXY
Triple camera_white;
multiply3x3_v3(color_matrix, white_xyz, camera_white);
const Triple camera_white = multiply3x3_v3(color_matrix, white_xyz);
const Matrix white_diag = {
{
{camera_white[0], 0, 0},
{0, camera_white[1], 0},
{0, 0, camera_white[2]}
}
};
const Matrix white_diag = {{
{camera_white[0], 0, 0},
{0, camera_white[1], 0},
{0, 0, camera_white[2]}
}};
Matrix white_diag_inv;
invert3x3(white_diag, white_diag_inv);
Matrix xyz_cam;
multiply3x3(fwd, white_diag_inv, xyz_cam);
invert3x3(xyz_cam, cam_xyz);
cam_xyz = invert3x3(multiply3x3(fwd, invert3x3(white_diag)));
} else {
Matrix white_matrix;
const Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50
mapWhiteMatrix(white_d50, white_xyz, white_matrix);
multiply3x3(color_matrix, white_matrix, cam_xyz);
constexpr Triple white_d50 = {0.3457, 0.3585, 0.2958}; // D50
cam_xyz = multiply3x3(color_matrix, mapWhiteMatrix(white_d50, white_xyz));
}
// Convert cam_xyz (XYZ D50 to CameraRGB, "PCS to Camera" in DNG terminology) to mXYZCAM
{
// This block can probably be simplified, seems unnecessary to pass through the sRGB matrix
// (probably dcraw legacy), it does no harm though as we don't clip anything.
int i, j, k;
// This block can probably be simplified, seems unnecessary to pass through the sRGB matrix
// (probably dcraw legacy), it does no harm though as we don't clip anything.
int i, j, k;
// Multiply out XYZ colorspace
double cam_rgb[3][3] = {};
// Multiply out XYZ colorspace
double cam_rgb[3][3] = {};
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
for (k = 0; k < 3; ++k) {
cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j];
}
}
}
// Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1)
double num;
for (i = 0; i < 3; ++i) {
for (num = j = 0; j < 3; ++j) {
num += cam_rgb[i][j];
}
for (j = 0; j < 3; ++j) {
cam_rgb[i][j] /= num;
}
}
double rgb_cam[3][3] = {};
RawImageSource::inverse33(cam_rgb, rgb_cam);
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
xyz_cam[i][j] = 0;
}
}
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
for (k = 0; k < 3; ++k) {
xyz_cam[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j];
}
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
for (k = 0; k < 3; ++k) {
cam_rgb[i][j] += cam_xyz[i][k] * xyz_sRGB[k][j];
}
}
}
// Normalize cam_rgb so that cam_rgb * (1,1,1) is (1,1,1,1)
double num;
for (i = 0; i < 3; ++i) {
for (num = j = 0; j < 3; ++j) {
num += cam_rgb[i][j];
}
for (j = 0; j < 3; ++j) {
cam_rgb[i][j] /= num;
}
}
double rgb_cam[3][3] = {};
RawImageSource::inverse33(cam_rgb, rgb_cam);
Matrix res = {};
for (i = 0; i < 3; ++i) {
for (j = 0; j < 3; ++j) {
for (k = 0; k < 3; ++k) {
res[i][j] += xyz_sRGB[i][k] * rgb_cam[k][j];
}
}
}
return res;
}
std::vector<DCPProfile::HsbModify> DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const
@ -1621,14 +1518,15 @@ std::vector<DCPProfile::HsbModify> DCPProfile::makeHueSatMap(const ColorTemp& wh
const bool reverse = temperature_1 > temperature_2;
const double t1 =
reverse
? temperature_2
: temperature_1;
? temperature_2
: temperature_1;
const double t2 =
reverse
? temperature_1
: temperature_2;
? temperature_1
: temperature_2;
double mix;
if (white_balance.getTemp() <= t1) {
mix = 1.0;
} else if (white_balance.getTemp() >= t2) {
@ -1676,7 +1574,7 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector<HsbM
const float h_scaled = h * table_info.pc.h_scale;
const float s_scaled = s * table_info.pc.s_scale;
int h_index0 = std::max<int>(h_scaled, 0);
int h_index0 = max<int>(h_scaled, 0);
const int s_index0 = std::max(std::min<int>(s_scaled, table_info.pc.max_sat_index0), 0);
int h_index1 = h_index0 + 1;
@ -1714,12 +1612,12 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector<HsbM
const float s_scaled = s * table_info.pc.s_scale;
if (table_info.srgb_gamma) {
v_encoded = srgbGammaForward(v);
v_encoded = Color::gammatab_srgb1[v * 65535.f];
}
const float v_scaled = v_encoded * table_info.pc.v_scale;
int h_index0 = static_cast<int>(h_scaled);
int h_index0 = h_scaled;
const int s_index0 = std::max(std::min<int>(s_scaled, table_info.pc.max_sat_index0), 0);
const int v_index0 = std::max(std::min<int>(v_scaled, table_info.pc.max_val_index0), 0);
@ -1779,7 +1677,7 @@ void DCPProfile::hsdApply(const HsdTableInfo& table_info, const std::vector<HsbM
s *= sat_scale; // No clipping here, we are RT float :-)
if (table_info.srgb_gamma) {
v = srgbGammaInverse(v_encoded * val_scale);
v = Color::igammatab_srgb1[v_encoded * val_scale * 65535.f];
} else {
v *= val_scale;
}
@ -1872,10 +1770,14 @@ DCPProfile* DCPStore::getProfile(const Glib::ustring& filename) const
DCPProfile* const res = new DCPProfile(filename);
// Add profile
profile_cache[filename] = res;
if (*res) {
// Add profile
profile_cache[filename] = res;
return res;
}
return res;
delete res;
return nullptr;
}
DCPProfile* DCPStore::getStdProfile(const Glib::ustring& cam_short_name) const

View File

@ -66,6 +66,8 @@ public:
DCPProfile(const Glib::ustring& filename);
~DCPProfile();
explicit operator bool() const;
bool getHasToneCurve() const;
bool getHasLookTable() const;
bool getHasHueSatMap() const;
@ -80,9 +82,7 @@ public:
const ColorTemp& white_balance,
const Triple& pre_mul,
const Matrix& cam_wb_matrix,
bool use_tone_curve = false,
bool apply_hue_sat_map = true,
bool apply_look_table = false
bool apply_hue_sat_map = true
) const;
void setStep2ApplyState(const Glib::ustring& working_space, bool use_tone_curve, bool apply_look_table, bool apply_baseline_exposure, ApplyState& as_out);
void step2ApplyTile(float* r, float* g, float* b, int width, int height, int tile_width, const ApplyState& as_in) const;
@ -114,9 +114,9 @@ private:
} pc;
};
void findXyztoCamera(const double white_xy[2], int preferred_illuminant, Matrix& xyz_to_camera) const;
void neutralToXy(const Triple& neutral, int preferred_illuminant, double xy[2]) const;
void makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant, Matrix& xyz_cam) const;
Matrix findXyztoCamera(const std::array<double, 2>& white_xy, int preferred_illuminant) const;
std::array<double, 2> neutralToXy(const Triple& neutral, int preferred_illuminant) const;
Matrix makeXyzCam(const ColorTemp& white_balance, const Triple& pre_mul, const Matrix& cam_wb_matrix, int preferred_illuminant) const;
std::vector<HsbModify> makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const;
void hsdApply(const HsdTableInfo& table_info, const std::vector<HsbModify>& table_base, float& h, float& s, float& v) const;

View File

@ -20,184 +20,242 @@
#define _ICCMATRICES_
// Bradford transform between illuminants
const double d65_d50[3][3] = {{0.9555766, -0.0230393, 0.0631636},
constexpr double d65_d50[3][3] = {
{0.9555766, -0.0230393, 0.0631636},
{ -0.0282895, 1.0099416, 0.0210077},
{0.0122982, -0.0204830, 1.3299098}
};
const double d50_d65[3][3] = {{ 1.0478112, 0.0228866, -0.0501270},
constexpr double d50_d65[3][3] = {
{ 1.0478112, 0.0228866, -0.0501270},
{0.0295424, 0.9904844, -0.0170491},
{ -0.0092345, 0.0150436, 0.7521316}
};
// Color space conversion to/from XYZ; color spaces adapted to D65
const double xyz_sRGBd65[3][3] = {{0.4124564, 0.3575761, 0.1804375},
constexpr double xyz_sRGBd65[3][3] = {
{0.4124564, 0.3575761, 0.1804375},
{0.2126729, 0.7151522, 0.0721750}, // WARNING: the summ of this line is > 1.0
{0.0193339, 0.1191920, 0.9503041}
};
const double sRGBd65_xyz[3][3] = {{ 3.2404542, -1.5371385, -0.4985314},
constexpr double sRGBd65_xyz[3][3] = {
{ 3.2404542, -1.5371385, -0.4985314},
{ -0.9692660, 1.8760108, 0.0415560},
{0.0556434, -0.2040259, 1.0572252}
};
//%%%%%%%%%%%%%%%%%%%%%%%%
// TEST using Gabor's matrices
/*const double xyz_sRGB[3][3] = {{0.435859, 0.385336, 0.143023},
/*constexpr double xyz_sRGB[3][3] = {
{0.435859, 0.385336, 0.143023},
{0.222385, 0.717021, 0.0605936 },
{0.0139162, 0.0971389, 0.713817}};
const double sRGB_xyz[3][3] = {{3.13593293538656, -1.61878246026431, -0.490913888760734},
constexpr double sRGB_xyz[3][3] = {
{3.13593293538656, -1.61878246026431, -0.490913888760734},
{-0.978702373022194, 1.91609508555177, 0.0334453372795315},
{0.0720490013929888, -0.22919049060526, 1.40593851447263}};*/
//%%%%%%%%%%%%%%%%%%%%%%%%
// Color space conversion to/from XYZ; color spaces adapted to D50 using Bradford transform
constexpr double xyz_sRGB[3][3] = {{0.4360747, 0.3850649, 0.1430804},
constexpr double xyz_sRGB[3][3] = {
{0.4360747, 0.3850649, 0.1430804},
{0.2225045, 0.7168786, 0.0606169},
{0.0139322, 0.0971045, 0.7141733}
};
const double sRGB_xyz[3][3] = {{3.1338561, -1.6168667, -0.4906146},
constexpr double sRGB_xyz[3][3] = {
{3.1338561, -1.6168667, -0.4906146},
{ -0.9787684, 1.9161415, 0.0334540},
{0.0719453, -0.2289914, 1.4052427}
};
const double xyz_adobe[3][3] = {{0.6097559, 0.2052401, 0.1492240},
constexpr double xyz_adobe[3][3] = {
{0.6097559, 0.2052401, 0.1492240},
{0.3111242, 0.6256560, 0.0632197},
{0.0194811, 0.0608902, 0.7448387}
};
const double adobe_xyz[3][3] = {{1.9624274, -0.6105343, -0.3413404},
constexpr double adobe_xyz[3][3] = {
{1.9624274, -0.6105343, -0.3413404},
{ -0.9787684, 1.9161415, 0.0334540},
{0.0286869, -0.1406752, 1.3487655}
};
const double xyz_prophoto[3][3] = {{0.7976749, 0.1351917, 0.0313534},
constexpr double xyz_prophoto[3][3] = {
{0.7976749, 0.1351917, 0.0313534},
{0.2880402, 0.7118741, 0.0000857},
{0.0000000, 0.0000000, 0.8252100}
};
const double prophoto_xyz[3][3] = {{1.3459433, -0.2556075, -0.0511118},
constexpr double prophoto_xyz[3][3] = {
{1.3459433, -0.2556075, -0.0511118},
{ -0.5445989, 1.5081673, 0.0205351},
{0.0000000, 0.0000000, 1.2118128}
};
/*
const double xyz_rec2020[3][3] = {{0.636958, 0.144617, 0.168881},
constexpr double xyz_rec2020[3][3] = {
{0.636958, 0.144617, 0.168881},
{0.262700, 0.677998, 0.059302},
{0.0000000, 0.028073, 1.060985}
};
const double rec2020_xyz[3][3] = {{1.716651, -0.355671, -0.253366},
constexpr double rec2020_xyz[3][3] = {
{1.716651, -0.355671, -0.253366},
{ -0.666684, 1.616481, 0.015769},
{0.017640, -0.042771, 0.942103}
};
*/
const double xyz_rec2020[3][3] = {{0.6734241, 0.1656411, 0.1251286},
constexpr double xyz_rec2020[3][3] = {
{0.6734241, 0.1656411, 0.1251286},
{0.2790177, 0.6753402, 0.0456377},
{ -0.0019300, 0.0299784, 0.7973330}
};
const double rec2020_xyz[3][3] = {{1.6473376, -0.3935675, -0.2359961},
constexpr double rec2020_xyz[3][3] = {
{1.6473376, -0.3935675, -0.2359961},
{ -0.6826036, 1.6475887, 0.0128190},
{0.0296524, -0.0628993, 1.2531279}
};
const double xyz_widegamut[3][3] = {{0.7161046, 0.1009296, 0.1471858},
constexpr double xyz_widegamut[3][3] = {
{0.7161046, 0.1009296, 0.1471858},
{0.2581874, 0.7249378, 0.0168748},
{0.0000000, 0.0517813, 0.7734287}
};
const double widegamut_xyz[3][3] = {{ 1.4628067, -0.1840623, -0.2743606},
constexpr double widegamut_xyz[3][3] = {
{ 1.4628067, -0.1840623, -0.2743606},
{ -0.5217933, 1.4472381, 0.0677227},
{0.0349342, -0.0968930, 1.2884099}
};
const double xyz_bruce[3][3] = {{0.4941816, 0.3204834, 0.1495550},
constexpr double xyz_bruce[3][3] = {
{0.4941816, 0.3204834, 0.1495550},
{0.2521531, 0.6844869, 0.0633600},
{0.0157886, 0.0629304, 0.7464909}
};
const double bruce_xyz[3][3] = {{2.6502856, -1.2014485, -0.4289936},
constexpr double bruce_xyz[3][3] = {
{2.6502856, -1.2014485, -0.4289936},
{ -0.9787684, 1.9161415, 0.0334540},
{0.0264570, -0.1361227, 1.3458542}
};
const double xyz_beta[3][3] = {{0.6712537, 0.1745834, 0.1183829},
constexpr double xyz_beta[3][3] = {
{0.6712537, 0.1745834, 0.1183829},
{0.3032726, 0.6637861, 0.0329413},
{0.0000000, 0.0407010, 0.7845090}
};
const double beta_xyz[3][3] = {{1.6832270, -0.4282363, -0.2360185},
constexpr double beta_xyz[3][3] = {
{1.6832270, -0.4282363, -0.2360185},
{ -0.7710229, 1.7065571, 0.0446900},
{0.0400013, -0.0885376, 1.2723640}
};
const double xyz_best[3][3] = {{0.6326696, 0.2045558, 0.1269946},
constexpr double xyz_best[3][3] = {
{0.6326696, 0.2045558, 0.1269946},
{0.2284569, 0.7373523, 0.0341908},
{0.0000000, 0.0095142, 0.8156958}
};
const double best_xyz[3][3] = {{1.7552599, -0.4836786, -0.2530000},
constexpr double best_xyz[3][3] = {
{1.7552599, -0.4836786, -0.2530000},
{ -0.5441336, 1.5068789, 0.0215528},
{0.0063467, -0.0175761, 1.2256959}
};
/*const double sRGB_d50[3][3] = {{0.4360520246092, 0.2224915978656, 0.0139291219896},
{0.38508159282, 0.716886060114, 0.09709700166},
{0.1430874138552, 0.0606214863936, 0.714185469944}};
/*
constexpr double sRGB_d50[3][3] = {
{0.4360520246092, 0.2224915978656, 0.0139291219896},
{0.38508159282, 0.716886060114, 0.09709700166},
{0.1430874138552, 0.0606214863936, 0.714185469944}
};
const double d50_sRGB[3][3] = {{3.13405134405167,-0.978762729953942, 0.0719425766617001},
{-1.61702771153574,1.91614222810656, -0.228971178679309},
{-0.49065220876631,0.0334496273068589, 1.40521830559074}};*/
constexpr double d50_sRGB[3][3] = {
{3.13405134405167,-0.978762729953942, 0.0719425766617001},
{-1.61702771153574,1.91614222810656, -0.228971178679309},
{-0.49065220876631,0.0334496273068589, 1.40521830559074}
};
*/
/*
// Gabor's matrices
const double sRGB_d50[3][3] = {{0.435859, 0.222385, 0.0139162},
{0.385336, 0.717021, 0.0971389},
{0.143023, 0.0605936, 0.713817}};
constexpr double sRGB_d50[3][3] = {
{0.435859, 0.222385, 0.0139162},
{0.385336, 0.717021, 0.0971389},
{0.143023, 0.0605936, 0.713817}
};
const double d50_sRGB[3][3] = {{3.13593293538656, -0.978702373022194, 0.0720490013929888},
{-1.61878246026431, 1.91609508555177, -0.22919049060526},
{-0.490913888760734, 0.0334453372795315, 1.40593851447263}};
constexpr double d50_sRGB[3][3] = {
{3.13593293538656, -0.978702373022194, 0.0720490013929888},
{-1.61878246026431, 1.91609508555177, -0.22919049060526},
{-0.490913888760734, 0.0334453372795315, 1.40593851447263}
};
const double adobe_d50[3][3] = {{0.6097395054954, 0.3111142944042, 0.0194773131652},
{0.2052518325737, 0.6256618480686, 0.0608872306106},
{0.1492308013399, 0.0632241329247, 0.744846530711}};
const double d50_adobe[3][3] = {{1.9624959949628, -0.978762712052774, 0.0286904764959749},
{-0.610587687828765,1.91614073756734, -0.140667763143042},
{-0.34136021627766, 0.0334501217627688, 1.34875045144924}};
const double prophoto_d50[3][3] = {{0.797675, 0.288040, 0.000000},
{0.135192, 0.711874, 0.000000},
{0.0313534,0.000086, 0.825210}};
const double d50_prophoto[3][3] = {{1.34594335079331, -0.544598514291158, 0},
{-0.255608118122657, 1.50816768465213, 0},
{-0.0511117387775285, 0.0205345459181255, 1.21181275069376}};
const double widegamut_d50[3][3] = {{0.716105, 0.258187, 0.000000},
{0.100930, 0.724938, 0.0517813},
{0.147186, 0.0168748, 0.773429}};
const double d50_widegamut[3][3] = {{1.46280597103052, -0.521792197260068, 0.0349341417298585},
{-0.184062984909417, 1.44723786022891, -0.0968930022172314},
{-0.27436071519732, 0.0677226440980744,1.28840945122198}};
const double bruce_d50[3][3] = {{0.4941607255908, 0.2521412970174, 0.0157852934504},
{0.3204990468435, 0.684494580042, 0.062927176507},
{0.1495612990809, 0.0633643619597, 0.746498914581}};
const double d50_bruce[3][3] = {{2.65042308164152, -0.978762745761462, 0.0264609493245811},
{-1.20155941925411, 1.9161402914007, -0.136115844662896},
{-0.42902228923717, 0.0334495071197919, 1.34583900936772}};
const double beta_d50[3][3] = {{0.671254, 0.303273, 0.000000},
{0.174583, 0.663786, 0.040701},
{0.118383, 0.0329413, 0.784509}};
const double d50_beta[3][3] = {{1.68322591962771, -0.771023599950842, 0.0400013658754702},
{-0.428235060337656, 1.70655704781303, -0.0885376438040078},
{-0.236018598193503, 0.0446902191738489,1.27236406897742}};
const double best_d50[3][3] = {{0.632670, 0.228457, 0.000000},
{0.204556, 0.737352, 0.00951424},
{0.126995, 0.0341908, 0.815696}};
const double d50_best[3][3] = {{1.75525923340349, -0.544133953997468, 0.00634675299435191},
{-0.483679025800866, 1.50687975713407, -0.017576175021718},
{-0.253000840399762, 0.0215532098817316,1.22569552576991}};
constexpr double adobe_d50[3][3] = {
{0.6097395054954, 0.3111142944042, 0.0194773131652},
{0.2052518325737, 0.6256618480686, 0.0608872306106},
{0.1492308013399, 0.0632241329247, 0.744846530711}
};
constexpr double d50_adobe[3][3] = {
{1.9624959949628, -0.978762712052774, 0.0286904764959749},
{-0.610587687828765,1.91614073756734, -0.140667763143042},
{-0.34136021627766, 0.0334501217627688, 1.34875045144924}
};
constexpr double prophoto_d50[3][3] = {
{0.797675, 0.288040, 0.000000},
{0.135192, 0.711874, 0.000000},
{0.0313534,0.000086, 0.825210}
};
constexpr double d50_prophoto[3][3] = {
{1.34594335079331, -0.544598514291158, 0},
{-0.255608118122657, 1.50816768465213, 0},
{-0.0511117387775285, 0.0205345459181255, 1.21181275069376}
};
constexpr double widegamut_d50[3][3] = {
{0.716105, 0.258187, 0.000000},
{0.100930, 0.724938, 0.0517813},
{0.147186, 0.0168748, 0.773429}
};
constexpr double d50_widegamut[3][3] = {
{1.46280597103052, -0.521792197260068, 0.0349341417298585},
{-0.184062984909417, 1.44723786022891, -0.0968930022172314},
{-0.27436071519732, 0.0677226440980744,1.28840945122198}
};
constexpr double bruce_d50[3][3] = {
{0.4941607255908, 0.2521412970174, 0.0157852934504},
{0.3204990468435, 0.684494580042, 0.062927176507},
{0.1495612990809, 0.0633643619597, 0.746498914581}
};
constexpr double d50_bruce[3][3] = {
{2.65042308164152, -0.978762745761462, 0.0264609493245811},
{-1.20155941925411, 1.9161402914007, -0.136115844662896},
{-0.42902228923717, 0.0334495071197919, 1.34583900936772}
};
constexpr double beta_d50[3][3] = {
{0.671254, 0.303273, 0.000000},
{0.174583, 0.663786, 0.040701},
{0.118383, 0.0329413, 0.784509}
};
constexpr double d50_beta[3][3] = {
{1.68322591962771, -0.771023599950842, 0.0400013658754702},
{-0.428235060337656, 1.70655704781303, -0.0885376438040078},
{-0.236018598193503, 0.0446902191738489,1.27236406897742}
};
constexpr double best_d50[3][3] = {
{0.632670, 0.228457, 0.000000},
{0.204556, 0.737352, 0.00951424},
{0.126995, 0.0341908, 0.815696}
};
constexpr double d50_best[3][3] = {
{1.75525923340349, -0.544133953997468, 0.00634675299435191},
{-0.483679025800866, 1.50687975713407, -0.017576175021718},
{-0.253000840399762, 0.0215532098817316,1.22569552576991}
};
*/
#endif

View File

@ -40,7 +40,7 @@
#include "improccoordinator.h"
#include "clutstore.h"
#include "ciecam02.h"
#define BENCHMARK
//#define BENCHMARK
#include "StopWatch.h"
#include "../rtgui/ppversion.h"
#include "../rtgui/guiutils.h"
@ -2957,6 +2957,7 @@ void ImProcFunctions::rgbProc (Imagefloat* working, LabImage* lab, PipetteBuffer
SHMap* shmap, int sat, LUTf & rCurve, LUTf & gCurve, LUTf & bCurve, float satLimit , float satLimitOpacity, const ColorGradientCurve & ctColorCurve, const OpacityCurve & ctOpacityCurve, bool opautili, LUTf & clToningcurve, LUTf & cl2Toningcurve,
const ToneCurve & customToneCurve1, const ToneCurve & customToneCurve2, const ToneCurve & customToneCurvebw1, const ToneCurve & customToneCurvebw2, double &rrm, double &ggm, double &bbm, float &autor, float &autog, float &autob, double expcomp, int hlcompr, int hlcomprthresh, DCPProfile *dcpProf, const DCPProfile::ApplyState &asIn )
{
BENCHFUN
Imagefloat *tmpImage = nullptr;
// NOTE: We're getting all 3 pointers here, but this function may not need them all, so one could optimize this

View File

@ -3737,7 +3737,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam
{camMatrix[1][0], camMatrix[1][1], camMatrix[1][2]},
{camMatrix[2][0], camMatrix[2][1], camMatrix[2][2]}
}};
dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, false, cmp.applyHueSatMap, false);
dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul_row, cam_matrix, cmp.applyHueSatMap);
return;
}