diff --git a/rtdata/languages/default b/rtdata/languages/default index 126b94f01..33d260c31 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1229,7 +1229,7 @@ HISTORY_MSG_981;Local - Log encoding Strength HISTORY_MSG_982;Local - Equalizer hue HISTORY_MSG_983;Local - denoise threshold mask high HISTORY_MSG_984;Local - denoise threshold mask low -HISTORY_MSG_985;Local - denoise use mask +HISTORY_MSG_985;Local - denoise Laplacian HISTORY_MSG_986;Local - denoise reinforce HISTORY_MSG_BLSHAPE;Blur by level HISTORY_MSG_BLURCWAV;Blur chroma @@ -2559,6 +2559,7 @@ TP_LOCALLAB_DENOI_EXP;Denoise TP_LOCALLAB_DENOI_TOOLTIP;This module can be used for noise reduction either on its own (at the end of the processing pipeline) or in addition to the Noise Reduction module in the Detail tab (which works at the beginning of the pipeline).\n Scope allows you to differentiate the action based on color (deltaE).\n\n You can refine the result with a "Median filter" or a "Guided Filter" (Soft radius). TP_LOCALLAB_DEPTH;Depth TP_LOCALLAB_DETAIL;Local contrast +TP_LOCALLAB_DETAILFRA;Edge detection TP_LOCALLAB_DETAILSH;Details TP_LOCALLAB_DETAILTHR;Luminance & chroma detail threshold (DCT ƒ) TP_LOCALLAB_DUPLSPOTNAME;Copy @@ -3024,7 +3025,7 @@ TP_LOCALLAB_TRANSIT_TOOLTIP;Adjust smoothness of transition between affected and TP_LOCALLAB_TRANSMISSIONGAIN;Transmission gain TP_LOCALLAB_TRANSMISSIONMAP;Transmission map TP_LOCALLAB_TRANSMISSION_TOOLTIP;Transmission according to transmission.\nAbscissa: transmission from negative values (min), mean, and positive values (max).\nOrdinate: amplification or reduction.\nYou can adjust this curve to change the Transmission and reduce artifacts -//TP_LOCALLAB_USEMASK;Use mask +TP_LOCALLAB_USEMASK;Laplacian TP_LOCALLAB_VART;Variance (contrast) TP_LOCALLAB_VIBRANCE;Vibrance & Warm/Cool TP_LOCALLAB_VIBRA_TOOLTIP;Adjusts vibrance (essentially the same as the global adjustment).\nCarries out the equivalent of a white-balance adjustment using a CIECAM algorithm. diff --git a/rtengine/boxblural.h b/rtengine/boxblural.h new file mode 100644 index 000000000..3504e92ab --- /dev/null +++ b/rtengine/boxblural.h @@ -0,0 +1,889 @@ +/* -*- C++ -*- + * + * This file is part of RawTherapee. + * + * Copyright (C) 2010 Emil Martinec + * + * 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 . + */ +#ifndef _BOXBLURAL_H_ +#define _BOXBLURAL_H_ + +#include +#include +#include +#include +#include +#include "alignedbuffer.h" +#include "rt_math.h" +#include "opthelper.h" +#include "StopWatch.h" + + +namespace rtengine +{ + +// classical filtering if the support window is small: + +template void boxblur (T** src, A** dst, int radx, int rady, int W, int H) +{ + //box blur image; box range = (radx,rady) + assert(2*radx+1 < W); + assert(2*rady+1 < H); + + AlignedBuffer* buffer = new AlignedBuffer (W * H); + float* temp = buffer->data; + + if (radx == 0) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + temp[row * W + col] = (float)src[row][col]; + } + } else { + //horizontal blur +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < H; row++) { + int len = radx + 1; + temp[row * W + 0] = (float)src[row][0] / len; + + for (int j = 1; j <= radx; j++) { + temp[row * W + 0] += (float)src[row][j] / len; + } + + for (int col = 1; col <= radx; col++) { + temp[row * W + col] = (temp[row * W + col - 1] * len + (float)src[row][col + radx]) / (len + 1); + len ++; + } + + for (int col = radx + 1; col < W - radx; col++) { + temp[row * W + col] = temp[row * W + col - 1] + ((float)(src[row][col + radx] - src[row][col - radx - 1])) / len; + } + + for (int col = W - radx; col < W; col++) { + temp[row * W + col] = (temp[row * W + col - 1] * len - src[row][col - radx - 1]) / (len - 1); + len --; + } + } + } + + if (rady == 0) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + dst[row][col] = temp[row * W + col]; + } + } else { + //vertical blur +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int col = 0; col < W; col++) { + int len = rady + 1; + dst[0][col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0][col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row][col] = (dst[(row - 1)][col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row][col] = dst[(row - 1)][col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row][col] = (dst[(row - 1)][col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + } + + delete buffer; + +} + +template void boxblur (T** src, A** dst, T* buffer, int radx, int rady, int W, int H) +{ + //box blur image; box range = (radx,rady) + + float* temp = buffer; + + if (radx == 0) { +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + temp[row * W + col] = (float)src[row][col]; + } + } else { + //horizontal blur +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 0; row < H; row++) { + float len = radx + 1; + float tempval = (float)src[row][0]; + + for (int j = 1; j <= radx; j++) { + tempval += (float)src[row][j]; + } + + tempval /= len; + temp[row * W + 0] = tempval; + + for (int col = 1; col <= radx; col++) { + temp[row * W + col] = tempval = (tempval * len + (float)src[row][col + radx]) / (len + 1); + len ++; + } + + for (int col = radx + 1; col < W - radx; col++) { + temp[row * W + col] = tempval = tempval + ((float)(src[row][col + radx] - src[row][col - radx - 1])) / len; + } + + for (int col = W - radx; col < W; col++) { + temp[row * W + col] = tempval = (tempval * len - src[row][col - radx - 1]) / (len - 1); + len --; + } + } + } + + if (rady == 0) { +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + dst[row][col] = temp[row * W + col]; + } + } else { + const int numCols = 8; // process numCols columns at once for better usage of L1 cpu cache +#ifdef __SSE2__ + vfloat leninitv = F2V( (float)(rady + 1)); + vfloat onev = F2V( 1.f ); + vfloat tempv, temp1v, lenv, lenp1v, lenm1v, rlenv; + +#ifdef _OPENMP + #pragma omp for +#endif + + for (int col = 0; col < W - 7; col += 8) { + lenv = leninitv; + tempv = LVFU(temp[0 * W + col]); + temp1v = LVFU(temp[0 * W + col + 4]); + + for (int i = 1; i <= rady; i++) { + tempv = tempv + LVFU(temp[i * W + col]); + temp1v = temp1v + LVFU(temp[i * W + col + 4]); + } + + tempv = tempv / lenv; + temp1v = temp1v / lenv; + STVFU(dst[0][col], tempv); + STVFU(dst[0][col + 4], temp1v); + + for (int row = 1; row <= rady; row++) { + lenp1v = lenv + onev; + tempv = (tempv * lenv + LVFU(temp[(row + rady) * W + col])) / lenp1v; + temp1v = (temp1v * lenv + LVFU(temp[(row + rady) * W + col + 4])) / lenp1v; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + lenv = lenp1v; + } + + rlenv = onev / lenv; + + for (int row = rady + 1; row < H - rady; row++) { + tempv = tempv + (LVFU(temp[(row + rady) * W + col]) - LVFU(temp[(row - rady - 1) * W + col])) * rlenv ; + temp1v = temp1v + (LVFU(temp[(row + rady) * W + col + 4]) - LVFU(temp[(row - rady - 1) * W + col + 4])) * rlenv ; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + } + + for (int row = H - rady; row < H; row++) { + lenm1v = lenv - onev; + tempv = (tempv * lenv - LVFU(temp[(row - rady - 1) * W + col])) / lenm1v; + temp1v = (temp1v * lenv - LVFU(temp[(row - rady - 1) * W + col + 4])) / lenm1v; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + lenv = lenm1v; + } + } + +#else + //vertical blur +#ifdef _OPENMP + #pragma omp for +#endif + + for (int col = 0; col < W - numCols + 1; col += 8) { + float len = rady + 1; + + for(int k = 0; k < numCols; k++) { + dst[0][col + k] = temp[0 * W + col + k]; + } + + for (int i = 1; i <= rady; i++) { + for(int k = 0; k < numCols; k++) { + dst[0][col + k] += temp[i * W + col + k]; + } + } + + for(int k = 0; k < numCols; k++) { + dst[0][col + k] /= len; + } + + for (int row = 1; row <= rady; row++) { + for(int k = 0; k < numCols; k++) { + dst[row][col + k] = (dst[(row - 1)][col + k] * len + temp[(row + rady) * W + col + k]) / (len + 1); + } + + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + for(int k = 0; k < numCols; k++) { + dst[row][col + k] = dst[(row - 1)][col + k] + (temp[(row + rady) * W + col + k] - temp[(row - rady - 1) * W + col + k]) / len; + } + } + + for (int row = H - rady; row < H; row++) { + for(int k = 0; k < numCols; k++) { + dst[row][col + k] = (dst[(row - 1)][col + k] * len - temp[(row - rady - 1) * W + col + k]) / (len - 1); + } + + len --; + } + } + +#endif +#ifdef _OPENMP + #pragma omp single +#endif + + for (int col = W - (W % numCols); col < W; col++) { + float len = rady + 1; + dst[0][col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0][col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row][col] = (dst[(row - 1)][col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row][col] = dst[(row - 1)][col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row][col] = (dst[(row - 1)][col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + } + +} + +inline void boxblur (float** src, float** dst, int radius, int W, int H, bool multiThread) +{ + //box blur using rowbuffers and linebuffers instead of a full size buffer + + if (radius == 0) { + if (src != dst) { +#ifdef _OPENMP + #pragma omp parallel for if (multiThread) +#endif + + for (int row = 0; row < H; row++) { + for (int col = 0; col < W; col++) { + dst[row][col] = src[row][col]; + } + } + } + return; + } + + constexpr int numCols = 8; // process numCols columns at once for better usage of L1 cpu cache +#ifdef _OPENMP + #pragma omp parallel if (multiThread) +#endif + { + std::unique_ptr buffer(new float[numCols * (radius + 1)]); + + //horizontal blur + float* const lineBuffer = buffer.get(); +// float* const lineBuffer = buffer; +#ifdef _OPENMP + #pragma omp for +#endif + for (int row = 0; row < H; row++) { + float len = radius + 1; + float tempval = src[row][0]; + lineBuffer[0] = tempval; + for (int j = 1; j <= radius; j++) { + tempval += src[row][j]; + } + + tempval /= len; + dst[row][0] = tempval; + + for (int col = 1; col <= radius; col++) { + lineBuffer[col] = src[row][col]; + tempval = (tempval * len + src[row][col + radius]) / (len + 1); + dst[row][col] = tempval; + ++len; + } + int pos = 0; + for (int col = radius + 1; col < W - radius; col++) { + const float oldVal = lineBuffer[pos]; + lineBuffer[pos] = src[row][col]; + dst[row][col] = tempval = tempval + (src[row][col + radius] - oldVal) / len; + ++pos; + pos = pos <= radius ? pos : 0; + } + + for (int col = W - radius; col < W; col++) { + dst[row][col] = tempval = (tempval * len - lineBuffer[pos]) / (len - 1); + --len; + ++pos; + pos = pos <= radius ? pos : 0; + } + } + + //vertical blur +#ifdef __SSE2__ + vfloat (* const rowBuffer)[2] = (vfloat(*)[2]) buffer.get(); + const vfloat leninitv = F2V(radius + 1); + const vfloat onev = F2V(1.f); + vfloat tempv, temp1v, lenv, lenp1v, lenm1v, rlenv; + +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int col = 0; col < W - 7; col += 8) { + lenv = leninitv; + tempv = LVFU(dst[0][col]); + temp1v = LVFU(dst[0][col + 4]); + rowBuffer[0][0] = tempv; + rowBuffer[0][1] = temp1v; + + for (int i = 1; i <= radius; i++) { + tempv = tempv + LVFU(dst[i][col]); + temp1v = temp1v + LVFU(dst[i][col + 4]); + } + + tempv = tempv / lenv; + temp1v = temp1v / lenv; + STVFU(dst[0][col], tempv); + STVFU(dst[0][col + 4], temp1v); + + for (int row = 1; row <= radius; row++) { + rowBuffer[row][0] = LVFU(dst[row][col]); + rowBuffer[row][1] = LVFU(dst[row][col + 4]); + lenp1v = lenv + onev; + tempv = (tempv * lenv + LVFU(dst[row + radius][col])) / lenp1v; + temp1v = (temp1v * lenv + LVFU(dst[row + radius][col + 4])) / lenp1v; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + lenv = lenp1v; + } + + rlenv = onev / lenv; + int pos = 0; + for (int row = radius + 1; row < H - radius; row++) { + vfloat oldVal0 = rowBuffer[pos][0]; + vfloat oldVal1 = rowBuffer[pos][1]; + rowBuffer[pos][0] = LVFU(dst[row][col]); + rowBuffer[pos][1] = LVFU(dst[row][col + 4]); + tempv = tempv + (LVFU(dst[row + radius][col]) - oldVal0) * rlenv ; + temp1v = temp1v + (LVFU(dst[row + radius][col + 4]) - oldVal1) * rlenv ; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + ++pos; + pos = pos <= radius ? pos : 0; + } + + for (int row = H - radius; row < H; row++) { + lenm1v = lenv - onev; + tempv = (tempv * lenv - rowBuffer[pos][0]) / lenm1v; + temp1v = (temp1v * lenv - rowBuffer[pos][1]) / lenm1v; + STVFU(dst[row][col], tempv); + STVFU(dst[row][col + 4], temp1v); + lenv = lenm1v; + ++pos; + pos = pos <= radius ? pos : 0; + } + } + +#else + float (* const rowBuffer)[8] = (float(*)[8]) buffer.get(); +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int col = 0; col < W - numCols + 1; col += 8) { + float len = radius + 1; + + for (int k = 0; k < numCols; k++) { + rowBuffer[0][k] = dst[0][col + k]; + } + + for (int i = 1; i <= radius; i++) { + for (int k = 0; k < numCols; k++) { + dst[0][col + k] += dst[i][col + k]; + } + } + + for(int k = 0; k < numCols; k++) { + dst[0][col + k] /= len; + } + + for (int row = 1; row <= radius; row++) { + for(int k = 0; k < numCols; k++) { + rowBuffer[row][k] = dst[row][col + k]; + dst[row][col + k] = (dst[row - 1][col + k] * len + dst[row + radius][col + k]) / (len + 1); + } + + len ++; + } + + int pos = 0; + for (int row = radius + 1; row < H - radius; row++) { + for(int k = 0; k < numCols; k++) { + float oldVal = rowBuffer[pos][k]; + rowBuffer[pos][k] = dst[row][col + k]; + dst[row][col + k] = dst[row - 1][col + k] + (dst[row + radius][col + k] - oldVal) / len; + } + ++pos; + pos = pos <= radius ? pos : 0; + } + + for (int row = H - radius; row < H; row++) { + for(int k = 0; k < numCols; k++) { + dst[row][col + k] = (dst[row - 1][col + k] * len - rowBuffer[pos][k]) / (len - 1); + } + len --; + ++pos; + pos = pos <= radius ? pos : 0; + } + } + +#endif + //vertical blur, remaining columns +#ifdef _OPENMP + #pragma omp single +#endif + { + const int remaining = W % numCols; + + if (remaining > 0) { + float (* const rowBuffer)[8] = (float(*)[8]) buffer.get(); + const int col = W - remaining; + + float len = radius + 1; + for(int k = 0; k < remaining; ++k) { + rowBuffer[0][k] = dst[0][col + k]; + } + for (int row = 1; row <= radius; ++row) { + for(int k = 0; k < remaining; ++k) { + dst[0][col + k] += dst[row][col + k]; + } + } + for(int k = 0; k < remaining; ++k) { + dst[0][col + k] /= len; + } + for (int row = 1; row <= radius; ++row) { + for(int k = 0; k < remaining; ++k) { + rowBuffer[row][k] = dst[row][col + k]; + dst[row][col + k] = (dst[row - 1][col + k] * len + dst[row + radius][col + k]) / (len + 1); + } + len ++; + } + const float rlen = 1.f / len; + int pos = 0; + for (int row = radius + 1; row < H - radius; ++row) { + for(int k = 0; k < remaining; ++k) { + float oldVal = rowBuffer[pos][k]; + rowBuffer[pos][k] = dst[row][col + k]; + dst[row][col + k] = dst[row - 1][col + k] + (dst[row + radius][col + k] - oldVal) * rlen; + } + ++pos; + pos = pos <= radius ? pos : 0; + } + for (int row = H - radius; row < H; ++row) { + for(int k = 0; k < remaining; ++k) { + dst[row][col + k] = (dst[(row - 1)][col + k] * len - rowBuffer[pos][k]) / (len - 1); + } + len --; + ++pos; + pos = pos <= radius ? pos : 0; + } + } + } + } +} + +template void boxblur (T* src, A* dst, A* buffer, int radx, int rady, int W, int H) +{ + //box blur image; box range = (radx,rady) i.e. box size is (2*radx+1)x(2*rady+1) + + float* temp = buffer; + + if (radx == 0) { + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + temp[row * W + col] = src[row * W + col]; + } + } else { + //horizontal blur + for (int row = H - 1; row >= 0; row--) { + int len = radx + 1; + float tempval = (float)src[row * W]; + + for (int j = 1; j <= radx; j++) { + tempval += (float)src[row * W + j]; + } + + tempval = tempval / len; + temp[row * W] = tempval; + + for (int col = 1; col <= radx; col++) { + tempval = (tempval * len + src[row * W + col + radx]) / (len + 1); + temp[row * W + col] = tempval; + len ++; + } + + float reclen = 1.f / len; + + for (int col = radx + 1; col < W - radx; col++) { + tempval = tempval + ((float)(src[row * W + col + radx] - src[row * W + col - radx - 1])) * reclen; + temp[row * W + col] = tempval; + } + + for (int col = W - radx; col < W; col++) { + tempval = (tempval * len - src[row * W + col - radx - 1]) / (len - 1); + temp[row * W + col] = tempval; + len --; + } + } + } + + if (rady == 0) { + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + dst[row * W + col] = temp[row * W + col]; + } + } else { + //vertical blur +#ifdef __SSE2__ + vfloat leninitv = F2V( (float)(rady + 1)); + vfloat onev = F2V( 1.f ); + vfloat tempv, temp1v, lenv, lenp1v, lenm1v, rlenv; + int col; + + for (col = 0; col < W - 7; col += 8) { + lenv = leninitv; + tempv = LVFU(temp[0 * W + col]); + temp1v = LVFU(temp[0 * W + col + 4]); + + for (int i = 1; i <= rady; i++) { + tempv = tempv + LVFU(temp[i * W + col]); + temp1v = temp1v + LVFU(temp[i * W + col + 4]); + } + + tempv = tempv / lenv; + temp1v = temp1v / lenv; + STVFU(dst[0 * W + col], tempv); + STVFU(dst[0 * W + col + 4], temp1v); + + for (int row = 1; row <= rady; row++) { + lenp1v = lenv + onev; + tempv = (tempv * lenv + LVFU(temp[(row + rady) * W + col])) / lenp1v; + temp1v = (temp1v * lenv + LVFU(temp[(row + rady) * W + col + 4])) / lenp1v; + STVFU(dst[row * W + col], tempv); + STVFU(dst[row * W + col + 4], temp1v); + lenv = lenp1v; + } + + rlenv = onev / lenv; + + for (int row = rady + 1; row < H - rady; row++) { + tempv = tempv + (LVFU(temp[(row + rady) * W + col]) - LVFU(temp[(row - rady - 1) * W + col])) * rlenv ; + temp1v = temp1v + (LVFU(temp[(row + rady) * W + col + 4]) - LVFU(temp[(row - rady - 1) * W + col + 4])) * rlenv ; + STVFU(dst[row * W + col], tempv); + STVFU(dst[row * W + col + 4], temp1v); + } + + for (int row = H - rady; row < H; row++) { + lenm1v = lenv - onev; + tempv = (tempv * lenv - LVFU(temp[(row - rady - 1) * W + col])) / lenm1v; + temp1v = (temp1v * lenv - LVFU(temp[(row - rady - 1) * W + col + 4])) / lenm1v; + STVFU(dst[row * W + col], tempv); + STVFU(dst[row * W + col + 4], temp1v); + lenv = lenm1v; + } + } + + for (; col < W - 3; col += 4) { + lenv = leninitv; + tempv = LVFU(temp[0 * W + col]); + + for (int i = 1; i <= rady; i++) { + tempv = tempv + LVFU(temp[i * W + col]); + } + + tempv = tempv / lenv; + STVFU(dst[0 * W + col], tempv); + + for (int row = 1; row <= rady; row++) { + lenp1v = lenv + onev; + tempv = (tempv * lenv + LVFU(temp[(row + rady) * W + col])) / lenp1v; + STVFU(dst[row * W + col], tempv); + lenv = lenp1v; + } + + rlenv = onev / lenv; + + for (int row = rady + 1; row < H - rady; row++) { + tempv = tempv + (LVFU(temp[(row + rady) * W + col]) - LVFU(temp[(row - rady - 1) * W + col])) * rlenv ; + STVFU(dst[row * W + col], tempv); + } + + for (int row = H - rady; row < H; row++) { + lenm1v = lenv - onev; + tempv = (tempv * lenv - LVFU(temp[(row - rady - 1) * W + col])) / lenm1v; + STVFU(dst[row * W + col], tempv); + lenv = lenm1v; + } + } + + for (; col < W; col++) { + int len = rady + 1; + dst[0 * W + col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0 * W + col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row * W + col] = dst[(row - 1) * W + col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + +#else + + for (int col = 0; col < W; col++) { + int len = rady + 1; + dst[0 * W + col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0 * W + col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row * W + col] = dst[(row - 1) * W + col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + +#endif + } + +} + +template void boxabsblur (T* src, A* dst, int radx, int rady, int W, int H, float * temp) +{ + + //%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% + //box blur image; box range = (radx,rady) i.e. box size is (2*radx+1)x(2*rady+1) + + if (radx == 0) { + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + temp[row * W + col] = fabs(src[row * W + col]); + } + } else { + //horizontal blur + for (int row = 0; row < H; row++) { + int len = radx + 1; + float tempval = fabsf((float)src[row * W + 0]); + + for (int j = 1; j <= radx; j++) { + tempval += fabsf((float)src[row * W + j]); + } + + tempval /= len; + temp[row * W + 0] = tempval; + + for (int col = 1; col <= radx; col++) { + tempval = (tempval * len + fabsf(src[row * W + col + radx])) / (len + 1); + temp[row * W + col] = tempval; + len ++; + } + + float rlen = 1.f / (float)len; + + for (int col = radx + 1; col < W - radx; col++) { + tempval = tempval + ((float)(fabsf(src[row * W + col + radx]) - fabsf(src[row * W + col - radx - 1]))) * rlen; + temp[row * W + col] = tempval; + } + + for (int col = W - radx; col < W; col++) { + tempval = (tempval * len - fabsf(src[row * W + col - radx - 1])) / (len - 1); + temp[row * W + col] = tempval; + len --; + } + } + } + + if (rady == 0) { + for (int row = 0; row < H; row++) + for (int col = 0; col < W; col++) { + dst[row * W + col] = temp[row * W + col]; + } + } else { + //vertical blur +#ifdef __SSE2__ + vfloat leninitv = F2V( (float)(rady + 1)); + vfloat onev = F2V( 1.f ); + vfloat tempv, lenv, lenp1v, lenm1v, rlenv; + + for (int col = 0; col < W - 3; col += 4) { + lenv = leninitv; + tempv = LVF(temp[0 * W + col]); + + for (int i = 1; i <= rady; i++) { + tempv = tempv + LVF(temp[i * W + col]); + } + + tempv = tempv / lenv; + STVF(dst[0 * W + col], tempv); + + for (int row = 1; row <= rady; row++) { + lenp1v = lenv + onev; + tempv = (tempv * lenv + LVF(temp[(row + rady) * W + col])) / lenp1v; + STVF(dst[row * W + col], tempv); + lenv = lenp1v; + } + + rlenv = onev / lenv; + + for (int row = rady + 1; row < H - rady; row++) { + tempv = tempv + (LVF(temp[(row + rady) * W + col]) - LVF(temp[(row - rady - 1) * W + col])) * rlenv; + STVF(dst[row * W + col], tempv); + } + + for (int row = H - rady; row < H; row++) { + lenm1v = lenv - onev; + tempv = (tempv * lenv - LVF(temp[(row - rady - 1) * W + col])) / lenm1v; + STVF(dst[row * W + col], tempv); + lenv = lenm1v; + } + } + + for (int col = W - (W % 4); col < W; col++) { + int len = rady + 1; + dst[0 * W + col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0 * W + col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row * W + col] = dst[(row - 1) * W + col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + +#else + + for (int col = 0; col < W; col++) { + int len = rady + 1; + dst[0 * W + col] = temp[0 * W + col] / len; + + for (int i = 1; i <= rady; i++) { + dst[0 * W + col] += temp[i * W + col] / len; + } + + for (int row = 1; row <= rady; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len + temp[(row + rady) * W + col]) / (len + 1); + len ++; + } + + for (int row = rady + 1; row < H - rady; row++) { + dst[row * W + col] = dst[(row - 1) * W + col] + (temp[(row + rady) * W + col] - temp[(row - rady - 1) * W + col]) / len; + } + + for (int row = H - rady; row < H; row++) { + dst[row * W + col] = (dst[(row - 1) * W + col] * len - temp[(row - rady - 1) * W + col]) / (len - 1); + len --; + } + } + +#endif + } + +} + +} +#endif /* _BOXBLUR_H_ */ diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index f9ec00469..375d506ce 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -372,7 +372,7 @@ public: void DeNoise(int call, float * slidL, float * slida, float * slidb, int aut, bool noiscfactiv, const struct local_params& lp, LabImage* originalmaskbl, LabImage * bufmaskblurbl, int levred, float huerefblur, float lumarefblur, float chromarefblur, LabImage* original, LabImage* transformed, int cx, int cy, int sk, const LocwavCurve& locwavCurvehue, bool locwavhueutili); - void fftw_denoise(int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom); + void fftw_denoise(int sk, int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom); void ColorLight_Local(float moddE, float powdE, int call, LabImage * bufcolorig, LabImage * originalmask, float **buflight, float **bufchro, float **bufchroslid, float ** bufhh, float ** buflightslid, bool &LHutili, bool &HHutili, const float hueplus, const float huemoins, const float hueref, const float dhue, const float chromaref, const float lumaref, float sobelref, float ** blend2, LUTf & lllocalcurve, const LocLHCurve & loclhCurve, const LocHHCurve & lochhCurve, LUTf & lightCurveloc, const local_params& lp, LabImage* original, LabImage* transformed, int cx, int cy, int sk); void InverseColorLight_Local(bool tonequ, bool tonecurv, int sp, int senstype, struct local_params& lp, LabImage * originalmask, const LUTf& lightCurveloc, const LUTf& hltonecurveloc, const LUTf& shtonecurveloc, const LUTf& tonecurveloc, const LUTf& exlocalcurve, const LUTf& cclocalcurve, float adjustr, bool localcutili, const LUTf& lllocalcurve, bool locallutili, LabImage* original, LabImage* transformed, int cx, int cy, const float hueref, const float chromaref, const float lumaref, int sk); diff --git a/rtengine/iplocallab.cc b/rtengine/iplocallab.cc index 203efacad..ab58e88c0 100644 --- a/rtengine/iplocallab.cc +++ b/rtengine/iplocallab.cc @@ -49,6 +49,7 @@ #define BENCHMARK #include "StopWatch.h" #include "guidedfilter.h" +#include "boxblural.h" #pragma GCC diagnostic warning "-Wall" @@ -250,6 +251,8 @@ float calcreducdE(float dE, float maxdE, float mindE, float maxdElim, float mind } } + + void deltaEforLaplace(float *dE, const float lap, int bfw, int bfh, rtengine::LabImage* bufexporig, const float hueref, const float chromaref, const float lumaref) { @@ -659,7 +662,7 @@ struct local_params { bool activspot; float thrlow; float thrhigh; - // bool usemask; + bool usemask; float lnoiselow; }; @@ -780,7 +783,7 @@ static void calcLocalParams(int sp, int oW, int oH, const LocallabParams& locall lp.thrlow = locallab.spots.at(sp).levelthrlow; lp.thrhigh = locallab.spots.at(sp).levelthr; - // lp.usemask = locallab.spots.at(sp).usemask; + lp.usemask = locallab.spots.at(sp).usemask; lp.lnoiselow = locallab.spots.at(sp).lnoiselow; // printf("llColorMask=%i lllcMask=%i llExpMask=%i llSHMask=%i llcbMask=%i llretiMask=%i lltmMask=%i llblMask=%i llvibMask=%i\n", llColorMask, lllcMask, llExpMask, llSHMask, llcbMask, llretiMask, lltmMask, llblMask, llvibMask); @@ -3886,6 +3889,48 @@ static void showmask(int lumask, const local_params& lp, int xstart, int ystart, } } } +//from A.Griggio...very similar to discrete_laplacian_threhold...some differences with ceiling and data format +void laplacian(const array2D &src, array2D &dst, int bfw, int bfh, float threshold, float ceiling, float factor, bool multiThread) +{ + const int W = bfw; + const int H = bfh; + + const auto X = + [W](int x) -> int + { + return x < 0 ? x+2 : (x >= W ? x-2 : x); + }; + + const auto Y = + [H](int y) -> int + { + return y < 0 ? y+2 : (y >= H ? y-2 : y); + }; + + const auto get = + [&src](int y, int x) -> float + { + return std::max(src[y][x], 0.f); + }; + + dst(W, H); + const float f = factor / ceiling; + +#ifdef _OPENMP +# pragma omp parallel for if (multiThread) +#endif + for (int y = 0; y < H; ++y) { + int n = Y(y-1), s = Y(y+1); + for (int x = 0; x < W; ++x) { + int w = X(x-1), e = X(x+1); + float v = -8.f * get(y, x) + get(n, x) + get(s, x) + get(y, w) + get(y, e) + get(n, w) + get(n, e) + get(s, w) + get(s, e); + dst[y][x] = LIM(std::abs(v) - threshold, 0.f, ceiling) * f; + } + } +} + + + void ImProcFunctions::discrete_laplacian_threshold(float * data_out, const float * data_in, size_t nx, size_t ny, float t) { @@ -8412,7 +8457,7 @@ void ImProcFunctions::wavcontrast4(struct local_params& lp, float ** tmp, float } -void ImProcFunctions::fftw_denoise(int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom) +void ImProcFunctions::fftw_denoise(int sk, int GW, int GH, int max_numblox_W, int min_numblox_W, float **tmp1, array2D *Lin, int numThreads, const struct local_params & lp, int chrom) { // BENCHFUN @@ -8596,30 +8641,51 @@ void ImProcFunctions::fftw_denoise(int GW, int GH, int max_numblox_W, int min_nu }//end of vertical block loop } - //Threshold DCT from Alberto Grigio + //Threshold DCT from Alberto Grigio, adapted to Rawtherapee const int detail_thresh = lp.detailthr; array2D mask; if (detail_thresh > 0) { mask(GW, GH); - float thr = log2lin(float(detail_thresh) / 200.f, 100.f); - buildBlendMask(prov, mask, GW, GH, thr); + if (lp.usemask) {//with Laplacian + float amount = LIM01(float(detail_thresh)/100.f); + float thr = (1.f - amount); + float alph = params_Ldetail / 100.f; + array2D LL(GW, GH, prov, ARRAY2D_BYREFERENCE); + laplacian(LL, mask, GW, GH, 25.f, 20000.f, amount, false); + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + mask[i][j] = LIM01(mask[i][j]+ thr); + } + } + for (int i = 0; i < 3; ++i) { + boxblur(mask, mask, 10 / sk, GW, GH, false); + } + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + float k = 1.f - mask[i][j] * alph; + mask[i][j] = 1.f - (k * k); + } + } + } else {//with blend mask + float thr = log2lin(float(detail_thresh) / 200.f, 100.f); + buildBlendMask(prov, mask, GW, GH, thr); #ifdef _OPENMP #pragma omp parallel if (multiThread) #endif - { - gaussianBlur(mask, mask, GW, GH, 20.0); - } - array2D m2(GW, GH); - constexpr float alfa = 0.856f; - const float beta = 1.f + std::sqrt(log2lin(thr, 100.f)); - buildGradientsMask(GW, GH, prov, m2, params_Ldetail / 100.f, 7, 3, alfa, beta, multiThread); - - for (int i = 0; i < GH; ++i) { - for (int j = 0; j < GW; ++j) { - mask[i][j] *= m2[i][j]; + { + gaussianBlur(mask, mask, GW, GH, 20.0 / sk); } - } + array2D m2(GW, GH); + constexpr float alfa = 0.856f; + const float beta = 1.f + std::sqrt(log2lin(thr, 100.f)); + buildGradientsMask(GW, GH, prov, m2, params_Ldetail / 100.f, 7, 3, alfa, beta, multiThread); + for (int i = 0; i < GH; ++i) { + for (int j = 0; j < GW; ++j) { + mask[i][j] *= m2[i][j]; + } + } + } } @@ -9233,7 +9299,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!Ldecomp.memory_allocation_failed() && aut == 0) { if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f) { - fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.L, Lin, numThreads, lp, 0); + fftw_denoise(sk, GW, GH, max_numblox_W, min_numblox_W, tmp1.L, Lin, numThreads, lp, 0); } } @@ -9254,7 +9320,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!adecomp.memory_allocation_failed() && aut == 0) { if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { - fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.a, Ain, numThreads, lp, 1); + fftw_denoise(sk, GW, GH, max_numblox_W, min_numblox_W, tmp1.a, Ain, numThreads, lp, 1); } } @@ -9277,7 +9343,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!bdecomp.memory_allocation_failed() && aut == 0) { if ((lp.noisecf >= 0.01f || lp.noisecc >= 0.01f) && levred == 7 && lp.noisechrodetail != 100.f) { - fftw_denoise(GW, GH, max_numblox_W, min_numblox_W, tmp1.b, Bin, numThreads, lp, 1); + fftw_denoise(sk, GW, GH, max_numblox_W, min_numblox_W, tmp1.b, Bin, numThreads, lp, 1); } } @@ -9835,7 +9901,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if ((lp.noiself >= 0.01f || lp.noiself0 >= 0.01f || lp.noiself2 >= 0.01f || lp.noiselc >= 0.01f) && levred == 7 && lp.noiseldetail != 100.f) { - fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.L, Lin, numThreads, lp, 0); + fftw_denoise(sk, bfw, bfh, max_numblox_W, min_numblox_W, bufwv.L, Lin, numThreads, lp, 0); } } @@ -9856,7 +9922,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!adecomp.memory_allocation_failed() && aut == 0) { if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { - fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.a, Ain, numThreads, lp, 1); + fftw_denoise(sk, bfw, bfh, max_numblox_W, min_numblox_W, bufwv.a, Ain, numThreads, lp, 1); } } @@ -9877,7 +9943,7 @@ void ImProcFunctions::DeNoise(int call, float * slidL, float * slida, float * sl if (!bdecomp.memory_allocation_failed() && aut == 0) { if ((lp.noisecf >= 0.001f || lp.noisecc >= 0.001f) && levred == 7 && lp.noisechrodetail != 100.f) { - fftw_denoise(bfw, bfh, max_numblox_W, min_numblox_W, bufwv.b, Bin, numThreads, lp, 1); + fftw_denoise(sk, bfw, bfh, max_numblox_W, min_numblox_W, bufwv.b, Bin, numThreads, lp, 1); } } diff --git a/rtengine/procevents.h b/rtengine/procevents.h index 7da7d1d98..aae82f3b9 100644 --- a/rtengine/procevents.h +++ b/rtengine/procevents.h @@ -1007,8 +1007,8 @@ enum ProcEventCode { EvlocallabwavCurvehue = 981, Evlocallablevelthr = 982, Evlocallablevelthrlow = 983, - // Evlocallabusemask1 = 984, - Evlocallablnoiselow = 984, + Evlocallabusemask1 = 984, + Evlocallablnoiselow = 985, NUMOFEVENTS }; diff --git a/rtengine/procparams.cc b/rtengine/procparams.cc index e4d2852d3..64374f4c3 100644 --- a/rtengine/procparams.cc +++ b/rtengine/procparams.cc @@ -3307,7 +3307,7 @@ LocallabParams::LocallabSpot::LocallabSpot() : quamethod("cons"), blurMethod("norm"), medMethod("33"), - // usemask(false), + usemask(false), levelthr(40.), lnoiselow(1.), levelthrlow(12.), @@ -4350,7 +4350,7 @@ bool LocallabParams::LocallabSpot::operator ==(const LocallabSpot& other) const && chroMethod == other.chroMethod && quamethod == other.quamethod && blurMethod == other.blurMethod - // && usemask == other.usemask + && usemask == other.usemask && levelthr == other.levelthr && lnoiselow == other.lnoiselow && levelthrlow == other.levelthrlow @@ -5936,7 +5936,7 @@ int ProcParams::save(const Glib::ustring& fname, const Glib::ustring& fname2, bo saveToKeyfile(!pedited || spot_edited->chroMethod, "Locallab", "ChroMethod_" + index_str, spot.chroMethod, keyFile); saveToKeyfile(!pedited || spot_edited->quamethod, "Locallab", "QuaMethod_" + index_str, spot.quamethod, keyFile); saveToKeyfile(!pedited || spot_edited->blurMethod, "Locallab", "BlurMethod_" + index_str, spot.blurMethod, keyFile); - // saveToKeyfile(!pedited || spot_edited->usemask, "Locallab", "Usemaskb_" + index_str, spot.usemask, keyFile); + saveToKeyfile(!pedited || spot_edited->usemask, "Locallab", "Usemaskb_" + index_str, spot.usemask, keyFile); saveToKeyfile(!pedited || spot_edited->levelthr, "Locallab", "Levelthr_" + index_str, spot.levelthr, keyFile); saveToKeyfile(!pedited || spot_edited->lnoiselow, "Locallab", "Lnoiselow_" + index_str, spot.lnoiselow, keyFile); saveToKeyfile(!pedited || spot_edited->levelthrlow, "Locallab", "Levelthrlow_" + index_str, spot.levelthrlow, keyFile); @@ -7738,7 +7738,7 @@ int ProcParams::load(const Glib::ustring& fname, ParamsEdited* pedited) assignFromKeyfile(keyFile, "Locallab", "ChroMethod_" + index_str, pedited, spot.chroMethod, spotEdited.chroMethod); assignFromKeyfile(keyFile, "Locallab", "QuaMethod_" + index_str, pedited, spot.quamethod, spotEdited.quamethod); assignFromKeyfile(keyFile, "Locallab", "BlurMethod_" + index_str, pedited, spot.blurMethod, spotEdited.blurMethod); - // assignFromKeyfile(keyFile, "Locallab", "Usemaskb_" + index_str, pedited, spot.usemask, spotEdited.usemask); + assignFromKeyfile(keyFile, "Locallab", "Usemaskb_" + index_str, pedited, spot.usemask, spotEdited.usemask); assignFromKeyfile(keyFile, "Locallab", "Levelthr_" + index_str, pedited, spot.levelthr, spotEdited.levelthr); assignFromKeyfile(keyFile, "Locallab", "Lnoiselow_" + index_str, pedited, spot.lnoiselow, spotEdited.lnoiselow); assignFromKeyfile(keyFile, "Locallab", "Levelthrlow_" + index_str, pedited, spot.levelthrlow, spotEdited.levelthrlow); diff --git a/rtengine/procparams.h b/rtengine/procparams.h index 295099098..b5e241f51 100644 --- a/rtengine/procparams.h +++ b/rtengine/procparams.h @@ -1214,7 +1214,7 @@ struct LocallabParams { Glib::ustring quamethod; // cons agre Glib::ustring blurMethod; // norm, inv Glib::ustring medMethod; // none, 33, 55, 77, 99 - // bool usemask; + bool usemask; double levelthr; double lnoiselow; double levelthrlow; diff --git a/rtengine/refreshmap.cc b/rtengine/refreshmap.cc index 923763770..129afdca9 100644 --- a/rtengine/refreshmap.cc +++ b/rtengine/refreshmap.cc @@ -1011,7 +1011,7 @@ int refreshmap[rtengine::NUMOFEVENTS] = { LUMINANCECURVE, //EvlocallabwavCurvehue LUMINANCECURVE, // Evlocallablevelthr LUMINANCECURVE, // Evlocallablevelthrlow - // LUMINANCECURVE, //Evlocallabusemask1 + LUMINANCECURVE, //Evlocallabusemask1 LUMINANCECURVE // Evlocallablnoiselow }; diff --git a/rtgui/locallabtools.cc b/rtgui/locallabtools.cc index 7bb65348a..97fa9111d 100644 --- a/rtgui/locallabtools.cc +++ b/rtgui/locallabtools.cc @@ -5763,7 +5763,7 @@ LocallabBlur::LocallabBlur(): expdenoise1(Gtk::manage(new MyExpander(false, M("TP_LOCALLAB_DENOI1_EXP")))), maskusable(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUSABLE")))), maskunusable(Gtk::manage(new Gtk::Label(M("TP_LOCALLAB_MASKUNUSABLE")))), -// usemask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_USEMASK")))), + usemask(Gtk::manage(new Gtk::CheckButton(M("TP_LOCALLAB_USEMASK")))), lnoiselow(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLNOISELOW"), 0.7, 2., 0.01, 1.))), levelthr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHR"), 10., 100., 1., 40.))), levelthrlow(Gtk::manage(new Adjuster(M("TP_LOCALLAB_MASKLCTHRLOW"), 1., 100., 1., 12.))), @@ -5778,6 +5778,7 @@ LocallabBlur::LocallabBlur(): noisechrof(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROFINE"), MINCHRO, MAXCHRO, 0.01, 0.))), noisechroc(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHROCOARSE"), MINCHRO, MAXCHROCC, 0.01, 0.))), noisechrodetail(Gtk::manage(new Adjuster(M("TP_LOCALLAB_NOISECHRODETAIL"), 0., 100., 0.01, 50.))), + detailFrame(Gtk::manage(new Gtk::Frame(M("TP_LOCALLAB_DETAILFRA")))), detailthr(Gtk::manage(new Adjuster(M("TP_LOCALLAB_DETAILTHR"), 0, 100, 1, 50))), adjblur(Gtk::manage(new Adjuster(M("TP_LOCALLAB_ADJ"), -100., 100., 1., 0., Gtk::manage(new RTImage("circle-blue-yellow-small.png")), Gtk::manage(new RTImage("circle-red-green-small.png"))))), bilateral(Gtk::manage(new Adjuster(M("TP_LOCALLAB_BILATERAL"), 0, 100, 1, 0))), @@ -5829,7 +5830,7 @@ LocallabBlur::LocallabBlur(): blMethodConn = blMethod->signal_changed().connect(sigc::mem_fun(*this, &LocallabBlur::blMethodChanged)); fftwblConn = fftwbl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::fftwblChanged)); - // usemaskConn = usemask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::usemaskChanged)); + usemaskConn = usemask->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::usemaskChanged)); invblConn = invbl->signal_toggled().connect(sigc::mem_fun(*this, &LocallabBlur::invblChanged)); radius->setAdjusterListener(this); @@ -5931,6 +5932,7 @@ LocallabBlur::LocallabBlur(): noisechrodetail->setAdjusterListener(this); + detailFrame->set_label_align(0.025, 0.5); detailthr->setAdjusterListener(this); adjblur->setAdjusterListener(this); @@ -6057,7 +6059,6 @@ LocallabBlur::LocallabBlur(): wavBox->pack_start(*noiselequal); wavBox->pack_start(*LocalcurveEditorwavhue, Gtk::PACK_SHRINK, 4); ToolParamBlock* const wavBox1 = Gtk::manage(new ToolParamBlock()); - // wavBox1->pack_start(*usemask, Gtk::PACK_SHRINK, 0); wavBox1->pack_start(*maskusable, Gtk::PACK_SHRINK, 0); wavBox1->pack_start(*maskunusable, Gtk::PACK_SHRINK, 0); wavBox1->pack_start(*lnoiselow, Gtk::PACK_SHRINK, 0); @@ -6068,8 +6069,12 @@ LocallabBlur::LocallabBlur(): wavBox->pack_start(*noisechrof); wavBox->pack_start(*noisechroc); wavBox->pack_start(*noisechrodetail); - wavBox->pack_start(*detailthr); wavBox->pack_start(*adjblur); + ToolParamBlock* const detailBox = Gtk::manage(new ToolParamBlock()); + detailBox->pack_start(*detailthr); + detailBox->pack_start(*usemask, Gtk::PACK_SHRINK, 0); + detailFrame->add(*detailBox); + wavBox->pack_start(*detailFrame); wavFrame->add(*wavBox); denoisebox->pack_start(*wavFrame); denoisebox->pack_start(*bilateral); @@ -6260,6 +6265,7 @@ void LocallabBlur::neutral_pressed () quamethod->set_active (0); wavshapeden->setCurve(defSpot.locwavcurveden); wavhue->setCurve(defSpot.locwavcurvehue); + usemask->set_active(defSpot.usemask); } void LocallabBlur::setDefaultExpanderVisibility() @@ -6276,7 +6282,7 @@ void LocallabBlur::disableListener() blMethodConn.block(true); fftwblConn.block(true); - // usemaskConn.block(true); + usemaskConn.block(true); invblConn.block(true); medMethodConn.block(true); blurMethodConn.block(true); @@ -6295,7 +6301,7 @@ void LocallabBlur::enableListener() blMethodConn.block(false); fftwblConn.block(false); - // usemaskConn.block(false); + usemaskConn.block(false); invblConn.block(false); medMethodConn.block(false); blurMethodConn.block(false); @@ -6334,7 +6340,7 @@ void LocallabBlur::read(const rtengine::procparams::ProcParams* pp, const Params } fftwbl->set_active(spot.fftwbl); - // usemask->set_active(spot.usemask); + usemask->set_active(spot.usemask); invbl->set_active(spot.invbl); radius->setValue(spot.radius); strength->setValue(spot.strength); @@ -6459,7 +6465,7 @@ void LocallabBlur::write(rtengine::procparams::ProcParams* pp, ParamsEdited* ped } spot.fftwbl = fftwbl->get_active(); - // spot.usemask = usemask->get_active(); + spot.usemask = usemask->get_active(); spot.invbl = invbl->get_active(); spot.radius = radius->getValue(); spot.strength = strength->getIntValue(); @@ -6994,7 +7000,7 @@ void LocallabBlur::convertParamToSimple() levelthr->setValue(defSpot.levelthr); lnoiselow->setValue(defSpot.lnoiselow); levelthrlow->setValue(defSpot.levelthrlow); - // usemask->set_active(defSpot.usemask); + usemask->set_active(defSpot.usemask); // Enable all listeners enableListener(); @@ -7130,7 +7136,7 @@ void LocallabBlur::fftwblChanged() } } } -/* + void LocallabBlur::usemaskChanged() { if (isLocActivated && exp->getEnabled()) { @@ -7145,7 +7151,7 @@ void LocallabBlur::usemaskChanged() } } } -*/ + void LocallabBlur::invblChanged() { const LocallabParams::LocallabSpot defSpot; diff --git a/rtgui/locallabtools.h b/rtgui/locallabtools.h index 1eaaa94bd..7b3b6cb47 100644 --- a/rtgui/locallabtools.h +++ b/rtgui/locallabtools.h @@ -667,7 +667,7 @@ private: Gtk::Label* const maskusable; Gtk::Label* const maskunusable; -// Gtk::CheckButton* const usemask; + Gtk::CheckButton* const usemask; Adjuster* const lnoiselow; Adjuster* const levelthr; Adjuster* const levelthrlow; @@ -682,6 +682,7 @@ private: Adjuster* const noisechrof; Adjuster* const noisechroc; Adjuster* const noisechrodetail; + Gtk::Frame* const detailFrame; Adjuster* const detailthr; Adjuster* const adjblur; Adjuster* const bilateral; diff --git a/rtgui/paramsedited.cc b/rtgui/paramsedited.cc index 6c3716a91..6cd2c93e5 100644 --- a/rtgui/paramsedited.cc +++ b/rtgui/paramsedited.cc @@ -1284,7 +1284,7 @@ void ParamsEdited::initFrom(const std::vector& locallab.spots.at(j).chroMethod = locallab.spots.at(j).chroMethod && pSpot.chroMethod == otherSpot.chroMethod; locallab.spots.at(j).quamethod = locallab.spots.at(j).quamethod && pSpot.quamethod == otherSpot.quamethod; locallab.spots.at(j).blurMethod = locallab.spots.at(j).blurMethod && pSpot.blurMethod == otherSpot.blurMethod; - // locallab.spots.at(j).usemask = locallab.spots.at(j).usemask && pSpot.usemask == otherSpot.usemask; + locallab.spots.at(j).usemask = locallab.spots.at(j).usemask && pSpot.usemask == otherSpot.usemask; locallab.spots.at(j).levelthr = locallab.spots.at(j).levelthr && pSpot.levelthr == otherSpot.levelthr; locallab.spots.at(j).lnoiselow = locallab.spots.at(j).lnoiselow && pSpot.lnoiselow == otherSpot.lnoiselow; locallab.spots.at(j).levelthrlow = locallab.spots.at(j).levelthrlow && pSpot.levelthrlow == otherSpot.levelthrlow; @@ -4056,9 +4056,9 @@ void ParamsEdited::combine(rtengine::procparams::ProcParams& toEdit, const rteng toEdit.locallab.spots.at(i).blurMethod = mods.locallab.spots.at(i).blurMethod; } - // if (locallab.spots.at(i).usemask) { - // toEdit.locallab.spots.at(i).usemask = mods.locallab.spots.at(i).usemask; - // } + if (locallab.spots.at(i).usemask) { + toEdit.locallab.spots.at(i).usemask = mods.locallab.spots.at(i).usemask; + } if (locallab.spots.at(i).levelthr) { toEdit.locallab.spots.at(i).levelthr = mods.locallab.spots.at(i).levelthr; @@ -6587,7 +6587,7 @@ LocallabParamsEdited::LocallabSpotEdited::LocallabSpotEdited(bool v) : blMethod(v), chroMethod(v), quamethod(v), - // usemask(v), + usemask(v), levelthr(v), lnoiselow(v), levelthrlow(v), @@ -7106,7 +7106,7 @@ void LocallabParamsEdited::LocallabSpotEdited::set(bool v) blMethod = v; chroMethod = v; quamethod = v; -// usemask = v; + usemask = v; levelthr = v; lnoiselow = v; levelthrlow = v; diff --git a/rtgui/paramsedited.h b/rtgui/paramsedited.h index 897c8b16b..41406e3ea 100644 --- a/rtgui/paramsedited.h +++ b/rtgui/paramsedited.h @@ -620,7 +620,7 @@ public: bool blMethod; bool chroMethod; bool quamethod; - // bool usemask; + bool usemask; bool levelthr; bool lnoiselow; bool levelthrlow;