diff --git a/rtdata/languages/default b/rtdata/languages/default index 968a8c0ed..cad717e6f 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -1667,7 +1667,7 @@ TP_FLATFIELD_BT_HORIZONTAL;Horizontal TP_FLATFIELD_BT_VERTHORIZ;Vertical + Horizontal TP_FLATFIELD_BT_VERTICAL;Vertical TP_FLATFIELD_CLIPCONTROL;Clip control -TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, clip control can lead to color cast. +TP_FLATFIELD_CLIPCONTROL_TOOLTIP;Clip control avoids clipped highlights caused by applying the flat field. If there are already clipped highlights before applying the flat field, value 0 is used. TP_FLATFIELD_LABEL;Flat-Field TP_GENERAL_11SCALE_TOOLTIP;The effects of this tool are only visible or only accurate at a preview scale of 1:1. TP_GRADIENT_CENTER;Center diff --git a/rtengine/CMakeLists.txt b/rtengine/CMakeLists.txt index 40ddaefbb..52ec61b2f 100644 --- a/rtengine/CMakeLists.txt +++ b/rtengine/CMakeLists.txt @@ -111,6 +111,7 @@ set(RTENGINESOURCEFILES processingjob.cc procparams.cc profilestore.cc + rawflatfield.cc rawimage.cc rawimagesource.cc rcd_demosaic.cc diff --git a/rtengine/rawflatfield.cc b/rtengine/rawflatfield.cc new file mode 100644 index 000000000..8d8ed0873 --- /dev/null +++ b/rtengine/rawflatfield.cc @@ -0,0 +1,559 @@ +/* + * This file is part of RawTherapee. + * + * Copyright (c) 2004-2017 Gabor Horvath + * + * 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 . + */ +#include +#include + +#include "rtengine.h" +#include "rawimagesource.h" +#include "rawimage.h" +#include "procparams.h" +//#define BENCHMARK +//#include "StopWatch.h" +#include "opthelper.h" + +namespace { + +void cfaboxblur(float** riFlatFile, float* cfablur, int boxH, int boxW, int H, int W) +{ + + if (boxW < 0 || boxH < 0 || (boxW == 0 && boxH == 0)) { // nothing to blur or negative values + memcpy(cfablur, riFlatFile[0], W * H * sizeof(float)); + return; + } + + float *tmpBuffer = nullptr; + float *cfatmp = nullptr; + float *srcVertical = nullptr; + + + if (boxH > 0 && boxW > 0) { + // we need a temporary buffer if we have to blur both directions + tmpBuffer = (float (*)) calloc (H * W, sizeof * tmpBuffer); + } + + if (boxH == 0) { + // if boxH == 0 we can skip the vertical blur and process the horizontal blur from riFlatFile to cfablur without using a temporary buffer + cfatmp = cfablur; + } else { + cfatmp = tmpBuffer; + } + + if (boxW == 0) { + // if boxW == 0 we can skip the horizontal blur and process the vertical blur from riFlatFile to cfablur without using a temporary buffer + srcVertical = riFlatFile[0]; + } else { + srcVertical = cfatmp; + } + +#ifdef _OPENMP + #pragma omp parallel +#endif + { + + if (boxW > 0) { + //box blur cfa image; box size = BS + //horizontal blur +#ifdef _OPENMP + #pragma omp for +#endif + + for (int row = 0; row < H; row++) { + int len = boxW / 2 + 1; + cfatmp[row * W + 0] = riFlatFile[row][0] / len; + cfatmp[row * W + 1] = riFlatFile[row][1] / len; + + for (int j = 2; j <= boxW; j += 2) { + cfatmp[row * W + 0] += riFlatFile[row][j] / len; + cfatmp[row * W + 1] += riFlatFile[row][j + 1] / len; + } + + for (int col = 2; col <= boxW; col += 2) { + cfatmp[row * W + col] = (cfatmp[row * W + col - 2] * len + riFlatFile[row][boxW + col]) / (len + 1); + cfatmp[row * W + col + 1] = (cfatmp[row * W + col - 1] * len + riFlatFile[row][boxW + col + 1]) / (len + 1); + len ++; + } + + for (int col = boxW + 2; col < W - boxW; col++) { + cfatmp[row * W + col] = cfatmp[row * W + col - 2] + (riFlatFile[row][boxW + col] - cfatmp[row * W + col - boxW - 2]) / len; + } + + for (int col = W - boxW; col < W; col += 2) { + cfatmp[row * W + col] = (cfatmp[row * W + col - 2] * len - cfatmp[row * W + col - boxW - 2]) / (len - 1); + + if (col + 1 < W) { + cfatmp[row * W + col + 1] = (cfatmp[row * W + col - 1] * len - cfatmp[row * W + col - boxW - 1]) / (len - 1); + } + + len --; + } + } + } + + if (boxH > 0) { + //vertical blur +#ifdef __SSE2__ + const vfloat leninitv = F2V(boxH / 2 + 1); + const vfloat onev = F2V(1.f); +#ifdef _OPENMP + #pragma omp for nowait +#endif + + for (int col = 0; col < W - 7; col += 8) { + vfloat lenv = leninitv; + vfloat temp1v = LVFU(srcVertical[0 * W + col]) / lenv; + vfloat temp2v = LVFU(srcVertical[1 * W + col]) / lenv; + vfloat temp3v = LVFU(srcVertical[0 * W + col + 4]) / lenv; + vfloat temp4v = LVFU(srcVertical[1 * W + col + 4]) / lenv; + + for (int i = 2; i < boxH + 2; i += 2) { + temp1v += LVFU(srcVertical[i * W + col]) / lenv; + temp2v += LVFU(srcVertical[(i + 1) * W + col]) / lenv; + temp3v += LVFU(srcVertical[i * W + col + 4]) / lenv; + temp4v += LVFU(srcVertical[(i + 1) * W + col + 4]) / lenv; + } + + STVFU(cfablur[0 * W + col], temp1v); + STVFU(cfablur[1 * W + col], temp2v); + STVFU(cfablur[0 * W + col + 4], temp3v); + STVFU(cfablur[1 * W + col + 4], temp4v); + + int row; + for (row = 2; row < boxH + 2; row += 2) { + const vfloat lenp1v = lenv + onev; + temp1v = (temp1v * lenv + LVFU(srcVertical[(row + boxH) * W + col])) / lenp1v; + temp2v = (temp2v * lenv + LVFU(srcVertical[(row + boxH + 1) * W + col])) / lenp1v; + temp3v = (temp3v * lenv + LVFU(srcVertical[(row + boxH) * W + col + 4])) / lenp1v; + temp4v = (temp4v * lenv + LVFU(srcVertical[(row + boxH + 1) * W + col + 4])) / lenp1v; + STVFU(cfablur[row * W + col], temp1v); + STVFU(cfablur[(row + 1)*W + col], temp2v); + STVFU(cfablur[row * W + col + 4], temp3v); + STVFU(cfablur[(row + 1)*W + col + 4], temp4v); + lenv = lenp1v; + } + + for (; row < H - boxH - 1; row += 2) { + temp1v = temp1v + (LVFU(srcVertical[(row + boxH) * W + col]) - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenv; + temp2v = temp2v + (LVFU(srcVertical[(row + 1 + boxH) * W + col]) - LVFU(srcVertical[(row + 1 - boxH - 2) * W + col])) / lenv; + temp3v = temp3v + (LVFU(srcVertical[(row + boxH) * W + col + 4]) - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenv; + temp4v = temp4v + (LVFU(srcVertical[(row + 1 + boxH) * W + col + 4]) - LVFU(srcVertical[(row + 1 - boxH - 2) * W + col + 4])) / lenv; + STVFU(cfablur[row * W + col], temp1v); + STVFU(cfablur[(row + 1)*W + col], temp2v); + STVFU(cfablur[row * W + col + 4], temp3v); + STVFU(cfablur[(row + 1)*W + col + 4], temp4v); + } + + if (row < H - boxH) { + temp1v = temp1v + (LVFU(srcVertical[(row + boxH) * W + col]) - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenv; + temp3v = temp3v + (LVFU(srcVertical[(row + boxH) * W + col + 4]) - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenv; + STVFU(cfablur[row * W + col], temp1v); + STVFU(cfablur[row * W + col + 4], temp3v); + vfloat swapv = temp1v; + temp1v = temp2v; + temp2v = swapv; + swapv = temp3v; + temp3v = temp4v; + temp4v = swapv; + ++row; + } + + for (; row < H - 1; row += 2) { + const vfloat lenm1v = lenv - onev; + temp1v = (temp1v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenm1v; + temp2v = (temp2v * lenv - LVFU(srcVertical[(row - boxH - 1) * W + col])) / lenm1v; + temp3v = (temp3v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenm1v; + temp4v = (temp4v * lenv - LVFU(srcVertical[(row - boxH - 1) * W + col + 4])) / lenm1v; + STVFU(cfablur[row * W + col], temp1v); + STVFU(cfablur[(row + 1)*W + col], temp2v); + STVFU(cfablur[row * W + col + 4], temp3v); + STVFU(cfablur[(row + 1)*W + col + 4], temp4v); + lenv = lenm1v; + } + + if (row < H) { + vfloat lenm1v = lenv - onev; + temp1v = (temp1v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenm1v; + temp3v = (temp3v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenm1v; + STVFU(cfablur[(row)*W + col], temp1v); + STVFU(cfablur[(row)*W + col + 4], temp3v); + } + + } + +#ifdef _OPENMP + #pragma omp single +#endif + + for (int col = W - (W % 8); col < W; col++) { + int len = boxH / 2 + 1; + cfablur[0 * W + col] = srcVertical[0 * W + col] / len; + cfablur[1 * W + col] = srcVertical[1 * W + col] / len; + + for (int i = 2; i < boxH + 2; i += 2) { + cfablur[0 * W + col] += srcVertical[i * W + col] / len; + cfablur[1 * W + col] += srcVertical[(i + 1) * W + col] / len; + } + + for (int row = 2; row < boxH + 2; row += 2) { + cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len + srcVertical[(row + boxH) * W + col]) / (len + 1); + cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len + srcVertical[(row + boxH + 1) * W + col]) / (len + 1); + len ++; + } + + for (int row = boxH + 2; row < H - boxH; row++) { + cfablur[row * W + col] = cfablur[(row - 2) * W + col] + (srcVertical[(row + boxH) * W + col] - srcVertical[(row - boxH - 2) * W + col]) / len; + } + + for (int row = H - boxH; row < H; row += 2) { + cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len - srcVertical[(row - boxH - 2) * W + col]) / (len - 1); + + if (row + 1 < H) { + cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len - srcVertical[(row - boxH - 1) * W + col]) / (len - 1); + } + + len --; + } + } + +#else +#ifdef _OPENMP + #pragma omp for +#endif + + for (int col = 0; col < W; col++) { + int len = boxH / 2 + 1; + cfablur[0 * W + col] = srcVertical[0 * W + col] / len; + cfablur[1 * W + col] = srcVertical[1 * W + col] / len; + + for (int i = 2; i < boxH + 2; i += 2) { + cfablur[0 * W + col] += srcVertical[i * W + col] / len; + cfablur[1 * W + col] += srcVertical[(i + 1) * W + col] / len; + } + + for (int row = 2; row < boxH + 2; row += 2) { + cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len + srcVertical[(row + boxH) * W + col]) / (len + 1); + cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len + srcVertical[(row + boxH + 1) * W + col]) / (len + 1); + len ++; + } + + for (int row = boxH + 2; row < H - boxH; row++) { + cfablur[row * W + col] = cfablur[(row - 2) * W + col] + (srcVertical[(row + boxH) * W + col] - srcVertical[(row - boxH - 2) * W + col]) / len; + } + + for (int row = H - boxH; row < H; row += 2) { + cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len - srcVertical[(row - boxH - 2) * W + col]) / (len - 1); + + if (row + 1 < H) { + cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len - srcVertical[(row - boxH - 1) * W + col]) / (len - 1); + } + + len --; + } + } + +#endif + } + } + + if (tmpBuffer) { + free (tmpBuffer); + } +} + +} + +namespace rtengine +{ + +void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile, unsigned short black[4]) +{ +// BENCHFUN + float *cfablur = new float[H * W]; + int BS = raw.ff_BlurRadius; + BS += BS & 1; + + if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::V)) { + cfaboxblur(riFlatFile->data, cfablur, 2 * BS, 0, H, W); + } else if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::H)) { + cfaboxblur(riFlatFile->data, cfablur, 0, 2 * BS, H, W); + } else if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::VH)) { + //slightly more complicated blur if trying to correct both vertical and horizontal anomalies + cfaboxblur(riFlatFile->data, cfablur, BS, BS, H, W); //first do area blur to correct vignette + } else { //(raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::area_ff)) + cfaboxblur(riFlatFile->data, cfablur, BS, BS, H, W); + } + + if (ri->getSensorType() == ST_BAYER || ri->get_colors() == 1) { + float refcolor[2][2]; + + // find center values by channel + for (int m = 0; m < 2; ++m) + for (int n = 0; n < 2; ++n) { + const int row = 2 * (H >> 2) + m; + const int col = 2 * (W >> 2) + n; + const int c = ri->get_colors() != 1 ? FC(row, col) : 0; + const int c4 = ri->get_colors() != 1 ? ((c == 1 && !(row & 1)) ? 3 : c) : 0; + refcolor[m][n] = std::max(0.0f, cfablur[row * W + col] - black[c4]); + } + + float limitFactor = 1.f; + + if (raw.ff_AutoClipControl) { + bool clippedBefore = false; + for (int m = 0; m < 2 && !clippedBefore; ++m) { + for (int n = 0; n < 2 && !clippedBefore; ++n) { + float maxval = 0.f; + const int c = ri->get_colors() != 1 ? FC(m, n) : 0; + const int c4 = ri->get_colors() != 1 ? ((c == 1 && !(m & 1)) ? 3 : c) : 0; + const float clipVal = ri->get_white(c4); +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxval) schedule(dynamic, 16) +#endif + for (int row = 0; row < H - m; row += 2) { + for (int col = 0; col < W - n && !clippedBefore; col += 2) { + const float rawVal = rawData[row + m][col + n]; + if (rawVal >= clipVal) { + clippedBefore = true; + break; + } + const float tempval = (rawVal - black[c4]) * (refcolor[m][n] / std::max(1e-5f, cfablur[(row + m) * W + col + n] - black[c4])); + maxval = std::max(maxval, tempval); + } + } + + // now we have the max value for the channel + // if it clips, calculate factor to avoid clipping + if (maxval + black[c4] >= ri->get_white(c4)) { + if (!clippedBefore) { + limitFactor = std::min(limitFactor, ri->get_white(c4) / (maxval + black[c4])); + } else { + limitFactor = 1.f; + } + } + } + } + flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui + } else { + limitFactor = std::max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); + } + + for (int m = 0; m < 2; ++m) + for (int n = 0; n < 2; ++n) { + refcolor[m][n] *= limitFactor; + } + + unsigned int c[2][2] {}; + unsigned int c4[2][2] {}; + if (ri->get_colors() != 1) { + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + c[i][j] = FC(i, j); + } + } + c4[0][0] = (c[0][0] == 1) ? 3 : c[0][0]; + c4[0][1] = (c[0][1] == 1) ? 3 : c[0][1]; + c4[1][0] = c[1][0]; + c4[1][1] = c[1][1]; + } + + constexpr float minValue = 1.f; // if the pixel value in the flat field is less or equal this value, no correction will be applied. + +#ifdef __SSE2__ + const vfloat refcolorv[2] = {_mm_set_ps(refcolor[0][1], refcolor[0][0], refcolor[0][1], refcolor[0][0]), + _mm_set_ps(refcolor[1][1], refcolor[1][0], refcolor[1][1], refcolor[1][0]) + }; + const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), + _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) + }; + + const vfloat onev = F2V(1.f); + const vfloat minValuev = F2V(minValue); +#endif +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int row = 0; row < H; ++row) { + int col = 0; +#ifdef __SSE2__ + const vfloat rowBlackv = blackv[row & 1]; + const vfloat rowRefcolorv = refcolorv[row & 1]; + + for (; col < W - 3; col += 4) { + const vfloat blurv = LVFU(cfablur[(row) * W + col]) - rowBlackv; + vfloat vignettecorrv = rowRefcolorv / blurv; + vignettecorrv = vself(vmaskf_le(blurv, minValuev), onev, vignettecorrv); + const vfloat valv = LVFU(rawData[row][col]) - rowBlackv; + STVFU(rawData[row][col], valv * vignettecorrv + rowBlackv); + } + +#endif + + for (; col < W; ++col) { + const float blur = cfablur[(row) * W + col] - black[c4[row & 1][col & 1]]; + const float vignettecorr = blur <= minValue ? 1.f : refcolor[row & 1][col & 1] / blur; + rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * vignettecorr + black[c4[row & 1][col & 1]]; + } + } + } else if (ri->getSensorType() == ST_FUJI_XTRANS) { + float refcolor[3] = {0.f}; + int cCount[3] = {0}; + + // find center average values by channel + for (int m = -3; m < 3; ++m) + for (int n = -3; n < 3; ++n) { + const int row = 2 * (H >> 2) + m; + const int col = 2 * (W >> 2) + n; + const int c = riFlatFile->XTRANSFC(row, col); + refcolor[c] += std::max(0.0f, cfablur[row * W + col] - black[c]); + cCount[c] ++; + } + + for (int c = 0; c < 3; ++c) { + refcolor[c] = refcolor[c] / cCount[c]; + } + + float limitFactor = 1.f; + + if (raw.ff_AutoClipControl) { + // determine maximum calculated value to avoid clipping + bool clippedBefore = false; + const float clipVal = ri->get_white(0); + float maxval = 0.f; + // xtrans files have only one black level actually, so we can simplify the code a bit +#ifdef _OPENMP + #pragma omp parallel for reduction(max:maxval) schedule(dynamic,16) +#endif + for (int row = 0; row < H; ++row) { + for (int col = 0; col < W && !clippedBefore; ++col) { + const float rawVal = rawData[row][col]; + if (rawVal >= clipVal) { + clippedBefore = true; + break; + } + const float tempval = (rawVal - black[0]) * (refcolor[ri->XTRANSFC(row, col)] / std::max(1e-5f, cfablur[(row) * W + col] - black[0])); + maxval = std::max(maxval, tempval); + } + } + + // there's only one white level for xtrans + if (!clippedBefore && maxval + black[0] > ri->get_white(0)) { + limitFactor = ri->get_white(0) / (maxval + black[0]); + flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui + } + } else { + limitFactor = std::max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); + } + + + for (int c = 0; c < 3; ++c) { + refcolor[c] *= limitFactor; + } + + constexpr float minValue = 1.f; // if the pixel value in the flat field is less or equal this value, no correction will be applied. + +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < H; ++row) { + for (int col = 0; col < W; ++col) { + const int c = ri->XTRANSFC(row, col); + const float blur = cfablur[(row) * W + col] - black[c]; + const float vignettecorr = blur <= minValue ? 1.f : refcolor[c] / blur; + rawData[row][col] = (rawData[row][col] - black[c]) * vignettecorr + black[c]; + } + } + } + + if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::VH)) { + float *cfablur1 = new float[H * W]; + float *cfablur2 = new float[H * W]; + //slightly more complicated blur if trying to correct both vertical and horizontal anomalies + cfaboxblur(riFlatFile->data, cfablur1, 0, 2 * BS, H, W); //now do horizontal blur + cfaboxblur(riFlatFile->data, cfablur2, 2 * BS, 0, H, W); //now do vertical blur + + if (ri->getSensorType() == ST_BAYER || ri->get_colors() == 1) { + unsigned int c[2][2] {}; + unsigned int c4[2][2] {}; + if (ri->get_colors() != 1) { + for (int i = 0; i < 2; ++i) { + for (int j = 0; j < 2; ++j) { + c[i][j] = FC(i, j); + } + } + c4[0][0] = (c[0][0] == 1) ? 3 : c[0][0]; + c4[0][1] = (c[0][1] == 1) ? 3 : c[0][1]; + c4[1][0] = c[1][0]; + c4[1][1] = c[1][1]; + } + +#ifdef __SSE2__ + const vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), + _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) + }; + + const vfloat epsv = F2V(1e-5f); +#endif +#ifdef _OPENMP + #pragma omp parallel for schedule(dynamic,16) +#endif + + for (int row = 0; row < H; ++row) { + int col = 0; +#ifdef __SSE2__ + const vfloat rowBlackv = blackv[row & 1]; + + for (; col < W - 3; col += 4) { + const vfloat linecorrv = SQRV(vmaxf(LVFU(cfablur[row * W + col]) - rowBlackv, epsv)) / + (vmaxf(LVFU(cfablur1[row * W + col]) - rowBlackv, epsv) * vmaxf(LVFU(cfablur2[row * W + col]) - rowBlackv, epsv)); + const vfloat valv = LVFU(rawData[row][col]) - rowBlackv; + STVFU(rawData[row][col], valv * linecorrv + rowBlackv); + } + +#endif + + for (; col < W; ++col) { + const float linecorr = SQR(std::max(1e-5f, cfablur[row * W + col] - black[c4[row & 1][col & 1]])) / + (std::max(1e-5f, cfablur1[row * W + col] - black[c4[row & 1][col & 1]]) * std::max(1e-5f, cfablur2[row * W + col] - black[c4[row & 1][col & 1]])); + rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * linecorr + black[c4[row & 1][col & 1]]; + } + } + } else if (ri->getSensorType() == ST_FUJI_XTRANS) { +#ifdef _OPENMP + #pragma omp parallel for +#endif + + for (int row = 0; row < H; ++row) { + for (int col = 0; col < W; ++col) { + const int c = ri->XTRANSFC(row, col); + const float hlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur1[(row) * W + col] - black[c]); + const float vlinecorr = std::max(1e-5f, cfablur[(row) * W + col] - black[c]) / std::max(1e-5f, cfablur2[(row) * W + col] - black[c]); + rawData[row][col] = (rawData[row][col] - black[c]) * hlinecorr * vlinecorr + black[c]; + } + } + + } + + delete [] cfablur1; + delete [] cfablur2; + } + + delete [] cfablur; +} +} /* namespace */ diff --git a/rtengine/rawimagesource.cc b/rtengine/rawimagesource.cc index 5f1d13c79..34a50b944 100644 --- a/rtengine/rawimagesource.cc +++ b/rtengine/rawimagesource.cc @@ -2386,311 +2386,6 @@ void RawImageSource::HLRecovery_Global(const ToneCurveParams &hrp) } - -void RawImageSource::processFlatField(const RAWParams &raw, RawImage *riFlatFile, unsigned short black[4]) -{ -// BENCHFUN - float *cfablur = (float (*)) malloc (H * W * sizeof * cfablur); - int BS = raw.ff_BlurRadius; - BS += BS & 1; - - //function call to cfabloxblur - if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::V)) { - cfaboxblur(riFlatFile, cfablur, 2 * BS, 0); - } else if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::H)) { - cfaboxblur(riFlatFile, cfablur, 0, 2 * BS); - } else if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::VH)) { - //slightly more complicated blur if trying to correct both vertical and horizontal anomalies - cfaboxblur(riFlatFile, cfablur, BS, BS); //first do area blur to correct vignette - } else { //(raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::area_ff)) - cfaboxblur(riFlatFile, cfablur, BS, BS); - } - - if(ri->getSensorType() == ST_BAYER || ri->get_colors() == 1) { - float refcolor[2][2]; - - //find centre average values by channel - for (int m = 0; m < 2; m++) - for (int n = 0; n < 2; n++) { - int row = 2 * (H >> 2) + m; - int col = 2 * (W >> 2) + n; - int c = ri->get_colors() != 1 ? FC(row, col) : 0; - int c4 = ri->get_colors() != 1 ? (( c == 1 && !(row & 1) ) ? 3 : c) : 0; - refcolor[m][n] = max(0.0f, cfablur[row * W + col] - black[c4]); - } - - float limitFactor = 1.f; - - if(raw.ff_AutoClipControl) { - for (int m = 0; m < 2; m++) - for (int n = 0; n < 2; n++) { - float maxval = 0.f; - int c = ri->get_colors() != 1 ? FC(m, n) : 0; - int c4 = ri->get_colors() != 1 ? (( c == 1 && !(m & 1) ) ? 3 : c) : 0; -#ifdef _OPENMP - #pragma omp parallel -#endif - { - float maxvalthr = 0.f; -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 0; row < H - m; row += 2) { - for (int col = 0; col < W - n; col += 2) { - float tempval = (rawData[row + m][col + n] - black[c4]) * ( refcolor[m][n] / max(1e-5f, cfablur[(row + m) * W + col + n] - black[c4]) ); - - if(tempval > maxvalthr) { - maxvalthr = tempval; - } - } - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - - if(maxvalthr > maxval) { - maxval = maxvalthr; - } - - } - } - - // now we have the max value for the channel - // if it clips, calculate factor to avoid clipping - if(maxval + black[c4] >= ri->get_white(c4)) { - limitFactor = min(limitFactor, ri->get_white(c4) / (maxval + black[c4])); - } - } - - flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui - } else { - limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); - } - - for (int m = 0; m < 2; m++) - for (int n = 0; n < 2; n++) { - refcolor[m][n] *= limitFactor; - } - - unsigned int c[2][2] {}; - unsigned int c4[2][2] {}; - if(ri->get_colors() != 1) { - for (int i = 0; i < 2; ++i) { - for(int j = 0; j < 2; ++j) { - c[i][j] = FC(i, j); - } - } - c4[0][0] = ( c[0][0] == 1) ? 3 : c[0][0]; - c4[0][1] = ( c[0][1] == 1) ? 3 : c[0][1]; - c4[1][0] = c[1][0]; - c4[1][1] = c[1][1]; - } - - constexpr float minValue = 1.f; // if the pixel value in the flat field is less or equal this value, no correction will be applied. - -#ifdef __SSE2__ - vfloat refcolorv[2] = {_mm_set_ps(refcolor[0][1], refcolor[0][0], refcolor[0][1], refcolor[0][0]), - _mm_set_ps(refcolor[1][1], refcolor[1][0], refcolor[1][1], refcolor[1][0]) - }; - vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), - _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) - }; - - vfloat onev = F2V(1.f); - vfloat minValuev = F2V(minValue); -#endif -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - - for (int row = 0; row < H; row ++) { - int col = 0; -#ifdef __SSE2__ - vfloat rowBlackv = blackv[row & 1]; - vfloat rowRefcolorv = refcolorv[row & 1]; - - for (; col < W - 3; col += 4) { - vfloat blurv = LVFU(cfablur[(row) * W + col]) - rowBlackv; - vfloat vignettecorrv = rowRefcolorv / blurv; - vignettecorrv = vself(vmaskf_le(blurv, minValuev), onev, vignettecorrv); - vfloat valv = LVFU(rawData[row][col]); - valv -= rowBlackv; - STVFU(rawData[row][col], valv * vignettecorrv + rowBlackv); - } - -#endif - - for (; col < W; col ++) { - float blur = cfablur[(row) * W + col] - black[c4[row & 1][col & 1]]; - float vignettecorr = blur <= minValue ? 1.f : refcolor[row & 1][col & 1] / blur; - rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * vignettecorr + black[c4[row & 1][col & 1]]; - } - } - } else if(ri->getSensorType() == ST_FUJI_XTRANS) { - float refcolor[3] = {0.f}; - int cCount[3] = {0}; - - //find center ave values by channel - for (int m = -3; m < 3; m++) - for (int n = -3; n < 3; n++) { - int row = 2 * (H >> 2) + m; - int col = 2 * (W >> 2) + n; - int c = riFlatFile->XTRANSFC(row, col); - refcolor[c] += max(0.0f, cfablur[row * W + col] - black[c]); - cCount[c] ++; - } - - for(int c = 0; c < 3; c++) { - refcolor[c] = refcolor[c] / cCount[c]; - } - - float limitFactor = 1.f; - - if(raw.ff_AutoClipControl) { - // determine maximum calculated value to avoid clipping - float maxval = 0.f; - // xtrans files have only one black level actually, so we can simplify the code a bit -#ifdef _OPENMP - #pragma omp parallel -#endif - { - float maxvalthr = 0.f; -#ifdef _OPENMP - #pragma omp for schedule(dynamic,16) nowait -#endif - - for (int row = 0; row < H; row++) { - for (int col = 0; col < W; col++) { - float tempval = (rawData[row][col] - black[0]) * ( refcolor[ri->XTRANSFC(row, col)] / max(1e-5f, cfablur[(row) * W + col] - black[0]) ); - - if(tempval > maxvalthr) { - maxvalthr = tempval; - } - } - } - -#ifdef _OPENMP - #pragma omp critical -#endif - { - if(maxvalthr > maxval) { - maxval = maxvalthr; - } - } - } - - // there's only one white level for xtrans - if(maxval + black[0] > ri->get_white(0)) { - limitFactor = ri->get_white(0) / (maxval + black[0]); - flatFieldAutoClipValue = (1.f - limitFactor) * 100.f; // this value can be used to set the clip control slider in gui - } - } else { - limitFactor = max((float)(100 - raw.ff_clipControl) / 100.f, 0.01f); - } - - - for(int c = 0; c < 3; c++) { - refcolor[c] *= limitFactor; - } - - constexpr float minValue = 1.f; // if the pixel value in the flat field is less or equal this value, no correction will be applied. - -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int row = 0; row < H; row++) { - for (int col = 0; col < W; col++) { - int c = ri->XTRANSFC(row, col); - float blur = cfablur[(row) * W + col] - black[c]; - float vignettecorr = blur <= minValue ? 1.f : refcolor[c] / blur; - rawData[row][col] = (rawData[row][col] - black[c]) * vignettecorr + black[c]; - } - } - } - - if (raw.ff_BlurType == RAWParams::getFlatFieldBlurTypeString(RAWParams::FlatFieldBlurType::VH)) { - float *cfablur1 = (float (*)) malloc (H * W * sizeof * cfablur1); - float *cfablur2 = (float (*)) malloc (H * W * sizeof * cfablur2); - //slightly more complicated blur if trying to correct both vertical and horizontal anomalies - cfaboxblur(riFlatFile, cfablur1, 0, 2 * BS); //now do horizontal blur - cfaboxblur(riFlatFile, cfablur2, 2 * BS, 0); //now do vertical blur - - if(ri->getSensorType() == ST_BAYER || ri->get_colors() == 1) { - unsigned int c[2][2] {}; - unsigned int c4[2][2] {}; - if(ri->get_colors() != 1) { - for (int i = 0; i < 2; ++i) { - for(int j = 0; j < 2; ++j) { - c[i][j] = FC(i, j); - } - } - c4[0][0] = ( c[0][0] == 1) ? 3 : c[0][0]; - c4[0][1] = ( c[0][1] == 1) ? 3 : c[0][1]; - c4[1][0] = c[1][0]; - c4[1][1] = c[1][1]; - } - -#ifdef __SSE2__ - vfloat blackv[2] = {_mm_set_ps(black[c4[0][1]], black[c4[0][0]], black[c4[0][1]], black[c4[0][0]]), - _mm_set_ps(black[c4[1][1]], black[c4[1][0]], black[c4[1][1]], black[c4[1][0]]) - }; - - vfloat epsv = F2V(1e-5f); -#endif -#ifdef _OPENMP - #pragma omp parallel for schedule(dynamic,16) -#endif - - for (int row = 0; row < H; row ++) { - int col = 0; -#ifdef __SSE2__ - vfloat rowBlackv = blackv[row & 1]; - - for (; col < W - 3; col += 4) { - vfloat linecorrv = SQRV(vmaxf(LVFU(cfablur[row * W + col]) - rowBlackv, epsv)) / - (vmaxf(LVFU(cfablur1[row * W + col]) - rowBlackv, epsv) * vmaxf(LVFU(cfablur2[row * W + col]) - rowBlackv, epsv)); - vfloat valv = LVFU(rawData[row][col]); - valv -= rowBlackv; - STVFU(rawData[row][col], valv * linecorrv + rowBlackv); - } - -#endif - - for (; col < W; col ++) { - float linecorr = SQR(max(1e-5f, cfablur[row * W + col] - black[c4[row & 1][col & 1]])) / - (max(1e-5f, cfablur1[row * W + col] - black[c4[row & 1][col & 1]]) * max(1e-5f, cfablur2[row * W + col] - black[c4[row & 1][col & 1]])) ; - rawData[row][col] = (rawData[row][col] - black[c4[row & 1][col & 1]]) * linecorr + black[c4[row & 1][col & 1]]; - } - } - } else if(ri->getSensorType() == ST_FUJI_XTRANS) { -#ifdef _OPENMP - #pragma omp parallel for -#endif - - for (int row = 0; row < H; row++) { - for (int col = 0; col < W; col++) { - int c = ri->XTRANSFC(row, col); - float hlinecorr = (max(1e-5f, cfablur[(row) * W + col] - black[c]) / max(1e-5f, cfablur1[(row) * W + col] - black[c]) ); - float vlinecorr = (max(1e-5f, cfablur[(row) * W + col] - black[c]) / max(1e-5f, cfablur2[(row) * W + col] - black[c]) ); - rawData[row][col] = ((rawData[row][col] - black[c]) * hlinecorr * vlinecorr + black[c]); - } - } - - } - - free (cfablur1); - free (cfablur2); - } - - free (cfablur); -} - -//%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% - /* Copy original pixel data and * subtract dark frame (if present) from current image and apply flat field correction (if present) */ @@ -2782,253 +2477,6 @@ void RawImageSource::copyOriginalPixels(const RAWParams &raw, RawImage *src, Raw } } -void RawImageSource::cfaboxblur(RawImage *riFlatFile, float* cfablur, int boxH, int boxW) -{ - - if (boxW < 0 || boxH < 0 || (boxW == 0 && boxH == 0)) { // nothing to blur or negative values - memcpy(cfablur, riFlatFile->data[0], W * H * sizeof(float)); - return; - } - - float *tmpBuffer = nullptr; - float *cfatmp = nullptr; - float *srcVertical = nullptr; - - - if(boxH > 0 && boxW > 0) { - // we need a temporary buffer if we have to blur both directions - tmpBuffer = (float (*)) calloc (H * W, sizeof * tmpBuffer); - } - - if(boxH == 0) { - // if boxH == 0 we can skip the vertical blur and process the horizontal blur from riFlatFile to cfablur without using a temporary buffer - cfatmp = cfablur; - } else { - cfatmp = tmpBuffer; - } - - if(boxW == 0) { - // if boxW == 0 we can skip the horizontal blur and process the vertical blur from riFlatFile to cfablur without using a temporary buffer - srcVertical = riFlatFile->data[0]; - } else { - srcVertical = cfatmp; - } - -#ifdef _OPENMP - #pragma omp parallel -#endif - { - - if(boxW > 0) { - //box blur cfa image; box size = BS - //horizontal blur -#ifdef _OPENMP - #pragma omp for -#endif - - for (int row = 0; row < H; row++) { - int len = boxW / 2 + 1; - cfatmp[row * W + 0] = riFlatFile->data[row][0] / len; - cfatmp[row * W + 1] = riFlatFile->data[row][1] / len; - - for (int j = 2; j <= boxW; j += 2) { - cfatmp[row * W + 0] += riFlatFile->data[row][j] / len; - cfatmp[row * W + 1] += riFlatFile->data[row][j + 1] / len; - } - - for (int col = 2; col <= boxW; col += 2) { - cfatmp[row * W + col] = (cfatmp[row * W + col - 2] * len + riFlatFile->data[row][boxW + col]) / (len + 1); - cfatmp[row * W + col + 1] = (cfatmp[row * W + col - 1] * len + riFlatFile->data[row][boxW + col + 1]) / (len + 1); - len ++; - } - - for (int col = boxW + 2; col < W - boxW; col++) { - cfatmp[row * W + col] = cfatmp[row * W + col - 2] + (riFlatFile->data[row][boxW + col] - cfatmp[row * W + col - boxW - 2]) / len; - } - - for (int col = W - boxW; col < W; col += 2) { - cfatmp[row * W + col] = (cfatmp[row * W + col - 2] * len - cfatmp[row * W + col - boxW - 2]) / (len - 1); - - if (col + 1 < W) { - cfatmp[row * W + col + 1] = (cfatmp[row * W + col - 1] * len - cfatmp[row * W + col - boxW - 1]) / (len - 1); - } - - len --; - } - } - } - - if(boxH > 0) { - //vertical blur -#ifdef __SSE2__ - vfloat leninitv = F2V(boxH / 2 + 1); - vfloat onev = F2V( 1.0f ); - vfloat temp1v, temp2v, temp3v, temp4v, lenv, lenp1v, lenm1v; - int row; -#ifdef _OPENMP - #pragma omp for nowait -#endif - - for (int col = 0; col < W - 7; col += 8) { - lenv = leninitv; - temp1v = LVFU(srcVertical[0 * W + col]) / lenv; - temp2v = LVFU(srcVertical[1 * W + col]) / lenv; - temp3v = LVFU(srcVertical[0 * W + col + 4]) / lenv; - temp4v = LVFU(srcVertical[1 * W + col + 4]) / lenv; - - for (int i = 2; i < boxH + 2; i += 2) { - temp1v += LVFU(srcVertical[i * W + col]) / lenv; - temp2v += LVFU(srcVertical[(i + 1) * W + col]) / lenv; - temp3v += LVFU(srcVertical[i * W + col + 4]) / lenv; - temp4v += LVFU(srcVertical[(i + 1) * W + col + 4]) / lenv; - } - - STVFU(cfablur[0 * W + col], temp1v); - STVFU(cfablur[1 * W + col], temp2v); - STVFU(cfablur[0 * W + col + 4], temp3v); - STVFU(cfablur[1 * W + col + 4], temp4v); - - for (row = 2; row < boxH + 2; row += 2) { - lenp1v = lenv + onev; - temp1v = (temp1v * lenv + LVFU(srcVertical[(row + boxH) * W + col])) / lenp1v; - temp2v = (temp2v * lenv + LVFU(srcVertical[(row + boxH + 1) * W + col])) / lenp1v; - temp3v = (temp3v * lenv + LVFU(srcVertical[(row + boxH) * W + col + 4])) / lenp1v; - temp4v = (temp4v * lenv + LVFU(srcVertical[(row + boxH + 1) * W + col + 4])) / lenp1v; - STVFU(cfablur[row * W + col], temp1v); - STVFU(cfablur[(row + 1)*W + col], temp2v); - STVFU(cfablur[row * W + col + 4], temp3v); - STVFU(cfablur[(row + 1)*W + col + 4], temp4v); - lenv = lenp1v; - } - - for (; row < H - boxH - 1; row += 2) { - temp1v = temp1v + (LVFU(srcVertical[(row + boxH) * W + col]) - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenv; - temp2v = temp2v + (LVFU(srcVertical[(row + 1 + boxH) * W + col]) - LVFU(srcVertical[(row + 1 - boxH - 2) * W + col])) / lenv; - temp3v = temp3v + (LVFU(srcVertical[(row + boxH) * W + col + 4]) - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenv; - temp4v = temp4v + (LVFU(srcVertical[(row + 1 + boxH) * W + col + 4]) - LVFU(srcVertical[(row + 1 - boxH - 2) * W + col + 4])) / lenv; - STVFU(cfablur[row * W + col], temp1v); - STVFU(cfablur[(row + 1)*W + col], temp2v); - STVFU(cfablur[row * W + col + 4], temp3v); - STVFU(cfablur[(row + 1)*W + col + 4], temp4v); - } - - for(; row < H - boxH; row++) { - temp1v = temp1v + (LVFU(srcVertical[(row + boxH) * W + col]) - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenv; - temp3v = temp3v + (LVFU(srcVertical[(row + boxH) * W + col + 4]) - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenv; - STVFU(cfablur[row * W + col], temp1v); - STVFU(cfablur[row * W + col + 4], temp3v); - vfloat swapv = temp1v; - temp1v = temp2v; - temp2v = swapv; - swapv = temp3v; - temp3v = temp4v; - temp4v = swapv; - } - - for (; row < H - 1; row += 2) { - lenm1v = lenv - onev; - temp1v = (temp1v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenm1v; - temp2v = (temp2v * lenv - LVFU(srcVertical[(row - boxH - 1) * W + col])) / lenm1v; - temp3v = (temp3v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenm1v; - temp4v = (temp4v * lenv - LVFU(srcVertical[(row - boxH - 1) * W + col + 4])) / lenm1v; - STVFU(cfablur[row * W + col], temp1v); - STVFU(cfablur[(row + 1)*W + col], temp2v); - STVFU(cfablur[row * W + col + 4], temp3v); - STVFU(cfablur[(row + 1)*W + col + 4], temp4v); - lenv = lenm1v; - } - - for(; row < H; row++) { - lenm1v = lenv - onev; - temp1v = (temp1v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col])) / lenm1v; - temp3v = (temp3v * lenv - LVFU(srcVertical[(row - boxH - 2) * W + col + 4])) / lenm1v; - STVFU(cfablur[(row)*W + col], temp1v); - STVFU(cfablur[(row)*W + col + 4], temp3v); - } - - } - -#ifdef _OPENMP - #pragma omp single -#endif - - for (int col = W - (W % 8); col < W; col++) { - int len = boxH / 2 + 1; - cfablur[0 * W + col] = srcVertical[0 * W + col] / len; - cfablur[1 * W + col] = srcVertical[1 * W + col] / len; - - for (int i = 2; i < boxH + 2; i += 2) { - cfablur[0 * W + col] += srcVertical[i * W + col] / len; - cfablur[1 * W + col] += srcVertical[(i + 1) * W + col] / len; - } - - for (int row = 2; row < boxH + 2; row += 2) { - cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len + srcVertical[(row + boxH) * W + col]) / (len + 1); - cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len + srcVertical[(row + boxH + 1) * W + col]) / (len + 1); - len ++; - } - - for (int row = boxH + 2; row < H - boxH; row++) { - cfablur[row * W + col] = cfablur[(row - 2) * W + col] + (srcVertical[(row + boxH) * W + col] - srcVertical[(row - boxH - 2) * W + col]) / len; - } - - for (int row = H - boxH; row < H; row += 2) { - cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len - srcVertical[(row - boxH - 2) * W + col]) / (len - 1); - - if (row + 1 < H) { - cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len - srcVertical[(row - boxH - 1) * W + col]) / (len - 1); - } - - len --; - } - } - -#else -#ifdef _OPENMP - #pragma omp for -#endif - - for (int col = 0; col < W; col++) { - int len = boxH / 2 + 1; - cfablur[0 * W + col] = srcVertical[0 * W + col] / len; - cfablur[1 * W + col] = srcVertical[1 * W + col] / len; - - for (int i = 2; i < boxH + 2; i += 2) { - cfablur[0 * W + col] += srcVertical[i * W + col] / len; - cfablur[1 * W + col] += srcVertical[(i + 1) * W + col] / len; - } - - for (int row = 2; row < boxH + 2; row += 2) { - cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len + srcVertical[(row + boxH) * W + col]) / (len + 1); - cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len + srcVertical[(row + boxH + 1) * W + col]) / (len + 1); - len ++; - } - - for (int row = boxH + 2; row < H - boxH; row++) { - cfablur[row * W + col] = cfablur[(row - 2) * W + col] + (srcVertical[(row + boxH) * W + col] - srcVertical[(row - boxH - 2) * W + col]) / len; - } - - for (int row = H - boxH; row < H; row += 2) { - cfablur[row * W + col] = (cfablur[(row - 2) * W + col] * len - srcVertical[(row - boxH - 2) * W + col]) / (len - 1); - - if (row + 1 < H) { - cfablur[(row + 1)*W + col] = (cfablur[(row - 1) * W + col] * len - srcVertical[(row - boxH - 1) * W + col]) / (len - 1); - } - - len --; - } - } - -#endif - } - } - - if(tmpBuffer) { - free (tmpBuffer); - } -} - - // Scale original pixels into the range 0 65535 using black offsets and multipliers void RawImageSource::scaleColors(int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData) { diff --git a/rtengine/rawimagesource.h b/rtengine/rawimagesource.h index e52adea18..ecadec410 100644 --- a/rtengine/rawimagesource.h +++ b/rtengine/rawimagesource.h @@ -140,7 +140,6 @@ public: void processFlatField(const RAWParams &raw, RawImage *riFlatFile, unsigned short black[4]); void copyOriginalPixels(const RAWParams &raw, RawImage *ri, RawImage *riDark, RawImage *riFlatFile, array2D &rawData ); - void cfaboxblur (RawImage *riFlatFile, float* cfablur, int boxH, int boxW); void scaleColors (int winx, int winy, int winw, int winh, const RAWParams &raw, array2D &rawData); // raw for cblack void getImage (const ColorTemp &ctemp, int tran, Imagefloat* image, const PreviewProps &pp, const procparams::ToneCurveParams &hrp, const procparams::RAWParams &raw) override; diff --git a/rtgui/flatfield.cc b/rtgui/flatfield.cc index 03204c037..c0bd0555a 100644 --- a/rtgui/flatfield.cc +++ b/rtgui/flatfield.cc @@ -54,7 +54,7 @@ FlatField::FlatField () : FoldableToolPanel(this, "flatfield", M("TP_FLATFIELD_L flatFieldBlurRadius->show(); Gtk::HBox* hbffbt = Gtk::manage (new Gtk::HBox ()); - hbffbt->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_FLATFIELD_BLURTYPE") + ":"))); + hbffbt->pack_start (*Gtk::manage (new Gtk::Label ( M("TP_FLATFIELD_BLURTYPE") + ":")), Gtk::PACK_SHRINK, 4); hbffbt->set_spacing(4); flatFieldBlurType = Gtk::manage (new MyComboBoxText ()); flatFieldBlurType->append(M("TP_FLATFIELD_BT_AREA"));