Files
rawTherapee/rtengine/ipresize.cc
ffsup2 eef14f76dd Added dark frame subtraction
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)
2010-08-19 00:37:53 +02:00

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];
}
}
}
}
}