Moved debayer and preprocessing parameters to class ProcParams for every single image. Added tab RAW for changing those parameters. Progress bar shows only load step (work to do)
296 lines
11 KiB
C++
296 lines
11 KiB
C++
/*
|
|
* This file is part of RawTherapee.
|
|
*
|
|
* Copyright (c) 2004-2010 Gabor Horvath <hgabor@rawtherapee.com>
|
|
*
|
|
* RawTherapee is free software: you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation, either version 3 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* RawTherapee is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with RawTherapee. If not, see <http://www.gnu.org/licenses/>.
|
|
*/
|
|
#include <rtengine.h>
|
|
#include <improcfun.h>
|
|
#include <glibmm.h>
|
|
#ifdef _OPENMP
|
|
#include <omp.h>
|
|
#endif
|
|
|
|
namespace rtengine {
|
|
|
|
#undef CLIP
|
|
#undef CLIPTO
|
|
#undef CMAXVAL
|
|
|
|
#define CMAXVAL 0xffff
|
|
#define CLIP(a) ((a)>0?((a)<CMAXVAL?(a):CMAXVAL):0)
|
|
#define CLIPTO(a,b,c) ((a)>(b)?((a)<(c)?(a):(c)):(b))
|
|
|
|
void ImProcFunctions::resize (Image16* src, Image16* dst) {
|
|
|
|
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 / params->resize.scale;
|
|
double k = params->resize.scale * params->resize.scale;
|
|
|
|
#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);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
|
|
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 / params->resize.scale;
|
|
|
|
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);
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
if (params->resize.method.substr(0,7)=="Bicubic") {
|
|
double Av = -0.5;
|
|
if (params->resize.method=="Bicubic (Sharper)")
|
|
Av = -0.75;
|
|
else if (params->resize.method=="Bicubic (Softer)")
|
|
Av = -0.25;
|
|
#pragma omp parallel for if (multiThread)
|
|
for (int i=0; i<dst->height; i++) {
|
|
double wx[4], wy[4];
|
|
double Dy = i / params->resize.scale;
|
|
int yc = (int) Dy; Dy -= (double)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;
|
|
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; j<dst->width; j++) {
|
|
double Dx = j / params->resize.scale;
|
|
int xc = (int) Dx; Dx -= (double)xc;
|
|
int xs = xc - 1; // smallest x-index used for interpolation
|
|
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;
|
|
wx[3] = t1*Dx;
|
|
wx[2] = t1*(Dx-1.0) + t2;
|
|
wx[1] = -t1*Dx + 1.0 - t2;
|
|
wx[0] = -t1*(Dx-1.0);
|
|
// 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];
|
|
r += w*src->r[ys+y][xs+x];
|
|
g += w*src->g[ys+y][xs+x];
|
|
b += w*src->b[ys+y][xs+x];
|
|
}
|
|
dst->r[i][j] = CLIP(r);
|
|
dst->g[i][j] = CLIP(g);
|
|
dst->b[i][j] = CLIP(b);
|
|
}
|
|
else {
|
|
xc = CLIPTO(xc, 0, src->width-1);
|
|
yc = CLIPTO(yc, 0, src->height-1);
|
|
int nx = xc + 1;
|
|
if (nx>=src->width)
|
|
nx = xc;
|
|
int ny = yc + 1;
|
|
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];
|
|
dst->b[i][j] = (1-Dx)*(1-Dy)*src->b[yc][xc] + (1-Dx)*Dy*src->b[ny][xc] + Dx*(1-Dy)*src->b[yc][nx] + Dx*Dy*src->b[ny][nx];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else if (params->resize.method=="Bilinear") {
|
|
#pragma omp parallel for if (multiThread)
|
|
for (int i=0; i<dst->height; i++) {
|
|
int sy = i/params->resize.scale;
|
|
sy = CLIPTO(sy, 0, src->height-1);
|
|
double dy = i/params->resize.scale - sy;
|
|
int ny = sy+1;
|
|
if (ny>=src->height)
|
|
ny = sy;
|
|
for (int j=0; j<dst->width; j++) {
|
|
int sx = j/params->resize.scale;
|
|
sx = CLIPTO(sx, 0, src->width-1);
|
|
double dx = j/params->resize.scale - sx;
|
|
int nx = sx+1;
|
|
if (nx>=src->width)
|
|
nx = sx;
|
|
dst->r[i][j] = (1-dx)*(1-dy)*src->r[sy][sx] + (1-dx)*dy*src->r[ny][sx] + dx*(1-dy)*src->r[sy][nx] + dx*dy*src->r[ny][nx];
|
|
dst->g[i][j] = (1-dx)*(1-dy)*src->g[sy][sx] + (1-dx)*dy*src->g[ny][sx] + dx*(1-dy)*src->g[sy][nx] + dx*dy*src->g[ny][nx];
|
|
dst->b[i][j] = (1-dx)*(1-dy)*src->b[sy][sx] + (1-dx)*dy*src->b[ny][sx] + dx*(1-dy)*src->b[sy][nx] + dx*dy*src->b[ny][nx];
|
|
}
|
|
}
|
|
}
|
|
else {
|
|
#pragma omp parallel for if (multiThread)
|
|
for (int i=0; i<dst->height; i++) {
|
|
int sy = i/params->resize.scale;
|
|
sy = CLIPTO(sy, 0, src->height-1);
|
|
for (int j=0; j<dst->width; j++) {
|
|
int sx = j/params->resize.scale;
|
|
sx = CLIPTO(sx, 0, src->width-1);
|
|
dst->r[i][j] = src->r[sy][sx];
|
|
dst->g[i][j] = src->g[sy][sx];
|
|
dst->b[i][j] = src->b[sy][sx];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|