dehaze: speedup and changes requested by @Floessie in code review, #5456
This commit is contained in:
parent
204475dd05
commit
9cff2bca48
@ -16,7 +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 <https://www.gnu.org/licenses/>.
|
* along with RawTherapee. If not, see <https://www.gnu.org/licenses/>.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Haze removal using the algorithm described in the paper:
|
* Haze removal using the algorithm described in the paper:
|
||||||
@ -26,7 +26,7 @@
|
|||||||
*
|
*
|
||||||
* using a guided filter for the "soft matting" of the transmission map
|
* using a guided filter for the "soft matting" of the transmission map
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
@ -52,7 +52,7 @@ float normalize(Imagefloat *rgb, bool multithread)
|
|||||||
const int W = rgb->getWidth();
|
const int W = rgb->getWidth();
|
||||||
const int H = rgb->getHeight();
|
const int H = rgb->getHeight();
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
# pragma omp parallel for reduction(max:maxval) if (multithread)
|
#pragma omp parallel for reduction(max:maxval) schedule(dynamic, 16) if (multithread)
|
||||||
#endif
|
#endif
|
||||||
for (int y = 0; y < H; ++y) {
|
for (int y = 0; y < H; ++y) {
|
||||||
for (int x = 0; x < W; ++x) {
|
for (int x = 0; x < W; ++x) {
|
||||||
@ -61,7 +61,7 @@ float normalize(Imagefloat *rgb, bool multithread)
|
|||||||
}
|
}
|
||||||
maxval = max(maxval * 2.f, 65535.f);
|
maxval = max(maxval * 2.f, 65535.f);
|
||||||
#ifdef _OPENMP
|
#ifdef _OPENMP
|
||||||
# pragma omp parallel for if (multithread)
|
#pragma omp parallel for schedule(dynamic, 16) if (multithread)
|
||||||
#endif
|
#endif
|
||||||
for (int y = 0; y < H; ++y) {
|
for (int y = 0; y < H; ++y) {
|
||||||
for (int x = 0; x < W; ++x) {
|
for (int x = 0; x < W; ++x) {
|
||||||
@ -102,13 +102,36 @@ int get_dark_channel(const array2D<float> &R, const array2D<float> &G, const arr
|
|||||||
for (int y = 0; y < H; y += patchsize) {
|
for (int y = 0; y < H; y += patchsize) {
|
||||||
const int pH = min(y + patchsize, H);
|
const int pH = min(y + patchsize, H);
|
||||||
for (int x = 0; x < W; x += patchsize) {
|
for (int x = 0; x < W; x += patchsize) {
|
||||||
float val = RT_INFINITY_F;
|
float minR = RT_INFINITY_F;
|
||||||
|
float minG = RT_INFINITY_F;
|
||||||
|
float minB = RT_INFINITY_F;
|
||||||
|
#ifdef __SSE2__
|
||||||
|
vfloat minRv = F2V(minR);
|
||||||
|
vfloat minGv = F2V(minG);
|
||||||
|
vfloat minBv = F2V(minB);
|
||||||
|
#endif
|
||||||
const int pW = min(x + patchsize, W);
|
const int pW = min(x + patchsize, W);
|
||||||
for (int xx = x; xx < pW; ++xx) {
|
for (int yy = y; yy < pH; ++yy) {
|
||||||
for (int yy = y; yy < pH; ++yy) {
|
int xx = x;
|
||||||
val = min(val, R[yy][xx] / ambient[0], G[yy][xx] / ambient[1], B[yy][xx] / ambient[2]);
|
#ifdef __SSE2__
|
||||||
|
for (; xx < pW - 3; xx += 4) {
|
||||||
|
minRv = vminf(minRv, LVFU(R[yy][xx]));
|
||||||
|
minGv = vminf(minGv, LVFU(G[yy][xx]));
|
||||||
|
minBv = vminf(minBv, LVFU(B[yy][xx]));
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
for (; xx < pW; ++xx) {
|
||||||
|
minR = min(minR, R[yy][xx]);
|
||||||
|
minG = min(minG, G[yy][xx]);
|
||||||
|
minB = min(minB, B[yy][xx]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
#ifdef __SSE2__
|
||||||
|
minR = min(minR, vhmin(minRv));
|
||||||
|
minG = min(minG, vhmin(minGv));
|
||||||
|
minB = min(minB, vhmin(minBv));
|
||||||
|
#endif
|
||||||
|
float val = min(minR / ambient[0], minG / ambient[1], minB / ambient[2]);
|
||||||
val = 1.f - strength * LIM01(val);
|
val = 1.f - strength * LIM01(val);
|
||||||
for (int yy = y; yy < pH; ++yy) {
|
for (int yy = y; yy < pH; ++yy) {
|
||||||
std::fill(dst[yy] + x, dst[yy] + pW, val);
|
std::fill(dst[yy] + x, dst[yy] + pW, val);
|
||||||
@ -269,25 +292,25 @@ BENCHFUN
|
|||||||
|
|
||||||
int patchsize = max(int(5 / scale), 2);
|
int patchsize = max(int(5 / scale), 2);
|
||||||
float ambient[3];
|
float ambient[3];
|
||||||
float max_t = 0.f;
|
float maxDistance = 0.f;
|
||||||
|
|
||||||
{
|
{
|
||||||
array2D<float> R(W, H);
|
array2D<float>& R = dark; // R and dark can safely use the same buffer, which is faster and reduces memory allocations/deallocations
|
||||||
array2D<float> G(W, H);
|
array2D<float> G(W, H);
|
||||||
array2D<float> B(W, H);
|
array2D<float> B(W, H);
|
||||||
extract_channels(img, R, G, B, patchsize, 1e-1, multiThread);
|
extract_channels(img, R, G, B, patchsize, 1e-1, multiThread);
|
||||||
|
|
||||||
{
|
{
|
||||||
constexpr int sizecap = 200;
|
constexpr int sizecap = 200;
|
||||||
float r = float(W)/float(H);
|
const float r = static_cast<float>(W) / static_cast<float>(H);
|
||||||
const int hh = r >= 1.f ? sizecap : sizecap / r;
|
const int hh = r >= 1.f ? sizecap : sizecap / r;
|
||||||
const int ww = r >= 1.f ? sizecap * r : sizecap;
|
const int ww = r >= 1.f ? sizecap * r : sizecap;
|
||||||
|
|
||||||
if (W <= ww && H <= hh) {
|
if (W <= ww && H <= hh) {
|
||||||
// don't rescale small thumbs
|
// don't rescale small thumbs
|
||||||
array2D<float> D(W, H);
|
array2D<float> D(W, H);
|
||||||
int npatches = get_dark_channel_downsized(R, G, B, D, 2, multiThread);
|
const int npatches = get_dark_channel_downsized(R, G, B, D, 2, multiThread);
|
||||||
max_t = estimate_ambient_light(R, G, B, D, patchsize, npatches, ambient);
|
maxDistance = estimate_ambient_light(R, G, B, D, patchsize, npatches, ambient);
|
||||||
} else {
|
} else {
|
||||||
array2D<float> RR(ww, hh);
|
array2D<float> RR(ww, hh);
|
||||||
array2D<float> GG(ww, hh);
|
array2D<float> GG(ww, hh);
|
||||||
@ -297,8 +320,8 @@ BENCHFUN
|
|||||||
rescaleNearest(B, BB, multiThread);
|
rescaleNearest(B, BB, multiThread);
|
||||||
array2D<float> D(ww, hh);
|
array2D<float> D(ww, hh);
|
||||||
|
|
||||||
int npatches = get_dark_channel_downsized(RR, GG, BB, D, 2, multiThread);
|
const int npatches = get_dark_channel_downsized(RR, GG, BB, D, 2, multiThread);
|
||||||
max_t = estimate_ambient_light(RR, GG, BB, D, patchsize, npatches, ambient);
|
maxDistance = estimate_ambient_light(RR, GG, BB, D, patchsize, npatches, ambient);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -327,11 +350,11 @@ BENCHFUN
|
|||||||
guidedFilter(guideB, dark, dark, radius, epsilon, multiThread);
|
guidedFilter(guideB, dark, dark, radius, epsilon, multiThread);
|
||||||
|
|
||||||
if (options.rtSettings.verbose) {
|
if (options.rtSettings.verbose) {
|
||||||
std::cout << "dehaze: max distance is " << max_t << std::endl;
|
std::cout << "dehaze: max distance is " << maxDistance << std::endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
const float depth = -float(params->dehaze.depth) / 100.f;
|
const float depth = -float(params->dehaze.depth) / 100.f;
|
||||||
const float t0 = max(1e-3f, std::exp(depth * max_t));
|
const float t0 = max(1e-3f, std::exp(depth * maxDistance));
|
||||||
const float teps = 1e-3f;
|
const float teps = 1e-3f;
|
||||||
|
|
||||||
const bool luminance = params->dehaze.luminance;
|
const bool luminance = params->dehaze.luminance;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user