Moved findMinMaxPercentile() to rt_algo.*, use bool multiThread in fattal tonemapper, fixes #4195
This commit is contained in:
163
rtengine/rt_algo.cc
Normal file
163
rtengine/rt_algo.cc
Normal file
@@ -0,0 +1,163 @@
|
||||
/*
|
||||
* This file is part of RawTherapee.
|
||||
*
|
||||
* Copyright (c) 2017 Ingo Weyrich <heckflosse67@gmx.de>
|
||||
*
|
||||
* RawTherapee is free software: you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation, either version 3 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* RawTherapee is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include <cstddef>
|
||||
#include <cmath>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <cstdint>
|
||||
#ifdef _OPENMP
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
namespace rtengine
|
||||
{
|
||||
void findMinMaxPercentile (const float *data, size_t size, float minPrct, float& minOut, float maxPrct, float& maxOut, bool multithread)
|
||||
{
|
||||
// we need to find the (minPrct*size) smallest value and the (maxPrct*size) smallest value in data
|
||||
// We use a histogram based search for speed and to reduce memory usage
|
||||
// memory usage of this method is histoSize * sizeof(uint32_t) * (t + 1) byte,
|
||||
// where t is the number of threads and histoSize is in [1;65536]
|
||||
// The current implementation is not guaranteed to work correctly if size > 2^32 (4294967296)
|
||||
assert (minPrct <= maxPrct);
|
||||
|
||||
if(size == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
size_t numThreads = 1;
|
||||
#ifdef _OPENMP
|
||||
// Because we have an overhead in the critical region of the main loop for each thread
|
||||
// we make a rough calculation to reduce the number of threads for small data size
|
||||
// This also works fine for the minmax loop
|
||||
if(multithread) {
|
||||
size_t maxThreads = omp_get_max_threads();
|
||||
while (size > numThreads * numThreads * 16384 && numThreads < maxThreads) {
|
||||
++numThreads;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// We need min and max value of data to calculate the scale factor for the histogram
|
||||
float minVal = data[0];
|
||||
float maxVal = data[0];
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel for reduction(min:minVal) reduction(max:maxVal) num_threads(numThreads)
|
||||
#endif
|
||||
for (size_t i = 1; i < size; ++i) {
|
||||
minVal = std::min(minVal, data[i]);
|
||||
maxVal = std::max(maxVal, data[i]);
|
||||
}
|
||||
|
||||
if(std::fabs(maxVal - minVal) == 0.f) { // fast exit, also avoids division by zero in calculation of scale factor
|
||||
minOut = maxOut = minVal;
|
||||
return;
|
||||
}
|
||||
|
||||
// caution: currently this works correctly only for histoSize in range[1;65536]
|
||||
// for small data size (i.e. thumbnails) we reduce the size of the histogram to the size of data
|
||||
const unsigned int histoSize = std::min(static_cast<size_t>(65536), size);
|
||||
|
||||
// calculate scale factor to use full range of histogram
|
||||
const float scale = (histoSize - 1) / (maxVal - minVal);
|
||||
|
||||
// We need one main histogram
|
||||
std::vector<uint32_t> histo(histoSize, 0);
|
||||
|
||||
if(numThreads == 1) {
|
||||
// just one thread => use main histogram
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
// we have to subtract minVal and multiply with scale to get the data in [0;histosize] range
|
||||
histo[ (uint16_t) (scale * (data[i] - minVal))]++;
|
||||
}
|
||||
} else {
|
||||
#ifdef _OPENMP
|
||||
#pragma omp parallel num_threads(numThreads)
|
||||
#endif
|
||||
{
|
||||
// We need one histogram per thread
|
||||
std::vector<uint32_t> histothr(histoSize, 0);
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp for nowait
|
||||
#endif
|
||||
|
||||
for (size_t i = 0; i < size; ++i) {
|
||||
// we have to subtract minVal and multiply with scale to get the data in [0;histosize] range
|
||||
histothr[ (uint16_t) (scale * (data[i] - minVal))]++;
|
||||
}
|
||||
|
||||
#ifdef _OPENMP
|
||||
#pragma omp critical
|
||||
#endif
|
||||
{
|
||||
// add per thread histogram to main histogram
|
||||
#ifdef _OPENMP
|
||||
#pragma omp simd
|
||||
#endif
|
||||
|
||||
for(size_t i = 0; i < histoSize; ++i) {
|
||||
histo[i] += histothr[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
size_t k = 0;
|
||||
size_t count = 0;
|
||||
|
||||
// find (minPrct*size) smallest value
|
||||
const float threshmin = minPrct * size;
|
||||
while (count < threshmin) {
|
||||
count += histo[k++];
|
||||
}
|
||||
|
||||
if (k > 0) { // interpolate
|
||||
size_t count_ = count - histo[k - 1];
|
||||
float c0 = count - threshmin;
|
||||
float c1 = threshmin - count_;
|
||||
minOut = (c1 * k + c0 * (k - 1)) / (c0 + c1);
|
||||
} else {
|
||||
minOut = k;
|
||||
}
|
||||
// go back to original range
|
||||
minOut /= scale;
|
||||
minOut += minVal;
|
||||
|
||||
// find (maxPrct*size) smallest value
|
||||
const float threshmax = maxPrct * size;
|
||||
while (count < threshmax) {
|
||||
count += histo[k++];
|
||||
}
|
||||
|
||||
if (k > 0) { // interpolate
|
||||
size_t count_ = count - histo[k - 1];
|
||||
float c0 = count - threshmax;
|
||||
float c1 = threshmax - count_;
|
||||
maxOut = (c1 * k + c0 * (k - 1)) / (c0 + c1);
|
||||
} else {
|
||||
maxOut = k;
|
||||
}
|
||||
// go back to original range
|
||||
maxOut /= scale;
|
||||
maxOut += minVal;
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user