Closed Floessie closed 6 years ago
@Floessie how can we test this?
@Beep6581 The bin in #126 is still valid and exhibits the problem well. Maybe test this branch against a known stack of yours and see, if there are differences in the mask.
As said, this is only meant as a basis for something cleverer.
Best, Flössie
I confirm that it improves the situation in your Canon EOS 6D image set.
My Sony ILCE-7M2's white levels are not auto-detected correctly in master, forcing me to set them manually, as the theoretical maximum white is higher than the actual white. You can even see the Sony compression artifacts in the screenshot below because of the wrong white level. With your patch, the actual white level is auto-detected correctly.
Unpatched:
Patched:
@Floessie I will try to write the loop using omp.
@heckflosse This is a no-brainer for you, I'm sure. :+1:
@Floessie
Here's the patch
diff --git a/src/Image.hpp b/src/Image.hpp
index dc0fded..972fdeb 100644
--- a/src/Image.hpp
+++ b/src/Image.hpp
@@ -74,6 +74,10 @@ public:
return brightness > r.brightness;
}
void setSaturationThreshold(uint16_t sat);
+ uint16_t getMax() const
+ {
+ return max;
+ }
private:
struct ResponseFunction {
diff --git a/src/ImageStack.cpp b/src/ImageStack.cpp
index 9097bb4..fb29d7a 100644
--- a/src/ImageStack.cpp
+++ b/src/ImageStack.cpp
@@ -21,6 +21,7 @@
*/
#include <algorithm>
+#include <valarray>
#include "ImageStack.hpp"
#include "Log.hpp"
#include "BoxBlur.hpp"
@@ -50,11 +51,13 @@ int ImageStack::addImage(Image && i) {
void ImageStack::calculateSaturationLevel(const RawParameters & params, bool useCustomWl) {
// Calculate max value of brightest image and assume it is saturated
- uint16_t maxPerColor[4] = { 0, 0, 0, 0 };
Image & brightest = images.front();
+
+ std::vector<std::vector<size_t>> histograms(4, std::vector<size_t>(brightest.getMax() + 1));
+
#pragma omp parallel
{
- uint16_t maxPerColorThr[4] = { 0, 0, 0, 0 };
+ std::vector<std::vector<size_t>> histogramsThr(4, std::vector<size_t>(brightest.getMax() + 1));
#pragma omp for schedule(dynamic,16) nowait
for (size_t y = 0; y < height; ++y) {
// get the color codes from x = 0 to 5, works for bayer and xtrans
@@ -66,23 +69,33 @@ void ImageStack::calculateSaturationLevel(const RawParameters & params, bool use
for (; x < width - 5; x+=6) {
for(size_t j = 0; j < 6; ++j) {
uint16_t v = brightest(x + j, y);
- if (v > maxPerColorThr[fcrow[j]]) {
- maxPerColorThr[fcrow[j]] = v;
- }
+ ++histogramsThr[fcrow[j]][v];
}
}
// remaining pixels
for (size_t j = 0; x < width; ++x, ++j) {
- uint16_t v = brightest(x, y);
- if (v > maxPerColorThr[fcrow[j]]) {
- maxPerColorThr[fcrow[j]] = v;
- }
- }
+ uint16_t v = brightest(x, y);
+ ++histogramsThr[fcrow[j]][v];
+ }
}
#pragma omp critical
{
- for(int c = 0; c < 4; ++c) {
- maxPerColor[c] = std::max(maxPerColorThr[c], maxPerColor[c]);
+ for (int c = 0; c < 4; ++c) {
+ for (int i = 0; i < histograms[c].size(); ++i) {
+ histograms[c][i] += histogramsThr[c][i];
+ }
+ }
+ }
+ }
+
+ uint16_t maxPerColor[4] = { 0, 0, 0, 0 };
+
+ for (int c = 0; c < 4; ++c) {
+ for (int i = histograms[c].size() - 1; i >= 0; --i) {
+ const size_t v = histograms[c][i];
+ if (v > width * height / 1000) {
+ maxPerColor[c] = i;
+ break;
}
}
}
@@ -93,9 +106,8 @@ void ImageStack::calculateSaturationLevel(const RawParameters & params, bool use
satThreshold = maxPerColor[c];
}
}
- if(!useCustomWl) // only scale when no custom white level was specified
- satThreshold *= 0.99;
- else
+
+ if(useCustomWl)
Log::debug( "Using custom white level ", params.max );
for (auto & i : images) {
@heckflosse Ingo, thanks!
:+1: for merge from me
@Floessie @heckflosse I compared d7afdb1 to d2efefd. Both the mask and the HDR DNG (when viewed in RT) look identical. +1 for merge.
@heckflosse @Beep6581 Thanks for testing! I hope you're not waiting for me to merge, as I don't have that permission.
@Floessie Oh, completely forgot that you don't have permission.
Hi,
This is a proposal (taken from and) for #126, which prevents outliers from defining what's the maximum per channel. Instead, the histogram is searched top to bottom for the first value covering more than one per mil of the brightest image.
Take this as a basis and not a final solution.
Best, Flössie