Filmenegative core cleanup
This commit is contained in:
parent
80f2b6a002
commit
54cc02eea9
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RawTherapee.
|
* This file is part of RawTherapee.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
* Copyright (c) 2019 rom9
|
||||||
*
|
*
|
||||||
* RawTherapee is free software: you can redistribute it and/or modify
|
* RawTherapee is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -19,15 +19,17 @@
|
|||||||
#include <cmath>
|
#include <cmath>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
#include "rtengine.h"
|
|
||||||
#include "rawimagesource.h"
|
|
||||||
#include "mytime.h"
|
|
||||||
#include "procparams.h"
|
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
#include <omp.h>
|
#include <omp.h>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#include "rawimagesource.h"
|
||||||
|
|
||||||
|
#include "mytime.h"
|
||||||
#include "opthelper.h"
|
#include "opthelper.h"
|
||||||
|
#include "procparams.h"
|
||||||
#include "rt_algo.h"
|
#include "rt_algo.h"
|
||||||
|
#include "rtengine.h"
|
||||||
|
|
||||||
//#define BENCHMARK
|
//#define BENCHMARK
|
||||||
#include "StopWatch.h"
|
#include "StopWatch.h"
|
||||||
@ -37,168 +39,221 @@ namespace rtengine
|
|||||||
|
|
||||||
extern const Settings* settings;
|
extern const Settings* settings;
|
||||||
|
|
||||||
bool RawImageSource::channelsAvg(Coord spotPos, int spotSize, float avgs[3], const FilmNegativeParams ¶ms)
|
}
|
||||||
|
|
||||||
|
namespace
|
||||||
{
|
{
|
||||||
avgs[0] = avgs[1] = avgs[2] = 0.f; // Channel averages
|
|
||||||
|
|
||||||
if(ri->getSensorType() != ST_BAYER && ri->getSensorType() != ST_FUJI_XTRANS)
|
bool channelsAvg(
|
||||||
|
const rtengine::RawImage* ri,
|
||||||
|
int width,
|
||||||
|
int height,
|
||||||
|
array2D<float>& rawData,
|
||||||
|
rtengine::Coord spotPos,
|
||||||
|
int spotSize,
|
||||||
|
const rtengine::procparams::FilmNegativeParams& params,
|
||||||
|
std::array<float, 3>& avgs
|
||||||
|
)
|
||||||
|
{
|
||||||
|
avgs = {}; // Channel averages
|
||||||
|
|
||||||
|
if (ri->getSensorType() != rtengine::ST_BAYER && ri->getSensorType() != rtengine::ST_FUJI_XTRANS) {
|
||||||
return false;
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
if (settings->verbose)
|
if (rtengine::settings->verbose) {
|
||||||
printf("Spot coord: x=%d y=%d\n", spotPos.x, spotPos.y);
|
printf("Spot coord: x=%d y=%d\n", spotPos.x, spotPos.y);
|
||||||
|
}
|
||||||
|
|
||||||
int x1 = spotPos.x - spotSize / 2;
|
const int half_spot_size = spotSize / 2;
|
||||||
int x2 = spotPos.x + spotSize / 2;
|
|
||||||
int y1 = spotPos.y - spotSize / 2;
|
|
||||||
int y2 = spotPos.y + spotSize / 2;
|
|
||||||
|
|
||||||
if(x1<0 || x2>W || y1<0 || y2>H)
|
const int& x1 = spotPos.x - half_spot_size;
|
||||||
|
const int& x2 = spotPos.x + half_spot_size;
|
||||||
|
const int& y1 = spotPos.y - half_spot_size;
|
||||||
|
const int& y2 = spotPos.y + half_spot_size;
|
||||||
|
|
||||||
|
if (x1 < 0 || x2 > width || y1 < 0 || y2 > height) {
|
||||||
return false; // Spot goes outside bounds, bail out.
|
return false; // Spot goes outside bounds, bail out.
|
||||||
|
}
|
||||||
|
|
||||||
int pxCount[3] = {0}; // Per-channel sample counts
|
std::array<int, 3> pxCount = {}; // Per-channel sample counts
|
||||||
for(int c=spotPos.x-spotSize; c<spotPos.x+spotSize; c++) {
|
for (int c = spotPos.x - spotSize; c < spotPos.x + spotSize; ++c) {
|
||||||
for(int r=spotPos.y-spotSize; r<spotPos.y+spotSize; r++) {
|
for (int r = spotPos.y - spotSize; r < spotPos.y + spotSize; ++r) {
|
||||||
|
const int ch = ri->getSensorType() == rtengine::ST_BAYER ? ri->FC(r,c) : ri->XTRANSFC(r,c);
|
||||||
|
|
||||||
int ch = (ri->getSensorType() == ST_BAYER) ? FC(r,c) : ri->XTRANSFC(r,c);
|
++pxCount[ch];
|
||||||
|
|
||||||
pxCount[ch]++;
|
|
||||||
// If film negative is currently enabled, undo the effect by elevating to 1/exp,
|
// If film negative is currently enabled, undo the effect by elevating to 1/exp,
|
||||||
// in order to sample the original, linear value
|
// in order to sample the original, linear value
|
||||||
if(params.enabled)
|
if (params.enabled) {
|
||||||
avgs[ch] += powf(rawData[r][c], -1 / (ch==0 ? params.redExp : ch==1 ? params.greenExp : params.blueExp));
|
avgs[ch] += powf(rawData[r][c], -1.f / (ch == 0 ? params.redExp : ch == 1 ? params.greenExp : params.blueExp));
|
||||||
else
|
} else {
|
||||||
avgs[ch] += rawData[r][c];
|
avgs[ch] += rawData[r][c];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for(int ch=0; ch<3; ch++)
|
for (int ch = 0; ch < 3; ++ch) {
|
||||||
avgs[ch] = avgs[ch] / (pxCount[ch]);
|
avgs[ch] /= pxCount[ch];
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Calculate logarithms in arbitrary base
|
|
||||||
float logBase(float base, float num) {
|
|
||||||
return log(num) / log(base);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
bool RawImageSource::getFilmNegativeExponents(Coord2D spotA, Coord2D spotB, int tran, const FilmNegativeParams ¤tParams, std::array<float, 3>& newExps)
|
bool rtengine::RawImageSource::getFilmNegativeExponents(Coord2D spotA, Coord2D spotB, int tran, const FilmNegativeParams ¤tParams, std::array<float, 3>& newExps)
|
||||||
{
|
{
|
||||||
float clearVals[3], denseVals[3];
|
newExps = {
|
||||||
|
static_cast<float>(currentParams.redExp),
|
||||||
|
static_cast<float>(currentParams.greenExp),
|
||||||
|
static_cast<float>(currentParams.blueExp)
|
||||||
|
};
|
||||||
|
|
||||||
newExps[0] = currentParams.redExp;
|
constexpr int spotSize = 32; // TODO: Make this configurable?
|
||||||
newExps[1] = currentParams.greenExp;
|
|
||||||
newExps[2] = currentParams.blueExp;
|
|
||||||
|
|
||||||
int spotSize = 32; // TODO : make this confugurable ?
|
|
||||||
Coord spot;
|
Coord spot;
|
||||||
|
std::array<float, 3> clearVals;
|
||||||
|
std::array<float, 3> denseVals;
|
||||||
|
|
||||||
// Sample first spot
|
// Sample first spot
|
||||||
transformPosition (spotA.x, spotA.y, tran, spot.x, spot.y);
|
transformPosition(spotA.x, spotA.y, tran, spot.x, spot.y);
|
||||||
if(!channelsAvg(spot, spotSize, clearVals, currentParams))
|
if (!channelsAvg(ri, W, H, rawData, spot, spotSize, currentParams, clearVals)) {
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
// Sample second spot
|
|
||||||
transformPosition (spotB.x, spotB.y, tran, spot.x, spot.y);
|
|
||||||
if(!channelsAvg(spot, spotSize, denseVals, currentParams))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
// Detect which one is the dense spot, based on green channel
|
|
||||||
if(clearVals[1] < denseVals[1])
|
|
||||||
std::swap(clearVals, denseVals);
|
|
||||||
|
|
||||||
if (settings->verbose) {
|
|
||||||
printf("Clear film values: R=%g G=%g B=%g\n", clearVals[0], clearVals[1], clearVals[2]);
|
|
||||||
printf("Dense film values: R=%g G=%g B=%g\n", denseVals[0], denseVals[1], denseVals[2]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
float denseGreenRatio = clearVals[1] / denseVals[1];
|
// Sample second spot
|
||||||
|
transformPosition(spotB.x, spotB.y, tran, spot.x, spot.y);
|
||||||
|
if (!channelsAvg(ri, W, H, rawData, spot, spotSize, currentParams, denseVals)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Detect which one is the dense spot, based on green channel
|
||||||
|
if (clearVals[1] < denseVals[1]) {
|
||||||
|
std::swap(clearVals, denseVals);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (settings->verbose) {
|
||||||
|
printf("Clear film values: R=%g G=%g B=%g\n", clearVals[0], clearVals[1], clearVals[2]);
|
||||||
|
printf("Dense film values: R=%g G=%g B=%g\n", denseVals[0], denseVals[1], denseVals[2]);
|
||||||
|
}
|
||||||
|
|
||||||
|
const float denseGreenRatio = clearVals[1] / denseVals[1];
|
||||||
|
|
||||||
|
// Calculate logarithms in arbitrary base
|
||||||
|
const auto logBase =
|
||||||
|
[](float base, float num) -> float
|
||||||
|
{
|
||||||
|
return std::log(num) / std::log(base);
|
||||||
|
};
|
||||||
|
|
||||||
// Calculate exponents for each channel, based on the ratio between the bright and dark values,
|
// Calculate exponents for each channel, based on the ratio between the bright and dark values,
|
||||||
// compared to the ratio in the reference channel (green)
|
// compared to the ratio in the reference channel (green)
|
||||||
for(int ch=0; ch<3; ch++)
|
for (int ch = 0; ch < 3; ++ch) {
|
||||||
if(ch==1)
|
if (ch == 1) {
|
||||||
newExps[ch] = 2.f; // Green is the reference channel
|
newExps[ch] = 2.f; // Green is the reference channel
|
||||||
else
|
} else {
|
||||||
newExps[ch] = CLAMP(2.f * logBase(clearVals[ch] / denseVals[ch], denseGreenRatio), 0.3f, 6.f);
|
newExps[ch] = CLAMP(2.f * logBase(clearVals[ch] / denseVals[ch], denseGreenRatio), 0.3f, 6.f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (settings->verbose)
|
if (settings->verbose) {
|
||||||
printf("New exponents: R=%g G=%g B=%g\n", newExps[0], newExps[1], newExps[2]);
|
printf("New exponents: R=%g G=%g B=%g\n", newExps[0], newExps[1], newExps[2]);
|
||||||
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams ¶ms)
|
void rtengine::RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams ¶ms)
|
||||||
{
|
{
|
||||||
// BENCHFUNMICRO
|
// BENCHFUNMICRO
|
||||||
|
|
||||||
if(!params.enabled)
|
if (!params.enabled) {
|
||||||
return;
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
float exps[3] = { (float)params.redExp, (float)params.greenExp, (float)params.blueExp };
|
const std::array<float, 3> exps = {
|
||||||
|
static_cast<float>(params.redExp),
|
||||||
|
static_cast<float>(params.greenExp),
|
||||||
|
static_cast<float>(params.blueExp)
|
||||||
|
};
|
||||||
|
|
||||||
MyTime t1, t2, t3,t4, t5, t6;
|
MyTime t1, t2, t3,t4, t5;
|
||||||
|
|
||||||
t1.set();
|
t1.set();
|
||||||
|
|
||||||
// Channel vectors to calculate medians
|
// Channel vectors to calculate medians
|
||||||
std::vector<float> cvs[3] = {
|
std::array<std::vector<float>, 3> cvs;
|
||||||
std::vector<float>(),
|
|
||||||
std::vector<float>(),
|
|
||||||
std::vector<float>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Sample one every 5 pixels, and push the value in the appropriate channel vector.
|
// Sample one every 5 pixels, and push the value in the appropriate channel vector.
|
||||||
// Chose an odd step, not multiple of the CFA size, to get a chance to visit each channel.
|
// Choose an odd step, not a multiple of the CFA size, to get a chance to visit each channel.
|
||||||
if(ri->getSensorType() == ST_BAYER) {
|
if (ri->getSensorType() == ST_BAYER) {
|
||||||
for (int row = 0; row < H; row+=5) {
|
for (int row = 0; row < H; row += 5) {
|
||||||
for (int col = 0; col < W; col+=5) {
|
for (int col = 0; col < W; col += 5) {
|
||||||
int c = FC(row, col); // three colors, 0=R, 1=G, 2=B
|
const int c = FC(row, col); // three colors: 0=R, 1=G, 2=B
|
||||||
cvs[c].push_back(rawData[row][col]);
|
cvs[c].push_back(rawData[row][col]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
|
}
|
||||||
for (int row = 0; row < H; row+=5) {
|
else if (ri->getSensorType() == ST_FUJI_XTRANS) {
|
||||||
for (int col = 0; col < W; col+=5) {
|
for (int row = 0; row < H; row += 5) {
|
||||||
int c = ri->XTRANSFC(row, col); // three colors, 0=R, 1=G, 2=B
|
for (int col = 0; col < W; col += 5) {
|
||||||
|
const int c = ri->XTRANSFC(row, col); // three colors: 0=R, 1=G, 2=B
|
||||||
cvs[c].push_back(rawData[row][col]);
|
cvs[c].push_back(rawData[row][col]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const float MAX_OUT_VALUE = 65000.f;
|
constexpr float MAX_OUT_VALUE = 65000.f;
|
||||||
|
|
||||||
t2.set();
|
t2.set();
|
||||||
if (settings->verbose)
|
|
||||||
|
if (settings->verbose) {
|
||||||
printf("Median vector fill loop time us: %d\n", t2.etime(t1));
|
printf("Median vector fill loop time us: %d\n", t2.etime(t1));
|
||||||
|
}
|
||||||
|
|
||||||
float medians[3]; // Channel median values
|
t2.set();
|
||||||
float mults[3] = { 1.f }; // Channel normalization multipliers
|
|
||||||
|
|
||||||
for (int c=0; c<3; c++) {
|
std::array<float, 3> medians; // Channel median values
|
||||||
|
std::array<float, 3> mults = {
|
||||||
|
1.f,
|
||||||
|
1.f,
|
||||||
|
1.f
|
||||||
|
}; // Channel normalization multipliers
|
||||||
|
|
||||||
|
for (int c = 0; c < 3; ++c) {
|
||||||
// Find median values for each channel
|
// Find median values for each channel
|
||||||
if(cvs[c].size() > 0) {
|
if (!cvs[c].empty()) {
|
||||||
findMinMaxPercentile(&cvs[c][0], cvs[c].size(), 0.5f, medians[c], 0.5f, medians[c], true);
|
findMinMaxPercentile(cvs[c].data(), cvs[c].size(), 0.5f, medians[c], 0.5f, medians[c], true);
|
||||||
medians[c] = pow_F(max(medians[c], 1.f), -exps[c]);
|
medians[c] = pow_F(rtengine::max(medians[c], 1.f), -exps[c]);
|
||||||
// Determine the channel multipler so that N times the median becomes 65k. This clips away
|
// Determine the channel multipler so that N times the median becomes 65k. This clips away
|
||||||
// the values in the dark border surrounding the negative (due to the film holder, for example),
|
// the values in the dark border surrounding the negative (due to the film holder, for example),
|
||||||
// the reciprocal of which have blown up to stellar values.
|
// the reciprocal of which have blown up to stellar values.
|
||||||
mults[c] = MAX_OUT_VALUE / (medians[c] * 24);
|
mults[c] = MAX_OUT_VALUE / (medians[c] * 24.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
t3.set();
|
t3.set();
|
||||||
|
|
||||||
if (settings->verbose) {
|
if (settings->verbose) {
|
||||||
printf("Sample count : %lu, %lu, %lu\n", cvs[0].size(), cvs[1].size(), cvs[2].size());
|
printf("Sample count: %zu, %zu, %zu\n", cvs[0].size(), cvs[1].size(), cvs[2].size());
|
||||||
printf("Medians : %g %g %g\n", medians[0], medians[1], medians[2] );
|
printf("Medians: %g %g %g\n", medians[0], medians[1], medians[2] );
|
||||||
printf("Computed multipliers : %g %g %g\n", mults[0], mults[1], mults[2] );
|
printf("Computed multipliers: %g %g %g\n", mults[0], mults[1], mults[2] );
|
||||||
printf("Median calc time us: %d\n", t3.etime(t2));
|
printf("Median calc time us: %d\n", t3.etime(t2));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t3.set();
|
||||||
|
|
||||||
|
if (ri->getSensorType() == ST_BAYER) {
|
||||||
|
#ifdef __SSE2__
|
||||||
|
const vfloat onev = F2V(1.f);
|
||||||
|
const vfloat c65535v = F2V(65535.f);
|
||||||
|
#endif
|
||||||
|
|
||||||
if(ri->getSensorType() == ST_BAYER) {
|
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for schedule(dynamic, 16)
|
#pragma omp parallel for schedule(dynamic, 16)
|
||||||
#endif
|
#endif
|
||||||
for (int row = 0; row < H; row ++) {
|
for (int row = 0; row < H; ++row) {
|
||||||
int col = 0;
|
int col = 0;
|
||||||
// Exponents are expressed as positive in the parameters, so negate them in order
|
// Exponents are expressed as positive in the parameters, so negate them in order
|
||||||
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
|
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
|
||||||
@ -209,21 +264,24 @@ void RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams &p
|
|||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
const vfloat expsv = _mm_setr_ps(exps0, exps1, exps0, exps1);
|
const vfloat expsv = _mm_setr_ps(exps0, exps1, exps0, exps1);
|
||||||
const vfloat multsv = _mm_setr_ps(mult0, mult1, mult0, mult1);
|
const vfloat multsv = _mm_setr_ps(mult0, mult1, mult0, mult1);
|
||||||
const vfloat onev = F2V(1.f);
|
for (; col < W - 3; col += 4) {
|
||||||
const vfloat c65535v = F2V(65535.f);
|
|
||||||
for (; col < W - 3; col+=4) {
|
|
||||||
STVFU(rawData[row][col], vminf(multsv * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv), c65535v));
|
STVFU(rawData[row][col], vminf(multsv * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv), c65535v));
|
||||||
}
|
}
|
||||||
#endif // __SSE2__
|
#endif // __SSE2__
|
||||||
for (; col < W - 1; col+=2) {
|
for (; col < W - 1; col += 2) {
|
||||||
rawData[row][col] = rtengine::min(mult0 * pow_F(max(rawData[row][col], 1.f), exps0), 65535.f);
|
rawData[row][col] = rtengine::min(mult0 * pow_F(rtengine::max(rawData[row][col], 1.f), exps0), 65535.f);
|
||||||
rawData[row][col + 1] = rtengine::min(mult1 * pow_F(max(rawData[row][col + 1], 1.f), exps1), 65535.f);
|
rawData[row][col + 1] = rtengine::min(mult1 * pow_F(rtengine::max(rawData[row][col + 1], 1.f), exps1), 65535.f);
|
||||||
}
|
}
|
||||||
if (col < W) {
|
if (col < W) {
|
||||||
rawData[row][col] = rtengine::min(mult0 * pow_F(max(rawData[row][col], 1.f), exps0), 65535.f);
|
rawData[row][col] = rtengine::min(mult0 * pow_F(rtengine::max(rawData[row][col], 1.f), exps0), 65535.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
|
} else if (ri->getSensorType() == ST_FUJI_XTRANS) {
|
||||||
|
#ifdef __SSE2__
|
||||||
|
const vfloat onev = F2V(1.f);
|
||||||
|
const vfloat c65535v = F2V(65535.f);
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for schedule(dynamic, 16)
|
#pragma omp parallel for schedule(dynamic, 16)
|
||||||
#endif
|
#endif
|
||||||
@ -231,8 +289,22 @@ void RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams &p
|
|||||||
int col = 0;
|
int col = 0;
|
||||||
// Exponents are expressed as positive in the parameters, so negate them in order
|
// Exponents are expressed as positive in the parameters, so negate them in order
|
||||||
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
|
// to get the reciprocals. Avoid trouble with zeroes, minimum pixel value is 1.
|
||||||
const float expsc[6] = {-exps[ri->XTRANSFC(row, 0)], -exps[ri->XTRANSFC(row, 1)], -exps[ri->XTRANSFC(row, 2)], -exps[ri->XTRANSFC(row, 3)], -exps[ri->XTRANSFC(row, 4)], -exps[ri->XTRANSFC(row, 5)]};
|
const std::array<float, 6> expsc = {
|
||||||
const float multsc[6] = {mults[ri->XTRANSFC(row, 0)], mults[ri->XTRANSFC(row, 1)], mults[ri->XTRANSFC(row, 2)], mults[ri->XTRANSFC(row, 3)], mults[ri->XTRANSFC(row, 4)], mults[ri->XTRANSFC(row, 5)]};
|
-exps[ri->XTRANSFC(row, 0)],
|
||||||
|
-exps[ri->XTRANSFC(row, 1)],
|
||||||
|
-exps[ri->XTRANSFC(row, 2)],
|
||||||
|
-exps[ri->XTRANSFC(row, 3)],
|
||||||
|
-exps[ri->XTRANSFC(row, 4)],
|
||||||
|
-exps[ri->XTRANSFC(row, 5)]
|
||||||
|
};
|
||||||
|
const std::array<float, 6> multsc = {
|
||||||
|
mults[ri->XTRANSFC(row, 0)],
|
||||||
|
mults[ri->XTRANSFC(row, 1)],
|
||||||
|
mults[ri->XTRANSFC(row, 2)],
|
||||||
|
mults[ri->XTRANSFC(row, 3)],
|
||||||
|
mults[ri->XTRANSFC(row, 4)],
|
||||||
|
mults[ri->XTRANSFC(row, 5)]
|
||||||
|
};
|
||||||
#ifdef __SSE2__
|
#ifdef __SSE2__
|
||||||
const vfloat expsv0 = _mm_setr_ps(expsc[0], expsc[1], expsc[2], expsc[3]);
|
const vfloat expsv0 = _mm_setr_ps(expsc[0], expsc[1], expsc[2], expsc[3]);
|
||||||
const vfloat expsv1 = _mm_setr_ps(expsc[4], expsc[5], expsc[0], expsc[1]);
|
const vfloat expsv1 = _mm_setr_ps(expsc[4], expsc[5], expsc[0], expsc[1]);
|
||||||
@ -240,81 +312,75 @@ void RawImageSource::filmNegativeProcess(const procparams::FilmNegativeParams &p
|
|||||||
const vfloat multsv0 = _mm_setr_ps(multsc[0], multsc[1], multsc[2], multsc[3]);
|
const vfloat multsv0 = _mm_setr_ps(multsc[0], multsc[1], multsc[2], multsc[3]);
|
||||||
const vfloat multsv1 = _mm_setr_ps(multsc[4], multsc[5], multsc[0], multsc[1]);
|
const vfloat multsv1 = _mm_setr_ps(multsc[4], multsc[5], multsc[0], multsc[1]);
|
||||||
const vfloat multsv2 = _mm_setr_ps(multsc[2], multsc[3], multsc[4], multsc[5]);
|
const vfloat multsv2 = _mm_setr_ps(multsc[2], multsc[3], multsc[4], multsc[5]);
|
||||||
const vfloat onev = F2V(1.f);
|
for (; col < W - 11; col += 12) {
|
||||||
const vfloat c65535v = F2V(65535.f);
|
|
||||||
for (; col < W - 11; col+=12) {
|
|
||||||
STVFU(rawData[row][col], vminf(multsv0 * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv0), c65535v));
|
STVFU(rawData[row][col], vminf(multsv0 * pow_F(vmaxf(LVFU(rawData[row][col]), onev), expsv0), c65535v));
|
||||||
STVFU(rawData[row][col + 4], vminf(multsv1 * pow_F(vmaxf(LVFU(rawData[row][col + 4]), onev), expsv1), c65535v));
|
STVFU(rawData[row][col + 4], vminf(multsv1 * pow_F(vmaxf(LVFU(rawData[row][col + 4]), onev), expsv1), c65535v));
|
||||||
STVFU(rawData[row][col + 8], vminf(multsv2 * pow_F(vmaxf(LVFU(rawData[row][col + 8]), onev), expsv2), c65535v));
|
STVFU(rawData[row][col + 8], vminf(multsv2 * pow_F(vmaxf(LVFU(rawData[row][col + 8]), onev), expsv2), c65535v));
|
||||||
}
|
}
|
||||||
#endif // __SSE2__
|
#endif // __SSE2__
|
||||||
for (; col < W - 5; col+=6) {
|
for (; col < W - 5; col += 6) {
|
||||||
for (int c = 0; c < 6; ++c) {
|
for (int c = 0; c < 6; ++c) {
|
||||||
rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(max(rawData[row][col + c], 1.f), expsc[c]), 65535.f);
|
rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(rtengine::max(rawData[row][col + c], 1.f), expsc[c]), 65535.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (int c = 0; col < W; col++, c++) {
|
for (int c = 0; col < W; col++, c++) {
|
||||||
rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(max(rawData[row][col + c], 1.f), expsc[c]), 65535.f);
|
rawData[row][col + c] = rtengine::min(multsc[c] * pow_F(rtengine::max(rawData[row][col + c], 1.f), expsc[c]), 65535.f);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
t4.set();
|
||||||
|
|
||||||
|
if (settings->verbose) {
|
||||||
|
printf("Pow loop time us: %d\n", t4.etime(t3));
|
||||||
|
}
|
||||||
|
|
||||||
t4.set();
|
t4.set();
|
||||||
if (settings->verbose)
|
|
||||||
printf("Pow loop time us: %d\n", t4.etime(t3));
|
|
||||||
|
|
||||||
|
|
||||||
t5.set();
|
|
||||||
|
|
||||||
PixelsMap bitmapBads(W, H);
|
PixelsMap bitmapBads(W, H);
|
||||||
|
|
||||||
int totBP = 0; // Hold count of bad pixels to correct
|
int totBP = 0; // Hold count of bad pixels to correct
|
||||||
|
|
||||||
if(ri->getSensorType() == ST_BAYER) {
|
if (ri->getSensorType() == ST_BAYER) {
|
||||||
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
#pragma omp parallel for reduction(+:totBP) schedule(dynamic,16)
|
#pragma omp parallel for reduction(+:totBP) schedule(dynamic,16)
|
||||||
#endif
|
#endif
|
||||||
|
for (int i = 0; i < H; ++i) {
|
||||||
for(int i = 0; i < H; i++)
|
for (int j = 0; j < W; ++j) {
|
||||||
for(int j = 0; j < W; j++) {
|
|
||||||
if (rawData[i][j] >= MAX_OUT_VALUE) {
|
if (rawData[i][j] >= MAX_OUT_VALUE) {
|
||||||
bitmapBads.set(j, i);
|
bitmapBads.set(j, i);
|
||||||
totBP++;
|
++totBP;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (totBP > 0) {
|
|
||||||
interpolateBadPixelsBayer( bitmapBads, rawData );
|
|
||||||
}
|
}
|
||||||
|
|
||||||
} else if(ri->getSensorType() == ST_FUJI_XTRANS) {
|
|
||||||
|
|
||||||
#ifdef _OPENMP
|
|
||||||
#pragma omp parallel for reduction(+:totBP) schedule(dynamic,16)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
for(int i = 0; i < H; i++)
|
|
||||||
for(int j = 0; j < W; j++) {
|
|
||||||
if (rawData[i][j] >= MAX_OUT_VALUE) {
|
|
||||||
bitmapBads.set(j, i);
|
|
||||||
totBP++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (totBP > 0) {
|
if (totBP > 0) {
|
||||||
interpolateBadPixelsXtrans( bitmapBads );
|
interpolateBadPixelsBayer(bitmapBads, rawData);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
else if (ri->getSensorType() == ST_FUJI_XTRANS) {
|
||||||
|
#ifdef _OPENMP
|
||||||
|
#pragma omp parallel for reduction(+:totBP) schedule(dynamic,16)
|
||||||
|
#endif
|
||||||
|
for (int i = 0; i < H; ++i) {
|
||||||
|
for (int j = 0; j < W; ++j) {
|
||||||
|
if (rawData[i][j] >= MAX_OUT_VALUE) {
|
||||||
|
bitmapBads.set(j, i);
|
||||||
|
totBP++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (totBP > 0) {
|
||||||
|
interpolateBadPixelsXtrans(bitmapBads);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
t5.set();
|
||||||
|
|
||||||
t6.set();
|
|
||||||
if (settings->verbose) {
|
if (settings->verbose) {
|
||||||
printf("Bad pixels count: %d\n", totBP);
|
printf("Bad pixels count: %d\n", totBP);
|
||||||
printf("Bad pixels interpolation time us: %d\n", t6.etime(t5));
|
printf("Bad pixels interpolation time us: %d\n", t5.etime(t4));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
|
@ -67,7 +67,7 @@ RawImage::~RawImage()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
eSensorType RawImage::getSensorType()
|
eSensorType RawImage::getSensorType() const
|
||||||
{
|
{
|
||||||
if (isBayer()) {
|
if (isBayer()) {
|
||||||
return ST_BAYER;
|
return ST_BAYER;
|
||||||
|
@ -185,7 +185,7 @@ public:
|
|||||||
return float_raw_image;
|
return float_raw_image;
|
||||||
}
|
}
|
||||||
|
|
||||||
eSensorType getSensorType();
|
eSensorType getSensorType() const;
|
||||||
|
|
||||||
void getRgbCam (float rgbcam[3][4]);
|
void getRgbCam (float rgbcam[3][4]);
|
||||||
void getXtransMatrix ( int xtransMatrix[6][6]);
|
void getXtransMatrix ( int xtransMatrix[6][6]);
|
||||||
|
@ -43,7 +43,6 @@ private:
|
|||||||
static LUTf initInvGrad ();
|
static LUTf initInvGrad ();
|
||||||
static void colorSpaceConversion_ (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName);
|
static void colorSpaceConversion_ (Imagefloat* im, const procparams::ColorManagementParams& cmp, const ColorTemp &wb, double pre_mul[3], cmsHPROFILE embedded, cmsHPROFILE camprofile, double cam[3][3], const std::string &camName);
|
||||||
int defTransform (int tran);
|
int defTransform (int tran);
|
||||||
bool channelsAvg(Coord spotPos, int spotSize, float avgs[3], const FilmNegativeParams ¶ms);
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
MyMutex getImageMutex; // locks getImage
|
MyMutex getImageMutex; // locks getImage
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RawTherapee.
|
* This file is part of RawTherapee.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
* Copyright (c) 2019 rom9
|
||||||
*
|
*
|
||||||
* RawTherapee is free software: you can redistribute it and/or modify
|
* RawTherapee is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -16,52 +16,52 @@
|
|||||||
* 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 "filmnegative.h"
|
|
||||||
|
|
||||||
#include <iomanip>
|
#include <iomanip>
|
||||||
|
|
||||||
#include "rtimage.h"
|
#include "filmnegative.h"
|
||||||
#include "options.h"
|
|
||||||
#include "editwidgets.h"
|
#include "editwidgets.h"
|
||||||
#include "eventmapper.h"
|
#include "eventmapper.h"
|
||||||
|
#include "options.h"
|
||||||
|
#include "rtimage.h"
|
||||||
|
|
||||||
|
#include "../rtengine/procparams.h"
|
||||||
|
|
||||||
using namespace rtengine;
|
namespace
|
||||||
using namespace rtengine::procparams;
|
|
||||||
|
|
||||||
|
|
||||||
FilmNegative::FilmNegative () : FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true), EditSubscriber(ET_OBJECTS)
|
|
||||||
{
|
{
|
||||||
|
|
||||||
auto mkExponentAdjuster = [this](Glib::ustring label, double defaultVal) {
|
Adjuster* createExponentAdjuster(AdjusterListener* listener, const Glib::ustring& label, double defaultVal)
|
||||||
Adjuster *adj = Gtk::manage(new Adjuster (label, 0.3, 6, 0.001, defaultVal)); //exponent
|
{
|
||||||
adj->setAdjusterListener (this);
|
Adjuster* const adj = Gtk::manage(new Adjuster(label, 0.3, 6, 0.001, defaultVal)); // exponent
|
||||||
|
adj->setAdjusterListener(listener);
|
||||||
if (adj->delay < options.adjusterMaxDelay) {
|
|
||||||
adj->delay = options.adjusterMaxDelay;
|
|
||||||
}
|
|
||||||
|
|
||||||
adj->show();
|
|
||||||
return adj;
|
|
||||||
};
|
|
||||||
|
|
||||||
redExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_RED"), 2.72);
|
if (adj->delay < options.adjusterMaxDelay) {
|
||||||
greenExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_GREEN"), 2.0);
|
adj->delay = options.adjusterMaxDelay;
|
||||||
blueExp = mkExponentAdjuster(M("TP_FILMNEGATIVE_BLUE"), 1.72);
|
}
|
||||||
|
|
||||||
redRatio = redExp->getValue() / greenExp->getValue();
|
adj->show();
|
||||||
blueRatio = blueExp->getValue() / greenExp->getValue();
|
return adj;
|
||||||
|
}
|
||||||
|
|
||||||
auto m = ProcEventMapper::getInstance();
|
}
|
||||||
EvFilmNegativeEnabled = m->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_ENABLED");
|
|
||||||
EvFilmNegativeExponents = m->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_EXPONENTS");
|
|
||||||
|
|
||||||
|
FilmNegative::FilmNegative() :
|
||||||
spotgrid = Gtk::manage(new Gtk::Grid());
|
FoldableToolPanel(this, "filmnegative", M("TP_FILMNEGATIVE_LABEL"), false, true),
|
||||||
|
EditSubscriber(ET_OBJECTS),
|
||||||
|
evFilmNegativeExponents(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_EXPONENTS")),
|
||||||
|
evFilmNegativeEnabled(ProcEventMapper::getInstance()->newEvent(FIRST, "HISTORY_MSG_FILMNEGATIVE_ENABLED")),
|
||||||
|
fnp(nullptr),
|
||||||
|
redExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_RED"), 2.72)),
|
||||||
|
greenExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_GREEN"), 2.0)),
|
||||||
|
blueExp(createExponentAdjuster(this, M("TP_FILMNEGATIVE_BLUE"), 1.72)),
|
||||||
|
spotgrid(Gtk::manage(new Gtk::Grid())),
|
||||||
|
spotbutton(Gtk::manage(new Gtk::ToggleButton(M("TP_FILMNEGATIVE_PICK")))),
|
||||||
|
redRatio(redExp->getValue() / greenExp->getValue()),
|
||||||
|
blueRatio(blueExp->getValue() / greenExp->getValue())
|
||||||
|
{
|
||||||
spotgrid->get_style_context()->add_class("grid-spacing");
|
spotgrid->get_style_context()->add_class("grid-spacing");
|
||||||
setExpandAlignProperties(spotgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
setExpandAlignProperties(spotgrid, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
||||||
|
|
||||||
spotbutton = Gtk::manage (new Gtk::ToggleButton (M("TP_FILMNEGATIVE_PICK")));
|
|
||||||
setExpandAlignProperties(spotbutton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
setExpandAlignProperties(spotbutton, true, false, Gtk::ALIGN_FILL, Gtk::ALIGN_CENTER);
|
||||||
spotbutton->get_style_context()->add_class("independent");
|
spotbutton->get_style_context()->add_class("independent");
|
||||||
spotbutton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP"));
|
spotbutton->set_tooltip_text(M("TP_FILMNEGATIVE_GUESS_TOOLTIP"));
|
||||||
@ -83,120 +83,47 @@ FilmNegative::FilmNegative () : FoldableToolPanel(this, "filmnegative", M("TP_FI
|
|||||||
// spotsize->append ("4");
|
// spotsize->append ("4");
|
||||||
|
|
||||||
spotgrid->attach (*spotbutton, 0, 1, 1, 1);
|
spotgrid->attach (*spotbutton, 0, 1, 1, 1);
|
||||||
// spotgrid->attach (*slab, 1, 0, 1, 1);
|
// spotgrid->attach (*slab, 1, 0, 1, 1);
|
||||||
// spotgrid->attach (*wbsizehelper, 2, 0, 1, 1);
|
// spotgrid->attach (*wbsizehelper, 2, 0, 1, 1);
|
||||||
|
|
||||||
pack_start (*redExp, Gtk::PACK_SHRINK, 0);
|
pack_start(*redExp, Gtk::PACK_SHRINK, 0);
|
||||||
pack_start (*greenExp, Gtk::PACK_SHRINK, 0);
|
pack_start(*greenExp, Gtk::PACK_SHRINK, 0);
|
||||||
pack_start (*blueExp, Gtk::PACK_SHRINK, 0);
|
pack_start(*blueExp, Gtk::PACK_SHRINK, 0);
|
||||||
pack_start (*spotgrid, Gtk::PACK_SHRINK, 0 );
|
pack_start(*spotgrid, Gtk::PACK_SHRINK, 0);
|
||||||
|
|
||||||
spotbutton->signal_toggled().connect( sigc::mem_fun(*this, &FilmNegative::editToggled) );
|
|
||||||
// spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) );
|
|
||||||
|
|
||||||
|
spotbutton->signal_toggled().connect(sigc::mem_fun(*this, &FilmNegative::editToggled));
|
||||||
|
// spotsize->signal_changed().connect( sigc::mem_fun(*this, &WhiteBalance::spotSizeChanged) );
|
||||||
|
|
||||||
// Editing geometry; create the spot rectangle
|
// Editing geometry; create the spot rectangle
|
||||||
Rectangle *spotRect = new Rectangle();
|
Rectangle* const spotRect = new Rectangle();
|
||||||
spotRect->filled = false;
|
spotRect->filled = false;
|
||||||
|
|
||||||
EditSubscriber::visibleGeometry.push_back( spotRect );
|
visibleGeometry.push_back(spotRect);
|
||||||
|
|
||||||
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
|
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
|
||||||
// This is to make sure the getCursor call is fired everywhere.
|
// This is to make sure the getCursor() call is fired everywhere.
|
||||||
Rectangle *imgRect = new Rectangle();
|
Rectangle* imgRect = new Rectangle();
|
||||||
imgRect->filled = true;
|
imgRect->filled = true;
|
||||||
|
|
||||||
EditSubscriber::mouseOverGeometry.push_back( imgRect );
|
mouseOverGeometry.push_back(imgRect);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
FilmNegative::~FilmNegative()
|
FilmNegative::~FilmNegative()
|
||||||
{
|
{
|
||||||
// idle_register.destroy();
|
for (auto geometry : visibleGeometry) {
|
||||||
|
delete geometry;
|
||||||
for (std::vector<Geometry*>::const_iterator i = visibleGeometry.begin(); i != visibleGeometry.end(); ++i) {
|
|
||||||
delete *i;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (std::vector<Geometry*>::const_iterator i = mouseOverGeometry.begin(); i != mouseOverGeometry.end(); ++i) {
|
for (auto geometry : mouseOverGeometry) {
|
||||||
delete *i;
|
delete geometry;
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void FilmNegative::enabledChanged()
|
|
||||||
{
|
|
||||||
if (listener) {
|
|
||||||
if (get_inconsistent()) {
|
|
||||||
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_UNCHANGED"));
|
|
||||||
} else if (getEnabled()) {
|
|
||||||
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_ENABLED"));
|
|
||||||
} else {
|
|
||||||
listener->panelChanged(EvFilmNegativeEnabled, M("GENERAL_DISABLED"));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FilmNegative::read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited)
|
||||||
void FilmNegative::adjusterChanged(Adjuster* a, double newval)
|
|
||||||
{
|
{
|
||||||
if (listener) {
|
disableListener();
|
||||||
if(a == redExp || a == greenExp || a == blueExp) {
|
|
||||||
disableListener();
|
|
||||||
if(a == greenExp) {
|
|
||||||
redExp->setValue(a->getValue() * redRatio);
|
|
||||||
blueExp->setValue(a->getValue() * blueRatio);
|
|
||||||
} else if(a == redExp) {
|
|
||||||
redRatio = newval / greenExp->getValue();
|
|
||||||
} else if(a == blueExp) {
|
|
||||||
blueRatio = newval / greenExp->getValue();
|
|
||||||
}
|
|
||||||
enableListener();
|
|
||||||
|
|
||||||
if(getEnabled()) {
|
if (pedited) {
|
||||||
listener->panelChanged (EvFilmNegativeExponents, Glib::ustring::compose (
|
|
||||||
"R=%1 ; G=%2 ; B=%3", redExp->getTextValue(), greenExp->getTextValue(), blueExp->getTextValue()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void FilmNegative::adjusterAutoToggled(Adjuster* a, bool newval)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void FilmNegative::setEditProvider (EditDataProvider* provider)
|
|
||||||
{
|
|
||||||
EditSubscriber::setEditProvider(provider);
|
|
||||||
}
|
|
||||||
|
|
||||||
void FilmNegative::editToggled ()
|
|
||||||
{
|
|
||||||
if (spotbutton->get_active()) {
|
|
||||||
subscribe();
|
|
||||||
|
|
||||||
int w, h;
|
|
||||||
getEditProvider()->getImageSize(w, h);
|
|
||||||
|
|
||||||
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
|
|
||||||
// This is to make sure the getCursor call is fired everywhere.
|
|
||||||
const auto imgRect = static_cast<Rectangle*>(mouseOverGeometry.at(0));
|
|
||||||
imgRect->setXYWH(0, 0, w, h);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
this->refSpotCoords.clear();
|
|
||||||
unsubscribe();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void FilmNegative::read (const ProcParams* pp, const ParamsEdited* pedited)
|
|
||||||
{
|
|
||||||
disableListener ();
|
|
||||||
|
|
||||||
if(pedited) {
|
|
||||||
redExp->setEditedState(pedited->filmNegative.redExp ? Edited : UnEdited);
|
redExp->setEditedState(pedited->filmNegative.redExp ? Edited : UnEdited);
|
||||||
greenExp->setEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited);
|
greenExp->setEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited);
|
||||||
blueExp->setEditedState(pedited->filmNegative.blueExp ? Edited : UnEdited);
|
blueExp->setEditedState(pedited->filmNegative.blueExp ? Edited : UnEdited);
|
||||||
@ -208,10 +135,10 @@ void FilmNegative::read (const ProcParams* pp, const ParamsEdited* pedited)
|
|||||||
greenExp->setValue(pp->filmNegative.greenExp);
|
greenExp->setValue(pp->filmNegative.greenExp);
|
||||||
blueExp->setValue(pp->filmNegative.blueExp);
|
blueExp->setValue(pp->filmNegative.blueExp);
|
||||||
|
|
||||||
enableListener ();
|
enableListener();
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilmNegative::write (ProcParams* pp, ParamsEdited* pedited)
|
void FilmNegative::write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited)
|
||||||
{
|
{
|
||||||
pp->filmNegative.redExp = redExp->getValue();
|
pp->filmNegative.redExp = redExp->getValue();
|
||||||
pp->filmNegative.greenExp = greenExp->getValue();
|
pp->filmNegative.greenExp = greenExp->getValue();
|
||||||
@ -226,37 +153,103 @@ void FilmNegative::write (ProcParams* pp, ParamsEdited* pedited)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilmNegative::setDefaults (const ProcParams* defParams, const ParamsEdited* pedited)
|
void FilmNegative::setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited)
|
||||||
{
|
{
|
||||||
redExp->setValue(defParams->filmNegative.redExp);
|
redExp->setValue(defParams->filmNegative.redExp);
|
||||||
greenExp->setValue(defParams->filmNegative.greenExp);
|
greenExp->setValue(defParams->filmNegative.greenExp);
|
||||||
blueExp->setValue(defParams->filmNegative.blueExp);
|
blueExp->setValue(defParams->filmNegative.blueExp);
|
||||||
|
|
||||||
if (pedited) {
|
if (pedited) {
|
||||||
redExp->setDefaultEditedState (pedited->filmNegative.redExp ? Edited : UnEdited);
|
redExp->setDefaultEditedState(pedited->filmNegative.redExp ? Edited : UnEdited);
|
||||||
greenExp->setDefaultEditedState (pedited->filmNegative.greenExp ? Edited : UnEdited);
|
greenExp->setDefaultEditedState(pedited->filmNegative.greenExp ? Edited : UnEdited);
|
||||||
blueExp->setDefaultEditedState (pedited->filmNegative.blueExp ? Edited : UnEdited);
|
blueExp->setDefaultEditedState(pedited->filmNegative.blueExp ? Edited : UnEdited);
|
||||||
} else {
|
} else {
|
||||||
redExp->setDefaultEditedState (Irrelevant);
|
redExp->setDefaultEditedState(Irrelevant);
|
||||||
greenExp->setDefaultEditedState (Irrelevant);
|
greenExp->setDefaultEditedState(Irrelevant);
|
||||||
blueExp->setDefaultEditedState (Irrelevant);
|
blueExp->setDefaultEditedState(Irrelevant);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void FilmNegative::setBatchMode (bool batchMode)
|
void FilmNegative::setBatchMode(bool batchMode)
|
||||||
{
|
{
|
||||||
spotConn.disconnect();
|
spotConn.disconnect();
|
||||||
removeIfThere(this, spotgrid, false);
|
removeIfThere(this, spotgrid, false);
|
||||||
ToolPanel::setBatchMode (batchMode);
|
ToolPanel::setBatchMode(batchMode);
|
||||||
redExp->showEditedCB ();
|
redExp->showEditedCB();
|
||||||
greenExp->showEditedCB ();
|
greenExp->showEditedCB();
|
||||||
blueExp->showEditedCB ();
|
blueExp->showEditedCB();
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::adjusterChanged(Adjuster* a, double newval)
|
||||||
|
{
|
||||||
|
if (listener) {
|
||||||
|
if (a == redExp || a == greenExp || a == blueExp) {
|
||||||
|
disableListener();
|
||||||
|
if (a == greenExp) {
|
||||||
|
redExp->setValue(a->getValue() * redRatio);
|
||||||
|
blueExp->setValue(a->getValue() * blueRatio);
|
||||||
|
}
|
||||||
|
else if (a == redExp) {
|
||||||
|
redRatio = newval / greenExp->getValue();
|
||||||
|
}
|
||||||
|
else if (a == blueExp) {
|
||||||
|
blueRatio = newval / greenExp->getValue();
|
||||||
|
}
|
||||||
|
enableListener();
|
||||||
|
|
||||||
|
if (getEnabled()) {
|
||||||
|
listener->panelChanged(
|
||||||
|
evFilmNegativeExponents,
|
||||||
|
Glib::ustring::compose(
|
||||||
|
"R=%1 ; G=%2 ; B=%3",
|
||||||
|
redExp->getTextValue(),
|
||||||
|
greenExp->getTextValue(),
|
||||||
|
blueExp->getTextValue()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::adjusterAutoToggled(Adjuster* a, bool newval)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::enabledChanged()
|
||||||
|
{
|
||||||
|
if (listener) {
|
||||||
|
if (get_inconsistent()) {
|
||||||
|
listener->panelChanged(evFilmNegativeEnabled, M("GENERAL_UNCHANGED"));
|
||||||
|
}
|
||||||
|
else if (getEnabled()) {
|
||||||
|
listener->panelChanged(evFilmNegativeEnabled, M("GENERAL_ENABLED"));
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
listener->panelChanged(evFilmNegativeEnabled, M("GENERAL_DISABLED"));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::setFilmNegProvider(FilmNegProvider* p)
|
||||||
|
{
|
||||||
|
fnp = p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::setEditProvider(EditDataProvider* provider)
|
||||||
|
{
|
||||||
|
EditSubscriber::setEditProvider(provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
CursorShape FilmNegative::getCursor(int objectID) const
|
||||||
|
{
|
||||||
|
return CSSpotWB;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilmNegative::mouseOver(int modifierKey)
|
bool FilmNegative::mouseOver(int modifierKey)
|
||||||
{
|
{
|
||||||
EditDataProvider *provider = getEditProvider();
|
EditDataProvider* const provider = getEditProvider();
|
||||||
const auto spotRect = static_cast<Rectangle*>(visibleGeometry.at(0));
|
Rectangle* const spotRect = static_cast<Rectangle*>(visibleGeometry.at(0));
|
||||||
spotRect->setXYWH(provider->posImage.x - 16, provider->posImage.y - 16, 32, 32);
|
spotRect->setXYWH(provider->posImage.x - 16, provider->posImage.y - 16, 32, 32);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -264,20 +257,18 @@ bool FilmNegative::mouseOver(int modifierKey)
|
|||||||
|
|
||||||
bool FilmNegative::button1Pressed(int modifierKey)
|
bool FilmNegative::button1Pressed(int modifierKey)
|
||||||
{
|
{
|
||||||
EditDataProvider *provider = getEditProvider();
|
EditDataProvider* const provider = getEditProvider();
|
||||||
|
|
||||||
if(provider) { // debug. remove me
|
if (provider) { // TODO: Remove me (rom9)
|
||||||
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
||||||
}
|
}
|
||||||
|
|
||||||
EditSubscriber::action = EditSubscriber::Action::NONE;
|
EditSubscriber::action = EditSubscriber::Action::NONE;
|
||||||
|
|
||||||
if (listener) {
|
if (listener) {
|
||||||
|
|
||||||
refSpotCoords.push_back(provider->posImage);
|
refSpotCoords.push_back(provider->posImage);
|
||||||
|
|
||||||
if(refSpotCoords.size() == 2) {
|
if (refSpotCoords.size() == 2) {
|
||||||
|
|
||||||
// User has selected 2 reference gray spots. Calculating new exponents
|
// User has selected 2 reference gray spots. Calculating new exponents
|
||||||
// from channel values and updating parameters.
|
// from channel values and updating parameters.
|
||||||
|
|
||||||
@ -292,8 +283,15 @@ bool FilmNegative::button1Pressed(int modifierKey)
|
|||||||
enableListener();
|
enableListener();
|
||||||
|
|
||||||
if (listener && getEnabled()) {
|
if (listener && getEnabled()) {
|
||||||
listener->panelChanged (EvFilmNegativeExponents, Glib::ustring::compose (
|
listener->panelChanged(
|
||||||
"R=%1 ; G=%2 ; B=%3", redExp->getTextValue(), greenExp->getTextValue(), blueExp->getTextValue()));
|
evFilmNegativeExponents,
|
||||||
|
Glib::ustring::compose(
|
||||||
|
"R=%1 ; G=%2 ; B=%3",
|
||||||
|
redExp->getTextValue(),
|
||||||
|
greenExp->getTextValue(),
|
||||||
|
blueExp->getTextValue()
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -304,35 +302,50 @@ bool FilmNegative::button1Pressed(int modifierKey)
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool FilmNegative::button1Released ()
|
bool FilmNegative::button1Released()
|
||||||
{
|
{
|
||||||
EditDataProvider *provider = getEditProvider();
|
EditDataProvider* const provider = getEditProvider();
|
||||||
|
|
||||||
if(provider) { // debug. remove me
|
if (provider) { // TODO: Remove me (rom9)
|
||||||
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
printf("x=%d y=%d pv1=%f pv2=%f pv3=%f\n", provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
||||||
}
|
}
|
||||||
|
|
||||||
EditSubscriber::action = EditSubscriber::Action::NONE;
|
EditSubscriber::action = EditSubscriber::Action::NONE;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO remove me ; couldn't make Action::PICKING work
|
void FilmNegative::switchOffEditMode()
|
||||||
bool FilmNegative::pick1 (bool picked) {
|
|
||||||
EditDataProvider *provider = getEditProvider();
|
|
||||||
if(provider) { // debug. remove me
|
|
||||||
printf("Picked pick=%d x=%d y=%d pv1=%f pv2=%f pv3=%f\n", picked, provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
CursorShape FilmNegative::getCursor(int objectID) const
|
|
||||||
{
|
|
||||||
return CSSpotWB;
|
|
||||||
}
|
|
||||||
|
|
||||||
void FilmNegative::switchOffEditMode ()
|
|
||||||
{
|
{
|
||||||
refSpotCoords.clear();
|
refSpotCoords.clear();
|
||||||
unsubscribe();
|
unsubscribe();
|
||||||
spotbutton->set_active(false);
|
spotbutton->set_active(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Remove me ; couldn't make Action::PICKING work (rom9)
|
||||||
|
bool FilmNegative::pick1(bool picked)
|
||||||
|
{
|
||||||
|
EditDataProvider* const provider = getEditProvider();
|
||||||
|
if (provider) { // TODO: Remove me (rom9)
|
||||||
|
printf("Picked pick=%d x=%d y=%d pv1=%f pv2=%f pv3=%f\n", picked, provider->posImage.x, provider->posImage.y, provider->getPipetteVal1(), provider->getPipetteVal2(), provider->getPipetteVal3());
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void FilmNegative::editToggled()
|
||||||
|
{
|
||||||
|
if (spotbutton->get_active()) {
|
||||||
|
subscribe();
|
||||||
|
|
||||||
|
int w, h;
|
||||||
|
getEditProvider()->getImageSize(w, h);
|
||||||
|
|
||||||
|
// Stick a dummy rectangle over the whole image in mouseOverGeometry.
|
||||||
|
// This is to make sure the getCursor() call is fired everywhere.
|
||||||
|
Rectangle* const imgRect = static_cast<Rectangle*>(mouseOverGeometry.at(0));
|
||||||
|
imgRect->setXYWH(0, 0, w, h);
|
||||||
|
} else {
|
||||||
|
refSpotCoords.clear();
|
||||||
|
unsubscribe();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* This file is part of RawTherapee.
|
* This file is part of RawTherapee.
|
||||||
*
|
*
|
||||||
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
* Copyright (c) 2019 rom9
|
||||||
*
|
*
|
||||||
* RawTherapee is free software: you can redistribute it and/or modify
|
* RawTherapee is free software: you can redistribute it and/or modify
|
||||||
* it under the terms of the GNU General Public License as published by
|
* it under the terms of the GNU General Public License as published by
|
||||||
@ -28,66 +28,66 @@
|
|||||||
#include "toolpanel.h"
|
#include "toolpanel.h"
|
||||||
#include "wbprovider.h"
|
#include "wbprovider.h"
|
||||||
|
|
||||||
#include "../rtengine/procparams.h"
|
#include "../rtengine/noncopyable.h"
|
||||||
|
|
||||||
class FilmNegProvider
|
class FilmNegProvider
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
virtual ~FilmNegProvider() = default;
|
virtual ~FilmNegProvider() = default;
|
||||||
|
|
||||||
virtual bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, std::array<float, 3>& newExps) = 0;
|
virtual bool getFilmNegativeExponents(rtengine::Coord spotA, rtengine::Coord spotB, std::array<float, 3>& newExps) = 0;
|
||||||
};
|
};
|
||||||
|
|
||||||
class FilmNegative : public ToolParamBlock, public AdjusterListener, public FoldableToolPanel, public EditSubscriber
|
class FilmNegative :
|
||||||
|
public rtengine::NonCopyable,
|
||||||
|
public ToolParamBlock,
|
||||||
|
public AdjusterListener,
|
||||||
|
public FoldableToolPanel,
|
||||||
|
public EditSubscriber
|
||||||
{
|
{
|
||||||
|
|
||||||
private:
|
|
||||||
rtengine::ProcEvent EvFilmNegativeExponents;
|
|
||||||
rtengine::ProcEvent EvFilmNegativeEnabled;
|
|
||||||
|
|
||||||
std::vector<rtengine::Coord> refSpotCoords;
|
|
||||||
|
|
||||||
FilmNegProvider *fnp;
|
|
||||||
|
|
||||||
Adjuster* redExp;
|
|
||||||
Adjuster* greenExp;
|
|
||||||
Adjuster* blueExp;
|
|
||||||
|
|
||||||
Gtk::Grid* spotgrid;
|
|
||||||
Gtk::ToggleButton* spotbutton;
|
|
||||||
sigc::connection spotConn;
|
|
||||||
|
|
||||||
double redRatio, blueRatio;
|
|
||||||
|
|
||||||
void editToggled ();
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
FilmNegative();
|
||||||
|
~FilmNegative() override;
|
||||||
|
|
||||||
FilmNegative ();
|
void read(const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override;
|
||||||
~FilmNegative () override;
|
void write(rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override;
|
||||||
|
void setDefaults(const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override;
|
||||||
|
void setBatchMode(bool batchMode) override;
|
||||||
|
|
||||||
void setFilmNegProvider(FilmNegProvider* p)
|
void adjusterChanged(Adjuster* a, double newval) override;
|
||||||
{
|
|
||||||
fnp = p;
|
|
||||||
};
|
|
||||||
|
|
||||||
void read (const rtengine::procparams::ProcParams* pp, const ParamsEdited* pedited = nullptr) override;
|
|
||||||
void write (rtengine::procparams::ProcParams* pp, ParamsEdited* pedited = nullptr) override;
|
|
||||||
void setDefaults (const rtengine::procparams::ProcParams* defParams, const ParamsEdited* pedited = nullptr) override;
|
|
||||||
void setBatchMode (bool batchMode) override;
|
|
||||||
|
|
||||||
void adjusterChanged (Adjuster* a, double newval) override;
|
|
||||||
void adjusterAutoToggled(Adjuster* a, bool newval) override;
|
void adjusterAutoToggled(Adjuster* a, bool newval) override;
|
||||||
void spotPressed ();
|
|
||||||
void enabledChanged() override;
|
void enabledChanged() override;
|
||||||
|
|
||||||
void setEditProvider (EditDataProvider* provider) override;
|
void setFilmNegProvider(FilmNegProvider* p);
|
||||||
|
|
||||||
|
void setEditProvider(EditDataProvider* provider) override;
|
||||||
|
|
||||||
// EditSubscriber interface
|
// EditSubscriber interface
|
||||||
CursorShape getCursor(int objectID) const override;
|
CursorShape getCursor(int objectID) const override;
|
||||||
bool mouseOver(int modifierKey) override;
|
bool mouseOver(int modifierKey) override;
|
||||||
bool button1Pressed(int modifierKey) override;
|
bool button1Pressed(int modifierKey) override;
|
||||||
bool button1Released() override;
|
bool button1Released() override;
|
||||||
void switchOffEditMode () override;
|
void switchOffEditMode() override;
|
||||||
bool pick1(bool picked) override;
|
bool pick1(bool picked) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
void editToggled();
|
||||||
|
|
||||||
|
const rtengine::ProcEvent evFilmNegativeExponents;
|
||||||
|
const rtengine::ProcEvent evFilmNegativeEnabled;
|
||||||
|
|
||||||
|
std::vector<rtengine::Coord> refSpotCoords;
|
||||||
|
|
||||||
|
FilmNegProvider* fnp;
|
||||||
|
|
||||||
|
Adjuster* const redExp;
|
||||||
|
Adjuster* const greenExp;
|
||||||
|
Adjuster* const blueExp;
|
||||||
|
|
||||||
|
Gtk::Grid* const spotgrid;
|
||||||
|
Gtk::ToggleButton* const spotbutton;
|
||||||
|
sigc::connection spotConn;
|
||||||
|
|
||||||
|
double redRatio;
|
||||||
|
double blueRatio;
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user