Skip to content

Commit

Permalink
Added linear weight function, which yields the best SNR in case of sh…
Browse files Browse the repository at this point in the history
…ot noise. Edges are smoothly clipped, to account for readout and compression noise. See Grandos2010 for analysis. Note that triangular weight is rather suboptimal and should not be the default.
  • Loading branch information
bash0 committed Mar 21, 2021
1 parent 0d159a2 commit 4821fd4
Show file tree
Hide file tree
Showing 6 changed files with 53 additions and 8 deletions.
2 changes: 2 additions & 0 deletions src/Common/CommonFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -460,6 +460,8 @@ QString getQString(libhdr::fusion::WeightFunctionType wf) {
return QObject::tr("Gaussian");
case WEIGHT_FLAT:
return QObject::tr("Flat");
case WEIGHT_LINEAR:
return QObject::tr("Linear");
}

return QString();
Expand Down
45 changes: 40 additions & 5 deletions src/HdrCreation/weights.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ WeightFunctionType WeightFunction::fromString(const std::string &type) {
typedef map<string, WeightFunctionType, pfs::utils::StringUnsensitiveComp>
Dict;
static Dict v = map_list_of("triangular", WEIGHT_TRIANGULAR)(
"gaussian", WEIGHT_GAUSSIAN)("plateau", WEIGHT_PLATEAU)("flat",
WEIGHT_FLAT);
"gaussian", WEIGHT_GAUSSIAN)("plateau", WEIGHT_PLATEAU)(
"flat", WEIGHT_FLAT)("linear", WEIGHT_LINEAR);

Dict::const_iterator it = v.find(type);
if (it != v.end()) {
Expand Down Expand Up @@ -128,6 +128,38 @@ static float maxTrustedValueFlat() {
return 1.f + std::numeric_limits<float>::epsilon();
}

namespace {
static const float s_linearThreshold = 0.00025f;
}

static float getWeightLinear(float input) {
if ((input < s_linearThreshold) ||
(input > (1.f - s_linearThreshold))) {
return 0.f;
}
/* Clipping is such that weights rise quadratically on both edges
and the quadratic part reaches 1 at clipWidth away from edges. */
const float clipWidth = 0.07f;
float clipDark = 1.f - exp(-input / (clipWidth * clipWidth));
float clipBright = 1.f - exp(-pow((1.f - input) / clipWidth, 2));
return input * clipDark * clipBright;
}

static void fillWeightLinear(WeightFunction::WeightContainer &weight) {
size_t divider = (weight.size() - 1);
for (size_t i = 0; i < weight.size(); ++i) {
weight[i] = getWeightLinear((float)i / divider);
}
}

static float minTrustedValueLinear() {
return 0.f - std::numeric_limits<float>::epsilon();
}
static float maxTrustedValueLinear() {
return 1.f + std::numeric_limits<float>::epsilon();
}


void WeightFunction::setType(WeightFunctionType type) {
typedef void (*WeightFunctionCalculator)(WeightContainer &);
typedef float (*WeightTrustedValue)();
Expand All @@ -146,13 +178,16 @@ void WeightFunction::setType(WeightFunctionType type) {
WeightFunctionFiller fillter_g = {&fillWeightGaussian,
&minTrustedValueGaussian,
&maxTrustedValueGaussian};
WeightFunctionFiller fillter_p = {
&fillWeightPlateau, &minTrustedValuePlateau, &maxTrustedValuePlateau};
WeightFunctionFiller fillter_p = {&fillWeightPlateau,
&minTrustedValuePlateau,
&maxTrustedValuePlateau};
WeightFunctionFiller fillter_f = {&fillWeightFlat, &minTrustedValueFlat,
&maxTrustedValueFlat};
WeightFunctionFiller fillter_l = {&fillWeightLinear, &minTrustedValueLinear,
&maxTrustedValueLinear};
static WeightFunctionFunc funcs =
map_list_of(WEIGHT_TRIANGULAR, fillter_t)(WEIGHT_GAUSSIAN, fillter_g)(
WEIGHT_PLATEAU, fillter_p)(WEIGHT_FLAT, fillter_f);
WEIGHT_PLATEAU, fillter_p)(WEIGHT_FLAT, fillter_f)(WEIGHT_LINEAR, fillter_l);

WeightFunctionType type_ = WEIGHT_TRIANGULAR;
WeightFunctionFiller func_ = {&fillWeightTriangular,
Expand Down
3 changes: 2 additions & 1 deletion src/HdrCreation/weights.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,8 @@ enum WeightFunctionType {
WEIGHT_TRIANGULAR = 0,
WEIGHT_GAUSSIAN = 1,
WEIGHT_PLATEAU = 2,
WEIGHT_FLAT = 3
WEIGHT_FLAT = 3,
WEIGHT_LINEAR = 4
};

class WeightFunction {
Expand Down
2 changes: 1 addition & 1 deletion src/HdrWizard/HdrWizard.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ static const FusionOperator models_in_gui[] = {DEBEVEC, ROBERTSON,
ROBERTSON_AUTO};

static const WeightFunctionType weights_in_gui[] = {
WEIGHT_TRIANGULAR, WEIGHT_GAUSSIAN, WEIGHT_PLATEAU, WEIGHT_FLAT};
WEIGHT_TRIANGULAR, WEIGHT_GAUSSIAN, WEIGHT_PLATEAU, WEIGHT_FLAT, WEIGHT_LINEAR};

namespace {

Expand Down
5 changes: 5 additions & 0 deletions src/HdrWizard/HdrWizard.ui
Original file line number Diff line number Diff line change
Expand Up @@ -719,6 +719,11 @@ p, li { white-space: pre-wrap; }
<string>Flat</string>
</property>
</item>
<item>
<property name="text">
<string>Linear</string>
</property>
</item>
</widget>
</item>
<item row="7" column="1" colspan="2">
Expand Down
4 changes: 3 additions & 1 deletion src/MainCli/commandline.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ int CommandLineInterfaceManager::execCommandLineParams() {
.constData());
hdr_desc.add_options()(
"hdrWeight", po::value<std::string>(),
tr("weight = triangular|gaussian|plateau|flat (Default is triangular)")
tr("weight = triangular|gaussian|plateau|flat|linear (Default is triangular)")
.toUtf8()
.constData())("hdrResponseCurve", po::value<std::string>(),
tr("response curve = from_file|linear|gamma|log|srgb "
Expand Down Expand Up @@ -550,6 +550,8 @@ reinhard02|\nreinhard05|mai|mantiuk06|mantiuk08|\nvanhateren|lischinski] (Defaul
hdrcreationconfig.weightFunction = WEIGHT_PLATEAU;
else if (strcmp(value, "flat") == 0)
hdrcreationconfig.weightFunction = WEIGHT_FLAT;
else if (strcmp(value, "linear") == 0)
hdrcreationconfig.weightFunction = WEIGHT_LINEAR;
else
printErrorAndExit(
tr("Error: Unknown weight function specified."));
Expand Down

0 comments on commit 4821fd4

Please sign in to comment.