Another bunch of cleanups

- DCPProfile::apply()
- DCPProfile::makeHueSatMap()
- DCPProfile::hsdApply()
- Refactoring

More to come...
This commit is contained in:
Flössie 2016-06-07 21:04:12 +02:00
parent 2abd641c06
commit 8ee8eb4ed6
4 changed files with 283 additions and 265 deletions

View File

@ -16,6 +16,7 @@
* You should have received a copy of the GNU General Public License
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
*/
#include <memory>
#include <cstring>
@ -609,10 +610,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
has_tone_curve(false),
has_baseline_exposure_offset(false),
will_interpolate(false),
baseline_exposure_offset(0.0),
deltas_1(nullptr),
deltas_2(nullptr),
look_table(nullptr)
baseline_exposure_offset(0.0)
{
constexpr int tiff_float_size = 4;
@ -709,9 +707,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_LOOK_TABLE_DATA));
look_info.array_count = tag->getCount() / 3;
look_table = new HSBModify[look_info.array_count];
look_table.resize(look_info.array_count);
for (int i = 0; i < look_info.array_count; i++) {
for (unsigned int i = 0; i < look_info.array_count; i++) {
look_table[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size);
look_table[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size);
look_table[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size);
@ -724,11 +722,11 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
: 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.maxHueIndex0 = look_info.hue_divisions - 1;
look_info.pc.maxSatIndex0 = look_info.sat_divisions - 2;
look_info.pc.maxValIndex0 = look_info.val_divisions - 2;
look_info.pc.hueStep = look_info.sat_divisions;
look_info.pc.valStep = look_info.hue_divisions * look_info.pc.hueStep;
look_info.pc.max_hue_index0 = look_info.hue_divisions - 1;
look_info.pc.max_sat_index0 = look_info.sat_divisions - 2;
look_info.pc.max_val_index0 = look_info.val_divisions - 2;
look_info.pc.hue_step = look_info.sat_divisions;
look_info.pc.val_step = look_info.hue_divisions * look_info.pc.hue_step;
}
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DIMS));
@ -744,9 +742,9 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_1));
delta_info.array_count = tag->getCount() / 3;
deltas_1 = new HSBModify[delta_info.array_count];
deltas_1.resize(delta_info.array_count);
for (int i = 0; i < delta_info.array_count; ++i) {
for (unsigned int i = 0; i < delta_info.array_count; ++i) {
deltas_1[i].hue_shift = tag->toDouble((i * 3) * tiff_float_size);
deltas_1[i].sat_scale = tag->toDouble((i * 3 + 1) * tiff_float_size);
deltas_1[i].val_scale = tag->toDouble((i * 3 + 2) * tiff_float_size);
@ -758,11 +756,11 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
: 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.maxHueIndex0 = delta_info.hue_divisions - 1;
delta_info.pc.maxSatIndex0 = delta_info.sat_divisions - 2;
delta_info.pc.maxValIndex0 = delta_info.val_divisions - 2;
delta_info.pc.hueStep = delta_info.sat_divisions;
delta_info.pc.valStep = delta_info.hue_divisions * delta_info.pc.hueStep;
delta_info.pc.max_hue_index0 = delta_info.hue_divisions - 1;
delta_info.pc.max_sat_index0 = delta_info.sat_divisions - 2;
delta_info.pc.max_val_index0 = delta_info.val_divisions - 2;
delta_info.pc.hue_step = delta_info.sat_divisions;
delta_info.pc.val_step = delta_info.hue_divisions * delta_info.pc.hue_step;
}
if (light_source_2 != -1) {
@ -782,7 +780,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
// Second huesatmap
if (has_second_hue_sat) {
deltas_2 = new HSBModify[delta_info.array_count];
deltas_2.resize(delta_info.array_count);
// Saturation maps. Need to be unwinded.
tag = tagDir->getTag(toUnderlying(TagKey::PROFILE_HUE_SAT_MAP_DATA_2));
@ -862,7 +860,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
will_interpolate = true;
}
if (deltas_1 && deltas_2) {
if (!deltas_1.empty() && !deltas_2.empty()) {
// We assume tables are different
will_interpolate = true;
}
@ -874,7 +872,7 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
will_interpolate = true;
}
if (deltas_1 && deltas_2) {
if (!deltas_1.empty() && !deltas_2.empty()) {
will_interpolate = true;
}
}
@ -886,9 +884,6 @@ DCPProfile::DCPProfile(const Glib::ustring& filename) :
DCPProfile::~DCPProfile()
{
delete[] deltas_1;
delete[] deltas_2;
delete[] look_table;
}
bool DCPProfile::getHasToneCurve() const
@ -898,12 +893,12 @@ bool DCPProfile::getHasToneCurve() const
bool DCPProfile::getHasLookTable() const
{
return look_table;
return !look_table.empty();
}
bool DCPProfile::getHasHueSatMap() const
{
return deltas_1;
return !deltas_1.empty();
}
bool DCPProfile::getHasBaselineExposureOffset() const
@ -911,100 +906,129 @@ bool DCPProfile::getHasBaselineExposureOffset() const
return has_baseline_exposure_offset;
}
void DCPProfile::getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) const
DCPProfile::Illuminants DCPProfile::getIlluminants() const
{
i1 = light_source_1;
i2 = light_source_2;
temp1 = temperature_1, temp2 = temperature_2;
willInterpolate_ = will_interpolate;
};
return {
light_source_1,
light_source_2,
temperature_1,
temperature_2,
will_interpolate
};
}
void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::ustring &workingSpace, const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], bool useToneCurve, bool applyHueSatMap, bool applyLookTable) const
void DCPProfile::apply(
Imagefloat* img,
int preferred_illuminant,
const Glib::ustring& working_space,
const ColorTemp& white_balance,
double pre_mul[3],
double cam_wb_matrix[3][3],
bool use_tone_curve,
bool apply_hue_sat_map,
bool apply_look_table
) const
{
const TMatrix work_matrix = iccStore->workingSpaceInverseMatrix(working_space);
TMatrix mWork = iccStore->workingSpaceInverseMatrix (workingSpace);
double xyz_cam[3][3]; // Camera RGB to XYZ D50 matrix
makeXyzCam(white_balance, pre_mul, cam_wb_matrix, preferred_illuminant, xyz_cam);
double mXYZCAM[3][3]; // Camera RGB to XYZ D50 matrix
MakeXYZCAM(wb, pre_mul, camWbMatrix, preferredIlluminant, mXYZCAM);
HSBModify *deleteTableHandle;
const HSBModify *deltaBase = MakeHueSatMap(wb, preferredIlluminant, &deleteTableHandle);
const std::vector<HSBModify> delta_base = makeHueSatMap(white_balance, preferred_illuminant);
if (!deltaBase) {
applyHueSatMap = false;
if (delta_base.empty()) {
apply_hue_sat_map = false;
}
if (!look_table) {
applyLookTable = false;
if (look_table.empty()) {
apply_look_table = false;
}
useToneCurve &= tone_curve;
use_tone_curve = use_tone_curve && tone_curve;
if (!applyHueSatMap && !applyLookTable && !useToneCurve) {
//===== The fast path: no LUT and not tone curve- Calculate matrix for direct conversion raw>working space
double mat[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
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] = {};
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
mat[i][j] += mWork[i][k] * mXYZCAM[k][j];
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
mat[i][j] += work_matrix[i][k] * xyz_cam[k][j];
}
}
}
// Apply the matrix part
#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);
const float& newg = mat[1][0] * img->r(y, x) + mat[1][1] * img->g(y, x) + mat[1][2] * img->b(y, x);
const float& newb = mat[2][0] * img->r(y, x) + mat[2][1] * img->g(y, x) + mat[2][2] * img->b(y, x);
for (int y = 0; y < pImg->height; y++) {
float newr, newg, newb;
for (int x = 0; x < pImg->width; x++) {
newr = mat[0][0] * pImg->r(y, x) + mat[0][1] * pImg->g(y, x) + mat[0][2] * pImg->b(y, x);
newg = mat[1][0] * pImg->r(y, x) + mat[1][1] * pImg->g(y, x) + mat[1][2] * pImg->b(y, x);
newb = mat[2][0] * pImg->r(y, x) + mat[2][1] * pImg->g(y, x) + mat[2][2] * pImg->b(y, x);
pImg->r(y, x) = newr;
pImg->g(y, x) = newg;
pImg->b(y, x) = newb;
img->r(y, x) = newr;
img->g(y, x) = newg;
img->b(y, x) = newb;
}
}
} else {
//===== LUT available- Calculate matrix for conversion raw>ProPhoto
double m2ProPhoto[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
// LUT available --> Calculate matrix for conversion raw>ProPhoto
double pro_photo[3][3] = {};
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
m2ProPhoto[i][j] += prophoto_xyz[i][k] * mXYZCAM[k][j];
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
pro_photo[i][j] += prophoto_xyz[i][k] * xyz_cam[k][j];
}
}
}
double m2Work[3][3] = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
double work[3][3] = {};
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
for (int k = 0; k < 3; k++) {
m2Work[i][j] += mWork[i][k] * xyz_prophoto[k][j];
for (int i = 0; i < 3; ++i) {
for (int j = 0; j < 3; ++j) {
for (int k = 0; k < 3; ++k) {
work[i][j] += work_matrix[i][k] * xyz_prophoto[k][j];
}
}
}
// Convert to prophoto and apply LUT
// Convert to ProPhoto and apply LUT
#ifdef _OPENMP
#pragma omp parallel for
#endif
for (int y = 0; y < img->height; ++y) {
float h, s, v, hs, ss, vs;
for (int y = 0; y < pImg->height; y++) {
float newr, newg, newb, h, s, v, hs, ss, vs;
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);
for (int x = 0; x < pImg->width; x++) {
newr = m2ProPhoto[0][0] * pImg->r(y, x) + m2ProPhoto[0][1] * pImg->g(y, x) + m2ProPhoto[0][2] * pImg->b(y, x);
newg = m2ProPhoto[1][0] * pImg->r(y, x) + m2ProPhoto[1][1] * pImg->g(y, x) + m2ProPhoto[1][2] * pImg->b(y, x);
newb = m2ProPhoto[2][0] * pImg->r(y, x) + m2ProPhoto[2][1] * pImg->g(y, x) + m2ProPhoto[2][2] * pImg->b(y, x);
// if point is in negative area, just the matrix, but not the LUT
if ((applyHueSatMap || applyLookTable) && newr >= 0 && newg >= 0 && newb >= 0) {
// 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.f; // RT calculates in [0,1]
h *= 6.0f; // RT calculates in [0,1]
if (applyHueSatMap) {
HSDApply(delta_info, deltaBase, h, s, v);
if (apply_hue_sat_map) {
hsdApply(delta_info, delta_base, h, s, v);
}
if (applyLookTable) {
HSDApply(look_info, look_table, h, s, v);
if (apply_look_table) {
hsdApply(look_info, look_table, h, s, v);
}
// RT range correction
@ -1017,24 +1041,20 @@ void DCPProfile::Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::us
}
h /= 6.f;
Color::hsv2rgb( h, s, v, newr, newg, newb);
Color::hsv2rgb(h, s, v, newr, newg, newb);
}
// tone curve
if (useToneCurve) {
if (use_tone_curve) {
tone_curve.Apply(newr, newg, newb);
}
pImg->r(y, x) = m2Work[0][0] * newr + m2Work[0][1] * newg + m2Work[0][2] * newb;
pImg->g(y, x) = m2Work[1][0] * newr + m2Work[1][1] * newg + m2Work[1][2] * newb;
pImg->b(y, x) = m2Work[2][0] * newr + m2Work[2][1] * newg + m2Work[2][2] * newb;
img->r(y, x) = work[0][0] * newr + work[0][1] * newg + work[0][2] * newb;
img->g(y, x) = work[1][0] * newr + work[1][1] * newg + work[1][2] * newb;
img->b(y, x) = work[2][0] * newr + work[2][1] * newg + work[2][2] * newb;
}
}
}
if (deleteTableHandle) {
delete[] deleteTableHandle;
}
}
void DCPProfile::setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut)
@ -1044,7 +1064,7 @@ void DCPProfile::setStep2ApplyState(const Glib::ustring &workingSpace, bool useT
asOut.applyLookTable = applyLookTable;
asOut.blScale = 1.0;
if (!look_table) {
if (look_table.empty()) {
asOut.applyLookTable = false;
}
@ -1138,7 +1158,7 @@ void DCPProfile::step2ApplyTile(float *rc, float *gc, float *bc, int width, int
Color::rgb2hsv(newr, newg, newb, h, s, v);
h *= 6.f; // RT calculates in [0,1]
HSDApply(look_info, look_table, h, s, v);
hsdApply(look_info, look_table, h, s, v);
s = CLIP01(s);
v = CLIP01(v);
@ -1351,7 +1371,7 @@ void DCPProfile::dngref_NeutralToXY(double neutral[3], int preferredIlluminant,
XY[1] = lastXY[1];
}
void DCPProfile::MakeXYZCAM(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const
void DCPProfile::makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const
{
// code adapted from dng_color_spec::FindXYZtoCamera
// note that we do not support monochrome or colorplanes > 3 (no reductionMatrix support)
@ -1551,53 +1571,52 @@ void DCPProfile::MakeXYZCAM(const ColorTemp &wb, double pre_mul[3], double camWb
}
}
const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(const ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const
std::vector<DCPProfile::HSBModify> DCPProfile::makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const
{
*deleteHandle = nullptr;
if (!deltas_1) {
return nullptr;
if (deltas_1.empty()) {
return std::vector<HSBModify>();
}
if (!deltas_2) {
if (deltas_2.empty()) {
return deltas_1;
}
if (preferredIlluminant == 1) {
if (preferred_illuminant == 1) {
return deltas_1;
} else if (preferredIlluminant == 2) {
} else if (preferred_illuminant == 2) {
return deltas_2;
}
// Interpolate based on color temperature.
if (temperature_1 <= 0.0 || temperature_2 <= 0.0 || temperature_1 == temperature_2) {
// Interpolate based on color temperature
if (
temperature_1 <= 0.0
|| temperature_2 <= 0.0
|| temperature_1 == temperature_2
) {
return deltas_1;
}
bool reverseOrder = temperature_1 > temperature_2;
double t1, t2;
if (reverseOrder) {
t1 = temperature_2;
t2 = temperature_1;
} else {
t1 = temperature_1;
t2 = temperature_2;
}
const bool reverse = temperature_1 > temperature_2;
const double t1 =
reverse
? temperature_2
: temperature_1;
const double t2 =
reverse
? temperature_1
: temperature_2;
double mix;
if (wb.getTemp() <= t1) {
if (white_balance.getTemp() <= t1) {
mix = 1.0;
} else if (wb.getTemp() >= t2) {
} else if (white_balance.getTemp() >= t2) {
mix = 0.0;
} else {
double invT = 1.0 / wb.getTemp();
const double invT = 1.0 / white_balance.getTemp();
mix = (invT - (1.0 / t2)) / ((1.0 / t1) - (1.0 / t2));
}
if (reverseOrder) {
if (reverse) {
mix = 1.0 - mix;
}
@ -1608,156 +1627,139 @@ const DCPProfile::HSBModify* DCPProfile::MakeHueSatMap(const ColorTemp &wb, int
}
// Interpolate between the tables.
HSBModify *aDeltas = new HSBModify[delta_info.array_count];
*deleteHandle = aDeltas;
float w1 = (float)mix;
float w2 = 1.0f - (float)mix;
std::vector<HSBModify> res(delta_info.array_count);
for (int i = 0; i < delta_info.array_count; i++) {
aDeltas[i].hue_shift = w1 * deltas_1[i].hue_shift + w2 * deltas_2[i].hue_shift;
aDeltas[i].sat_scale = w1 * deltas_1[i].sat_scale + w2 * deltas_2[i].sat_scale;
aDeltas[i].val_scale = w1 * deltas_1[i].val_scale + w2 * deltas_2[i].val_scale;
const float w1 = mix;
const float w2 = 1.0f - w1;
for (unsigned int i = 0; i < delta_info.array_count; ++i) {
res[i].hue_shift = w1 * deltas_1[i].hue_shift + w2 * deltas_2[i].hue_shift;
res[i].sat_scale = w1 * deltas_1[i].sat_scale + w2 * deltas_2[i].sat_scale;
res[i].val_scale = w1 * deltas_1[i].val_scale + w2 * deltas_2[i].val_scale;
}
return aDeltas;
return res;
}
void DCPProfile::HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const
void DCPProfile::hsdApply(const HSDTableInfo& table_info, const std::vector<HSBModify>& table_base, float& h, float& s, float& v) const
{
// Apply the HueSatMap. Ported from Adobes reference implementation.
float hue_shift;
float sat_scale;
float val_scale;
float v_encoded = v;
// Apply the HueSatMap. Ported from Adobes reference implementation
float hueShift, satScale, valScale;
float vEncoded = v;
if (table_info.val_divisions < 2) {
// Optimize most common case of "2.5D" table
const float h_scaled = h * table_info.pc.h_scale;
const float s_scaled = s * table_info.pc.s_scale;
if (ti.val_divisions < 2) { // Optimize most common case of "2.5D" table.
float hScaled = h * ti.pc.h_scale;
float sScaled = s * ti.pc.s_scale;
int h_index0 = max<int>(h_scaled, 0);
const int s_index0 = max(min<int>(s_scaled, table_info.pc.max_sat_index0), 0);
int hIndex0 = max((int)hScaled, 0);
int sIndex0 = max(min((int)sScaled, ti.pc.maxSatIndex0), 0);
int h_index1 = h_index0 + 1;
int hIndex1 = hIndex0 + 1;
if (hIndex0 >= ti.pc.maxHueIndex0) {
hIndex0 = ti.pc.maxHueIndex0;
hIndex1 = 0;
if (h_index0 >= table_info.pc.max_hue_index0) {
h_index0 = table_info.pc.max_hue_index0;
h_index1 = 0;
}
float hFract1 = hScaled - (float) hIndex0;
float sFract1 = sScaled - (float) sIndex0;
const float h_fract1 = h_scaled - static_cast<float>(h_index0);
const float s_fract1 = s_scaled - static_cast<float>(s_index0);
float hFract0 = 1.0f - hFract1;
float sFract0 = 1.0f - sFract1;
const float h_fract0 = 1.0f - h_fract1;
const float s_fract0 = 1.0f - s_fract1;
const HSBModify *entry00 = tableBase + hIndex0 * ti.pc.hueStep + sIndex0;
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep;
std::vector<HSBModify>::size_type e00_index = h_index0 * table_info.pc.hue_step + s_index0;
std::vector<HSBModify>::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step;
float hueShift0 = hFract0 * entry00->hue_shift + hFract1 * entry01->hue_shift;
float satScale0 = hFract0 * entry00->sat_scale + hFract1 * entry01->sat_scale;
float valScale0 = hFract0 * entry00->val_scale + hFract1 * entry01->val_scale;
const float hue_shift0 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift;
const float sat_scale0 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale;
const float val_scale0 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale;
entry00++;
entry01++;
++e00_index;
++e01_index;
float hueShift1 = hFract0 * entry00->hue_shift +
hFract1 * entry01->hue_shift;
float satScale1 = hFract0 * entry00->sat_scale +
hFract1 * entry01->sat_scale;
float valScale1 = hFract0 * entry00->val_scale +
hFract1 * entry01->val_scale;
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
satScale = sFract0 * satScale0 + sFract1 * satScale1;
valScale = sFract0 * valScale0 + sFract1 * valScale1;
const float hueShift1 = h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift;
const float satScale1 = h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale;
const float valScale1 = h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale;
hue_shift = s_fract0 * hue_shift0 + s_fract1 * hueShift1;
sat_scale = s_fract0 * sat_scale0 + s_fract1 * satScale1;
val_scale = s_fract0 * val_scale0 + s_fract1 * valScale1;
} else {
const float h_scaled = h * table_info.pc.h_scale;
const float s_scaled = s * table_info.pc.s_scale;
float hScaled = h * ti.pc.h_scale;
float sScaled = s * ti.pc.s_scale;
if (ti.srgb_gamma) {
vEncoded = sRGBGammaForward(v);
if (table_info.srgb_gamma) {
v_encoded = sRGBGammaForward(v);
}
float vScaled = vEncoded * ti.pc.v_scale;
const float v_scaled = v_encoded * table_info.pc.v_scale;
int hIndex0 = (int) hScaled;
int sIndex0 = max(min((int)sScaled, ti.pc.maxSatIndex0), 0);
int vIndex0 = max(min((int)vScaled, ti.pc.maxValIndex0), 0);
int h_index0 = (int) h_scaled;
const int s_index0 = max(min<int>(s_scaled, table_info.pc.max_sat_index0), 0);
const int v_index0 = max(min<int>(v_scaled, table_info.pc.max_val_index0), 0);
int hIndex1 = hIndex0 + 1;
int h_index1 = h_index0 + 1;
if (hIndex0 >= ti.pc.maxHueIndex0) {
hIndex0 = ti.pc.maxHueIndex0;
hIndex1 = 0;
if (h_index0 >= table_info.pc.max_hue_index0) {
h_index0 = table_info.pc.max_hue_index0;
h_index1 = 0;
}
float hFract1 = hScaled - (float) hIndex0;
float sFract1 = sScaled - (float) sIndex0;
float vFract1 = vScaled - (float) vIndex0;
const float h_fract1 = h_scaled - static_cast<float>(h_index0);
const float s_fract1 = s_scaled - static_cast<float>(s_index0);
const float v_fract1 = v_scaled - static_cast<float>(v_index0);
float hFract0 = 1.0f - hFract1;
float sFract0 = 1.0f - sFract1;
float vFract0 = 1.0f - vFract1;
const float h_fract0 = 1.0f - h_fract1;
const float s_fract0 = 1.0f - s_fract1;
const float v_fract0 = 1.0f - v_fract1;
const HSBModify *entry00 = tableBase + vIndex0 * ti.pc.valStep + hIndex0 * ti.pc.hueStep + sIndex0;
std::vector<HSBModify>::size_type e00_index = v_index0 * table_info.pc.val_step + h_index0 * table_info.pc.hue_step + s_index0;
std::vector<HSBModify>::size_type e01_index = e00_index + (h_index1 - h_index0) * table_info.pc.hue_step;
std::vector<HSBModify>::size_type e10_index = e00_index + table_info.pc.val_step;
std::vector<HSBModify>::size_type e11_index = e01_index + table_info.pc.val_step;
const HSBModify *entry01 = entry00 + (hIndex1 - hIndex0) * ti.pc.hueStep;
const float hueShift0 =
v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift)
+ v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift);
const float satScale0 =
v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale)
+ v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale);
const float valScale0 =
v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale)
+ v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale);
const HSBModify *entry10 = entry00 + ti.pc.valStep;
const HSBModify *entry11 = entry01 + ti.pc.valStep;
++e00_index;
++e01_index;
++e10_index;
++e11_index;
float hueShift0 = vFract0 * (hFract0 * entry00->hue_shift +
hFract1 * entry01->hue_shift) +
vFract1 * (hFract0 * entry10->hue_shift +
hFract1 * entry11->hue_shift);
const float hueShift1 =
v_fract0 * (h_fract0 * table_base[e00_index].hue_shift + h_fract1 * table_base[e01_index].hue_shift)
+ v_fract1 * (h_fract0 * table_base[e10_index].hue_shift + h_fract1 * table_base[e11_index].hue_shift);
const float satScale1 =
v_fract0 * (h_fract0 * table_base[e00_index].sat_scale + h_fract1 * table_base[e01_index].sat_scale)
+ v_fract1 * (h_fract0 * table_base[e10_index].sat_scale + h_fract1 * table_base[e11_index].sat_scale);
const float valScale1 =
v_fract0 * (h_fract0 * table_base[e00_index].val_scale + h_fract1 * table_base[e01_index].val_scale)
+ v_fract1 * (h_fract0 * table_base[e10_index].val_scale + h_fract1 * table_base[e11_index].val_scale);
float satScale0 = vFract0 * (hFract0 * entry00->sat_scale +
hFract1 * entry01->sat_scale) +
vFract1 * (hFract0 * entry10->sat_scale +
hFract1 * entry11->sat_scale);
float valScale0 = vFract0 * (hFract0 * entry00->val_scale +
hFract1 * entry01->val_scale) +
vFract1 * (hFract0 * entry10->val_scale +
hFract1 * entry11->val_scale);
entry00++;
entry01++;
entry10++;
entry11++;
float hueShift1 = vFract0 * (hFract0 * entry00->hue_shift +
hFract1 * entry01->hue_shift) +
vFract1 * (hFract0 * entry10->hue_shift +
hFract1 * entry11->hue_shift);
float satScale1 = vFract0 * (hFract0 * entry00->sat_scale +
hFract1 * entry01->sat_scale) +
vFract1 * (hFract0 * entry10->sat_scale +
hFract1 * entry11->sat_scale);
float valScale1 = vFract0 * (hFract0 * entry00->val_scale +
hFract1 * entry01->val_scale) +
vFract1 * (hFract0 * entry10->val_scale +
hFract1 * entry11->val_scale);
hueShift = sFract0 * hueShift0 + sFract1 * hueShift1;
satScale = sFract0 * satScale0 + sFract1 * satScale1;
valScale = sFract0 * valScale0 + sFract1 * valScale1;
hue_shift = s_fract0 * hueShift0 + s_fract1 * hueShift1;
sat_scale = s_fract0 * satScale0 + s_fract1 * satScale1;
val_scale = s_fract0 * valScale0 + s_fract1 * valScale1;
}
hueShift *= (6.0f / 360.0f); // Convert to internal hue range.
hue_shift *= 6.0f / 360.0f; // Convert to internal hue range.
h += hueShift;
s *= satScale; // no clipping here, we are RT float :-)
h += hue_shift;
s *= sat_scale; // No clipping here, we are RT float :-)
if (ti.srgb_gamma) {
v = sRGBGammaInverse(vEncoded * valScale);
if (table_info.srgb_gamma) {
v = sRGBGammaInverse(v_encoded * val_scale);
} else {
v *= valScale;
v *= val_scale;
}
}

View File

@ -20,6 +20,7 @@
#pragma once
#include <map>
#include <vector>
#include <glibmm.h>
@ -44,6 +45,14 @@ public:
float blScale;
};
struct Illuminants {
short light_source_1;
short light_source_2;
double temperature_1;
double temperature_2;
bool will_interpolate;
};
DCPProfile(const Glib::ustring& filename);
~DCPProfile();
@ -52,9 +61,19 @@ public:
bool getHasHueSatMap() const;
bool getHasBaselineExposureOffset() const;
void getIlluminants(int &i1, double &temp1, int &i2, double &temp2, bool &willInterpolate_) const;
Illuminants getIlluminants() const;
void Apply(Imagefloat *pImg, int preferredIlluminant, const Glib::ustring &workingSpace, const ColorTemp &wb, double pre_mul[3], double camMatrix[3][3], bool useToneCurve = false, bool applyHueSatMap = true, bool applyLookTable = false) const;
void apply(
Imagefloat* img,
int preferred_illuminant,
const Glib::ustring& working_space,
const ColorTemp& white_balance,
double pre_mul[3],
double cam_matrix[3][3],
bool use_tone_curve = false,
bool apply_hue_sat_map = true,
bool apply_look_table = false
) const;
void setStep2ApplyState(const Glib::ustring &workingSpace, bool useToneCurve, bool applyLookTable, bool applyBaselineExposure, ApplyState &asOut);
void step2ApplyTile(float *r, float *g, float *b, int width, int height, int tileWidth, const ApplyState &asIn) const;
@ -69,28 +88,28 @@ private:
int hue_divisions;
int sat_divisions;
int val_divisions;
int iHueStep;
int iValStep;
int array_count;
int hue_step;
int val_step;
unsigned int array_count;
bool srgb_gamma;
struct {
float h_scale;
float s_scale;
float v_scale;
int maxHueIndex0;
int maxSatIndex0;
int maxValIndex0;
int hueStep;
int valStep;
int max_hue_index0;
int max_sat_index0;
int max_val_index0;
int hue_step;
int val_step;
} pc;
};
void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const;
void dngref_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const;
void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) const;
void MakeXYZCAM(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) const;
const HSBModify* MakeHueSatMap(const ColorTemp &wb, int preferredIlluminant, HSBModify **deleteHandle) const;
void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) const;
void makeXyzCam(const ColorTemp &wb, double pre_mul[3], double camWbMatrix[3][3], int preferredIlluminant, double (*mXYZCAM)[3]) 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;
double color_matrix_1[3][3];
double color_matrix_2[3][3];
@ -106,9 +125,9 @@ private:
double temperature_1;
double temperature_2;
double baseline_exposure_offset;
HSBModify* deltas_1;
HSBModify* deltas_2;
HSBModify* look_table;
std::vector<HSBModify> deltas_1;
std::vector<HSBModify> deltas_2;
std::vector<HSBModify> look_table;
HSDTableInfo delta_info;
HSDTableInfo look_info;
short light_source_1;

View File

@ -3727,7 +3727,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam
if (dcpProf != NULL) {
// DCP processing
dcpProf->Apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false);
dcpProf->apply(im, cmp.dcpIlluminant, cmp.working, wb, pre_mul, camMatrix, false, cmp.applyHueSatMap, false);
return;
}

View File

@ -385,24 +385,21 @@ void ICMPanel::updateDCP (int dcpIlluminant, Glib::ustring dcp_name)
ckbApplyHueSatMap->set_sensitive (true);
}
int i1, i2;
double temp1, temp2;
bool willInterpolate;
dcp->getIlluminants(i1, temp1, i2, temp2, willInterpolate);
const DCPProfile::Illuminants illuminants = dcp->getIlluminants();
if (willInterpolate) {
if (dcpTemperatures[0] != temp1 || dcpTemperatures[1] != temp2) {
if (illuminants.will_interpolate) {
if (dcpTemperatures[0] != illuminants.temperature_1 || dcpTemperatures[1] != illuminants.temperature_2) {
char tempstr1[64], tempstr2[64];
sprintf(tempstr1, "%.0fK", temp1);
sprintf(tempstr2, "%.0fK", temp2);
sprintf(tempstr1, "%.0fK", illuminants.temperature_1);
sprintf(tempstr2, "%.0fK", illuminants.temperature_2);
int curr_active = dcpIll->get_active_row_number();
ignoreDcpSignal = true;
dcpIll->clear_items ();
dcpIll->append_text (M("TP_ICM_DCPILLUMINANT_INTERPOLATED"));
dcpIll->append_text (tempstr1);
dcpIll->append_text (tempstr2);
dcpTemperatures[0] = temp1;
dcpTemperatures[1] = temp2;
dcpTemperatures[0] = illuminants.temperature_1;
dcpTemperatures[1] = illuminants.temperature_2;
dcpIll->set_active (curr_active);
ignoreDcpSignal = false;
}