diff --git a/rtdata/languages/English (UK) b/rtdata/languages/English (UK) index 4cc5d511f..2540a3957 100644 --- a/rtdata/languages/English (UK) +++ b/rtdata/languages/English (UK) @@ -916,8 +916,6 @@ TP_RAW_FALSECOLOR;False colour suppression steps !TP_RESIZE_BICUBICSH;Bicubic (Sharper) !TP_RESIZE_BILINEAR;Bilinear !TP_RESIZE_CROPPEDAREA;Cropped area -!TP_RESIZE_DOWNSCALEB;Downscale (Better) -!TP_RESIZE_DOWNSCALEF;Downscale (Faster) !TP_RESIZE_FITBOX;Bounding box !TP_RESIZE_FULLIMAGE;Full image !TP_RESIZE_FULLSIZE;Full Image Size: diff --git a/rtdata/languages/English (US) b/rtdata/languages/English (US) index 4aa092cfc..d5d5f3edf 100644 --- a/rtdata/languages/English (US) +++ b/rtdata/languages/English (US) @@ -921,8 +921,6 @@ HISTOGRAM_TOOLTIP_BAR;Show/Hide RBG indicator bar\nClick right mouse button on i !TP_RESIZE_BICUBICSH;Bicubic (Sharper) !TP_RESIZE_BILINEAR;Bilinear !TP_RESIZE_CROPPEDAREA;Cropped area -!TP_RESIZE_DOWNSCALEB;Downscale (Better) -!TP_RESIZE_DOWNSCALEF;Downscale (Faster) !TP_RESIZE_FITBOX;Bounding box !TP_RESIZE_FULLIMAGE;Full image !TP_RESIZE_FULLSIZE;Full Image Size: diff --git a/rtdata/languages/default b/rtdata/languages/default index 078aa2688..ef9a2b4ac 100644 --- a/rtdata/languages/default +++ b/rtdata/languages/default @@ -932,8 +932,6 @@ TP_RESIZE_BICUBICSF;Bicubic (Softer) TP_RESIZE_BICUBICSH;Bicubic (Sharper) TP_RESIZE_BILINEAR;Bilinear TP_RESIZE_CROPPEDAREA;Cropped area -TP_RESIZE_DOWNSCALEB;Downscale (Better) -TP_RESIZE_DOWNSCALEF;Downscale (Faster) TP_RESIZE_FITBOX;Bounding box TP_RESIZE_FULLIMAGE;Full image TP_RESIZE_FULLSIZE;Full Image Size: diff --git a/rtengine/improcfun.h b/rtengine/improcfun.h index 0fabde5df..c8ab7b108 100644 --- a/rtengine/improcfun.h +++ b/rtengine/improcfun.h @@ -121,7 +121,7 @@ class ImProcFunctions { void sharpening (LabImage* lab, float** buffer); void transform (Imagefloat* original, Imagefloat* transformed, int cx, int cy, int sx, int sy, int oW, int oH); void lab2rgb (LabImage* lab, Image8* image); - void resize (Image16* src, Image16* dst, double dScale); + void resize (Image16* src, Image16* dst, float dScale); void deconvsharpening (LabImage* lab, float** buffer); void MLsharpen (LabImage* lab);// Manuel's clarity / sharpening void MLmicrocontrast(LabImage* lab ); //Manuel's microcontrast diff --git a/rtengine/ipresize.cc b/rtengine/ipresize.cc index 4871288f6..757ebc9b4 100644 --- a/rtengine/ipresize.cc +++ b/rtengine/ipresize.cc @@ -16,14 +16,18 @@ * You should have received a copy of the GNU General Public License * along with RawTherapee. If not, see . */ -#include -#include -#include + +#include "improcfun.h" + #ifdef _OPENMP #include #endif -#include +//#define PROFILE + +#ifdef PROFILE +# include +#endif namespace rtengine { @@ -35,55 +39,55 @@ namespace rtengine { #define CLIP(a) ((a)>0?((a)(b)?((a)<(c)?(a):(c)):(b)) -inline double Lanc(double x, double a) +static inline float Lanc(float x, float a) { - if (x * x < 1e-6) - return 1.0; + if (x * x < 1e-6f) + return 1.0f; else if (x * x > a * a) - return 0.0; + return 0.0f; else { - x = M_PI * x; - return sin(x) * sin(x / a) / (x * x / a); + x = static_cast(M_PI) * x; + return sinf(x) * sinf(x / a) / (x * x / a); } } -void Lanczos(const Image16* src, Image16* dst, double scale) +static void Lanczos(const Image16* src, Image16* dst, float scale) { - const double delta = 1.0 / scale; - const double a = 3.0; - const double sc = std::min(scale, 1.0); - const int support = (int)(2.0 * a / sc) + 1; + const float delta = 1.0f / scale; + const float a = 3.0f; + const float sc = std::min(scale, 1.0f); + const int support = static_cast(2.0f * a / sc) + 1; // storage for precomputed parameters for horisontal interpolation - double * wwh = new double[support * dst->width]; + float * wwh = new float[support * dst->width]; int * jj0 = new int[dst->width]; int * jj1 = new int[dst->width]; // temporal storage for vertically-interpolated row of pixels - double * lr = new double[src->width]; - double * lg = new double[src->width]; - double * lb = new double[src->width]; + float * lr = new float[src->width]; + float * lg = new float[src->width]; + float * lb = new float[src->width]; // Phase 1: precompute coefficients for horisontal interpolation for (int j = 0; j < dst->width; j++) { // x coord of the center of pixel on src image - double x0 = (j + 0.5) * delta - 0.5; + float x0 = (static_cast(j) + 0.5f) * delta - 0.5f; // weights for interpolation in horisontal direction - double * w = wwh + j * support; + float * w = wwh + j * support; // sum of weights used for normalization - double ws = 0.0; + float ws = 0.0f; - jj0[j] = std::max(0, (int)floor(x0 - a / sc) + 1); - jj1[j] = std::min(src->width, (int)floor(x0 + a / sc) + 1); + jj0[j] = std::max(0, static_cast(floorf(x0 - a / sc)) + 1); + jj1[j] = std::min(src->width, static_cast(floorf(x0 + a / sc)) + 1); // calculate weights for (int jj = jj0[j]; jj < jj1[j]; jj++) { int k = jj - jj0[j]; - double z = sc * (x0 - jj); + float z = sc * (x0 - static_cast(jj)); w[k] = Lanc(z, a); ws += w[k]; } @@ -99,21 +103,21 @@ void Lanczos(const Image16* src, Image16* dst, double scale) for (int i = 0; i < dst->height; i++) { // y coord of the center of pixel on src image - double y0 = (i + 0.5) * delta - 0.5; + float y0 = (static_cast(i) + 0.5f) * delta - 0.5f; // weights for interpolation in y direction - double w[support]; + float w[support]; // sum of weights used for normalization - double ws= 0.0; + float ws= 0.0f; - int ii0 = std::max(0, (int)floor(y0 - a / sc) + 1); - int ii1 = std::min(src->height, (int)floor(y0 + a / sc) + 1); + int ii0 = std::max(0, static_cast(floorf(y0 - a / sc)) + 1); + int ii1 = std::min(src->height, static_cast(floorf(y0 + a / sc)) + 1); // calculate weights for vertical interpolation for (int ii = ii0; ii < ii1; ii++) { int k = ii - ii0; - double z = sc * (y0 - ii); + float z = sc * (y0 - static_cast(ii)); w[k] = Lanc(z, a); ws += w[k]; } @@ -126,7 +130,7 @@ void Lanczos(const Image16* src, Image16* dst, double scale) // Do vertical interpolation. Store results. for (int j = 0; j < src->width; j++) { - double r = 0.0, g = 0.0, b = 0.0; + float r = 0.0f, g = 0.0f, b = 0.0f; for (int ii = ii0; ii < ii1; ii++) { int k = ii - ii0; @@ -144,9 +148,9 @@ void Lanczos(const Image16* src, Image16* dst, double scale) // Do horisontal interpolation for(int j = 0; j < dst->width; j++) { - double * wh = wwh + support * j; + float * wh = wwh + support * j; - double r = 0.0, g = 0.0, b = 0.0; + float r = 0.0f, g = 0.0f, b = 0.0f; for (int jj = jj0[j]; jj < jj1[j]; jj++) { int k = jj - jj0[j]; @@ -156,9 +160,9 @@ void Lanczos(const Image16* src, Image16* dst, double scale) b += wh[k] * lb[jj]; } - dst->r[i][j] = CLIP((int)r); - dst->g[i][j] = CLIP((int)g); - dst->b[i][j] = CLIP((int)b); + dst->r[i][j] = CLIP(static_cast(r)); + dst->g[i][j] = CLIP(static_cast(g)); + dst->b[i][j] = CLIP(static_cast(b)); } } @@ -170,204 +174,58 @@ void Lanczos(const Image16* src, Image16* dst, double scale) delete[] lb; } -void ImProcFunctions::resize (Image16* src, Image16* dst, double dScale) { +void ImProcFunctions::resize (Image16* src, Image16* dst, float dScale) { - //time_t t1 = clock(); +#ifdef PROFILE + time_t t1 = clock(); +#endif - if(params->resize.method == "Lanczos") { + if(params->resize.method == "Lanczos" || + params->resize.method == "Downscale (Better)" || + params->resize.method == "Downscale (Faster)" + ) { Lanczos(src, dst, dScale); - } - else if(params->resize.method == "Downscale (Better)") { - // small-scale algorithm by Ilia - // provides much better quality on small scales - // calculates mean value over source pixels which current destination pixel covers - // works only for scales < 1 - // for scales ~1 it is analogous to bilinear - // possibly, for even less scale factors (< 0.2 possibly) boundary pixels are not needed, omitting them can give a speedup - // this algorithm is much slower on small factors than others, because it uses all pixels of the SOURCE image - // Ilia Popov ilia_popov@rambler.ru 2010 - - double delta = 1.0 / dScale; - double k = dScale * dScale; - - #pragma omp parallel for if (multiThread) - for(int i = 0; i < dst->height; i++) { - // top and bottom boundary coordinates - double y0 = i * delta; - double y1 = (i + 1) * delta; - - int m0 = y0; - m0 = CLIPTO(m0, 0, src->height-1); - - int m1 = y1; - m1 = CLIPTO(m1, 0, src->height-1); - - // weights of boundary pixels - double wy0 = 1.0 - (y0 - m0); - double wy1 = y1 - m1; - - for(int j = 0; j < dst->width; j++) { - // left and right boundary coordinates - double x0 = j * delta; - double x1 = (j + 1) * delta; - - int n0 = x0; - n0 = CLIPTO(n0, 0, src->width-1); - int n1 = x1; - n1 = CLIPTO(n1, 0, src->width-1); - - double wx0 = 1.0 - (x0 - n0); - double wx1 = x1 - n1; - - double r = 0; - double g = 0; - double b = 0; - - // integration - // corners - r += wy0 * wx0 * src->r[m0][n0] + wy0 * wx1 * src->r[m0][n1] + wy1 * wx0 * src->r[m1][n0] + wy1 * wx1 * src->r[m1][n1]; - g += wy0 * wx0 * src->g[m0][n0] + wy0 * wx1 * src->g[m0][n1] + wy1 * wx0 * src->g[m1][n0] + wy1 * wx1 * src->g[m1][n1]; - b += wy0 * wx0 * src->b[m0][n0] + wy0 * wx1 * src->b[m0][n1] + wy1 * wx0 * src->b[m1][n0] + wy1 * wx1 * src->b[m1][n1]; - - // top and bottom boundaries - for(int n = n0 + 1; n < n1; n++) { - r += wy0 * src->r[m0][n] + wy1 * src->r[m1][n]; - g += wy0 * src->g[m0][n] + wy1 * src->g[m1][n]; - b += wy0 * src->b[m0][n] + wy1 * src->b[m1][n]; - } - - // inner rows - for(int m = m0 + 1; m < m1; m++) { - // left and right boundaries - r += wx0 * src->r[m][n0] + wx1 * src->r[m][n1]; - g += wx0 * src->g[m][n0] + wx1 * src->g[m][n1]; - b += wx0 * src->b[m][n0] + wx1 * src->b[m][n1]; - // inner pixels - for(int n = n0 + 1; n < n1; n++) { - r += src->r[m][n]; - g += src->g[m][n]; - b += src->b[m][n]; - } - } - // overall weight is equal to the DST pixel area in SRC coordinates - r *= k; - g *= k; - b *= k; - - dst->r[i][j] = CLIP((int)r); - dst->g[i][j] = CLIP((int)g); - dst->b[i][j] = CLIP((int)b); - } - } - } - else if(params->resize.method == "Downscale (Faster)") { - // faster version of algo above, does not take into account border pixels, - // which are summed with non-unity weights in slow algo. So, no need - // for weights at all - // Ilia Popov ilia_popov@rambler.ru 5.04.2010 - - double delta = 1.0 / dScale; - - int p = (int) delta; - - // if actually we are doing upscaling, behave like Nearest - if(p == 0) - p = 1; - - int q = p/2; - - // may cause problems on 32-bit systems on extremely small factors. - // In that case change 1024 to smth less - const int divider = 1024; - - // scaling factor after summation - int k = divider / (p * p); - - #pragma omp parallel for if (multiThread) - for(int i = 0; i < dst->height; i++) { - // y coordinate of center of destination pixel - double y = (i + 0.5) * delta; - - int m0 = (int) (y) - q; - m0 = CLIPTO(m0, 0, src->height-1); - - int m1 = m0 + p; - if(m1 > src->height) { - m1 = src->height; - m0 = m1 - p; - } - m1 = CLIPTO(m1, 0, src->height); - - for(int j = 0; j < dst->width; j++) { - // x coordinate of center of destination pixel - double x = (j + 0.5) * delta; - - int n0 = (int) (x) - q; - n0 = CLIPTO(n0, 0, src->width-1); - - int n1 = n0 + p; - if(n1 > src->width) { - n1 = src->width; - n0 = n1 - p; - } - n1 = CLIPTO(n1, 0, src->width); - - int r = 0; - int g = 0; - int b = 0; - - // integration - for(int m = m0; m < m1; m++) { - for(int n = n0; n < n1; n++) { - r += src->r[m][n]; - g += src->g[m][n]; - b += src->b[m][n]; - } - } - dst->r[i][j] = CLIP( r * k / divider); - dst->g[i][j] = CLIP( g * k / divider); - dst->b[i][j] = CLIP( b * k / divider); - } - } } else if (params->resize.method.substr(0,7)=="Bicubic") { - double Av = -0.5; + float Av = -0.5f; if (params->resize.method=="Bicubic (Sharper)") - Av = -0.75; + Av = -0.75f; else if (params->resize.method=="Bicubic (Softer)") - Av = -0.25; + Av = -0.25f; #pragma omp parallel for if (multiThread) for (int i=0; iheight; i++) { - double wx[4], wy[4]; - double Dy = i / dScale; - int yc = (int) Dy; Dy -= (double)yc; + float wx[4], wy[4]; + float Dy = i / dScale; + int yc = (int) Dy; + Dy -= (float)yc; int ys = yc - 1; // smallest y-index used for interpolation // compute vertical weights - double t1y = -Av*(Dy-1.0)*Dy; - double t2y = (3.0-2.0*Dy)*Dy*Dy; + float t1y = -Av*(Dy-1.0f)*Dy; + float t2y = (3.0f - 2.0f*Dy)*Dy*Dy; wy[3] = t1y*Dy; - wy[2] = t1y*(Dy-1.0) + t2y; - wy[1] = -t1y*Dy + 1.0 - t2y; - wy[0] = -t1y*(Dy-1.0); - for (int j=0; jwidth; j++) { - double Dx = j / dScale; - int xc = (int) Dx; Dx -= (double)xc; + wy[2] = t1y*(Dy - 1.0f) + t2y; + wy[1] = -t1y*Dy + 1.0f - t2y; + wy[0] = -t1y*(Dy - 1.0f); + for (int j = 0; j < dst->width; j++) { + float Dx = j / dScale; + int xc = (int) Dx; + Dx -= (float)xc; int xs = xc - 1; // smallest x-index used for interpolation - if (ys >= 0 && ys height-3 && xs >= 0 && xs <= src->width-3) { + if (ys >= 0 && ys < src->height-3 && xs >= 0 && xs <= src->width-3) { // compute horizontal weights - double t1 = -Av*(Dx-1.0)*Dx; - double t2 = (3.0-2.0*Dx)*Dx*Dx; + float t1 = -Av*(Dx-1.0f)*Dx; + float t2 = (3.0f - 2.0f*Dx)*Dx*Dx; wx[3] = t1*Dx; - wx[2] = t1*(Dx-1.0) + t2; - wx[1] = -t1*Dx + 1.0 - t2; - wx[0] = -t1*(Dx-1.0); + wx[2] = t1*(Dx - 1.0f) + t2; + wx[1] = -t1*Dx + 1.0f - t2; + wx[0] = -t1*(Dx - 1.0f); // compute weighted sum int r = 0; int g = 0; int b = 0; for (int x=0; x<4; x++) for (int y=0; y<4; y++) { - double w = wx[x]*wy[y]; + float w = wx[x]*wy[y]; r += w*src->r[ys+y][xs+x]; g += w*src->g[ys+y][xs+x]; b += w*src->b[ys+y][xs+x]; @@ -380,10 +238,10 @@ void ImProcFunctions::resize (Image16* src, Image16* dst, double dScale) { xc = CLIPTO(xc, 0, src->width-1); yc = CLIPTO(yc, 0, src->height-1); int nx = xc + 1; - if (nx>=src->width) + if (nx >= src->width) nx = xc; int ny = yc + 1; - if (ny>=src->height) + if (ny >= src->height) ny = yc; dst->r[i][j] = (1-Dx)*(1-Dy)*src->r[yc][xc] + (1-Dx)*Dy*src->r[ny][xc] + Dx*(1-Dy)*src->r[yc][nx] + Dx*Dy*src->r[ny][nx]; dst->g[i][j] = (1-Dx)*(1-Dy)*src->g[yc][xc] + (1-Dx)*Dy*src->g[ny][xc] + Dx*(1-Dy)*src->g[yc][nx] + Dx*Dy*src->g[ny][nx]; @@ -397,14 +255,14 @@ void ImProcFunctions::resize (Image16* src, Image16* dst, double dScale) { for (int i=0; iheight; i++) { int sy = i/dScale; sy = CLIPTO(sy, 0, src->height-1); - double dy = i/dScale - sy; + float dy = i/dScale - sy; int ny = sy+1; if (ny>=src->height) ny = sy; for (int j=0; jwidth; j++) { int sx = j/dScale; sx = CLIPTO(sx, 0, src->width-1); - double dx = j/dScale - sx; + float dx = j/dScale - sx; int nx = sx+1; if (nx>=src->width) nx = sx; @@ -415,6 +273,7 @@ void ImProcFunctions::resize (Image16* src, Image16* dst, double dScale) { } } else { + // Nearest neighbour algorithm #pragma omp parallel for if (multiThread) for (int i=0; iheight; i++) { int sy = i/dScale; @@ -428,10 +287,12 @@ void ImProcFunctions::resize (Image16* src, Image16* dst, double dScale) { } } } - - //time_t t2 = clock(); - //std::cout << "Resize: " << params->resize.method << ": " - // << (double)(t2 - t1) / CLOCKS_PER_SEC << std::endl; + +#ifdef PROFILE + time_t t2 = clock(); + std::cout << "Resize: " << params->resize.method << ": " + << (float)(t2 - t1) / CLOCKS_PER_SEC << std::endl; +#endif } } diff --git a/rtgui/resize.cc b/rtgui/resize.cc index 7adc22b5b..9c99272e8 100644 --- a/rtgui/resize.cc +++ b/rtgui/resize.cc @@ -48,8 +48,6 @@ Resize::Resize () : Gtk::VBox(), FoldableToolPanel(this), maxw(100000), maxh(100 method->append_text (M("TP_RESIZE_BICUBIC")); method->append_text (M("TP_RESIZE_BICUBICSF")); method->append_text (M("TP_RESIZE_BICUBICSH")); - method->append_text (M("TP_RESIZE_DOWNSCALEB")); - method->append_text (M("TP_RESIZE_DOWNSCALEF")); method->append_text (M("TP_RESIZE_LANCZOS")); method->set_active (0); @@ -150,12 +148,13 @@ void Resize::read (const ProcParams* pp, const ParamsEdited* pedited) { method->set_active (3); else if (pp->resize.method == "Bicubic (Sharper)") method->set_active (4); - else if (pp->resize.method == "Downscale (Better)") - method->set_active (5); - else if (pp->resize.method == "Downscale (Faster)") - method->set_active (6); else if (pp->resize.method == "Lanczos") - method->set_active (7); + method->set_active (5); + else if (pp->resize.method == "Downscale (Better)" || + pp->resize.method == "Downscale (Faster)") + { + method->set_active (5); + } wDirty = false; hDirty = false; @@ -206,10 +205,6 @@ void Resize::write (ProcParams* pp, ParamsEdited* pedited) { else if (method->get_active_row_number() == 4) pp->resize.method = "Bicubic (Sharper)"; else if (method->get_active_row_number() == 5) - pp->resize.method = "Downscale (Better)"; - else if (method->get_active_row_number() == 6) - pp->resize.method = "Downscale (Faster)"; - else if (method->get_active_row_number() == 7) pp->resize.method = "Lanczos"; pp->resize.dataspec = dataSpec;