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

View File

@ -20,6 +20,7 @@
#pragma once #pragma once
#include <map> #include <map>
#include <vector>
#include <glibmm.h> #include <glibmm.h>
@ -44,6 +45,14 @@ public:
float blScale; 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(const Glib::ustring& filename);
~DCPProfile(); ~DCPProfile();
@ -52,9 +61,19 @@ public:
bool getHasHueSatMap() const; bool getHasHueSatMap() const;
bool getHasBaselineExposureOffset() 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 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; 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 hue_divisions;
int sat_divisions; int sat_divisions;
int val_divisions; int val_divisions;
int iHueStep; int hue_step;
int iValStep; int val_step;
int array_count; unsigned int array_count;
bool srgb_gamma; bool srgb_gamma;
struct { struct {
float h_scale; float h_scale;
float s_scale; float s_scale;
float v_scale; float v_scale;
int maxHueIndex0; int max_hue_index0;
int maxSatIndex0; int max_sat_index0;
int maxValIndex0; int max_val_index0;
int hueStep; int hue_step;
int valStep; int val_step;
} pc; } pc;
}; };
void dngref_XYCoord2Temperature(const double whiteXY[2], double *temp, double *tint) const; 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_FindXYZtoCamera(const double whiteXY[2], int preferredIlluminant, double (*xyzToCamera)[3]) const;
void dngref_NeutralToXY(double neutral[3], int preferredIlluminant, double XY[2]) 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; 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; std::vector<HSBModify> makeHueSatMap(const ColorTemp& white_balance, int preferred_illuminant) const;
void HSDApply(const HSDTableInfo &ti, const HSBModify *tableBase, float &h, float &s, float &v) 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_1[3][3];
double color_matrix_2[3][3]; double color_matrix_2[3][3];
@ -106,9 +125,9 @@ private:
double temperature_1; double temperature_1;
double temperature_2; double temperature_2;
double baseline_exposure_offset; double baseline_exposure_offset;
HSBModify* deltas_1; std::vector<HSBModify> deltas_1;
HSBModify* deltas_2; std::vector<HSBModify> deltas_2;
HSBModify* look_table; std::vector<HSBModify> look_table;
HSDTableInfo delta_info; HSDTableInfo delta_info;
HSDTableInfo look_info; HSDTableInfo look_info;
short light_source_1; short light_source_1;

View File

@ -3727,7 +3727,7 @@ void RawImageSource::colorSpaceConversion_ (Imagefloat* im, ColorManagementParam
if (dcpProf != NULL) { if (dcpProf != NULL) {
// DCP processing // 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; return;
} }

View File

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