📄 image_filters.cpp
字号:
tmp = image::create_rgb(out_width, in_window_h);
xscale = (float) (out_width - 1) / in_width;
yscale = (float) (out_height - 1) / in_height;
// xxxx protect against division by 0
if (yscale == 0) { yscale = 1.0f; }
if (xscale == 0) { xscale = 1.0f; }
/* pre-calculate filter contributions for a row */
contrib.resize(tmp->m_width);
if(xscale < 1.0f) {
width = support / xscale;
fscale = 1.0f / xscale;
for (i = 0; i < tmp->m_width; ++i) {
contrib[i].resize(0);
center = (float) i / xscale;
left = int(ceilf(center - width));
right = int(floorf(center + width));
for (j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight / fscale) / fscale;
n = iclamp(j, 0, in_window_w - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
} else {
for (i = 0; i < tmp->m_width; ++i) {
contrib[i].resize(0);
center = (float) i / xscale;
left = int(ceilf(center - support));
right = int(floorf(center + support));
for(j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight);
n = iclamp(j, 0, in_window_w - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
}
/* apply filter to zoom horizontally from src to tmp */
raster = (Uint8*) my_calloc(in_window_w, 3);
for (k = 0; k < tmp->m_height; ++k) {
get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
for (i = 0; i < tmp->m_width; ++i) {
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
for(j = 0; j < contrib[i].size(); ++j) {
int pixel = contrib[i][j].pixel;
red += raster[pixel * 3 + 0] * contrib[i][j].weight;
green += raster[pixel * 3 + 1] * contrib[i][j].weight;
blue += raster[pixel * 3 + 2] * contrib[i][j].weight;
}
put_pixel(tmp, i, k, red, green, blue);
}
}
my_cfree(raster);
contrib.resize(out_height);
if (yscale < 1.0f) {
width = support / yscale;
fscale = 1.0f / yscale;
for (i = 0; i < out_height; ++i) {
contrib[i].resize(0);
center = (float) i / yscale;
left = int(ceilf(center - width));
right = int(floorf(center + width));
for (j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight / fscale) / fscale;
n = iclamp(j, 0, tmp->m_height - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
} else {
for (i = 0; i < out_height; ++i) {
contrib[i].resize(0);
center = (float) i / yscale;
left = int(ceilf(center - support));
right = int(floorf(center + support));
for(j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight);
n = iclamp(j, 0, tmp->m_height - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
}
/* apply filter to zoom vertically from tmp to dst */
raster = (Uint8*) my_calloc(tmp->m_height, 3);
for (k = 0; k < tmp->m_width; ++k) {
get_column(raster, tmp, k);
for (i = 0; i < out_height; ++i) {
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
for (j = 0; j < contrib[i].size(); ++j) {
int pixel = contrib[i][j].pixel;
red += raster[pixel * 3 + 0] * contrib[i][j].weight;
green += raster[pixel * 3 + 1] * contrib[i][j].weight;
blue += raster[pixel * 3 + 2] * contrib[i][j].weight;
}
put_pixel(out, k + out_x0, i + out_y0, red, green, blue);
}
}
my_cfree(raster);
contrib.resize(0);
delete tmp;
}
void resample(image::rgba* out, int out_x0, int out_y0, int out_x1, int out_y1,
image::rgba* in, float in_x0, float in_y0, float in_x1, float in_y1)
// Rescale the specified portion of the input image into the specified
// portion of the output image. Coordinates are *inclusive*.
//
// Same as above, but with an alpha channel.
{
assert(out_x0 <= out_x1);
assert(out_y0 <= out_y1);
assert(out_x0 >= 0 && out_x0 < out->m_width);
assert(out_x1 >= 0 && out_x1 < out->m_width);
assert(out_y0 >= 0 && out_y0 < out->m_height);
assert(out_y1 >= 0 && out_y1 < out->m_height);
float (*filter_function)(float);
float support;
// Pick a filter function & support.
assert(default_type >= FILTER0 && default_type < FILTER_COUNT);
filter_function = filter_table[default_type].filter_function;
support = filter_table[default_type].support;
image::rgba* tmp; /* intermediate image */
float xscale, yscale; /* zoom scale factors */
int i, j, k; /* loop variables */
int n; /* pixel number */
float center; int left, right; /* filter calculation variables */
float width, fscale, weight; /* filter calculation variables */
Uint8* raster; /* a row or column of pixels */
array< array<CONTRIB> > contrib;
int out_width = out_x1 - out_x0 + 1;
int out_height = out_y1 - out_y0 + 1;
assert(out_width > 0);
assert(out_height > 0);
float in_width = in_x1 - in_x0;
float in_height = in_y1 - in_y0;
assert(in_width > 0);
assert(in_height > 0);
int in_window_w = int(ceilf(in_x1) - floorf(in_x0) + 1);
int in_window_h = int(ceilf(in_y1) - floorf(in_y0) + 1);
/* create intermediate image to hold horizontal zoom */
tmp = image::create_rgba(out_width, in_window_h);
xscale = (float) (out_width - 1) / in_width;
yscale = (float) (out_height - 1) / in_height;
// xxxx protect against division by 0
if (yscale == 0) { yscale = 1.0f; }
if (xscale == 0) { xscale = 1.0f; }
/* pre-calculate filter contributions for a row */
contrib.resize(tmp->m_width);
if(xscale < 1.0f) {
width = support / xscale;
fscale = 1.0f / xscale;
for (i = 0; i < tmp->m_width; ++i) {
contrib[i].resize(0);
center = (float) i / xscale;
left = int(ceilf(center - width));
right = int(floorf(center + width));
for (j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight / fscale) / fscale;
n = iclamp(j, 0, in_window_w - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
} else {
for (i = 0; i < tmp->m_width; ++i) {
contrib[i].resize(0);
center = (float) i / xscale;
left = int(ceilf(center - support));
right = int(floorf(center + support));
for(j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight);
n = iclamp(j, 0, in_window_w - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
}
/* apply filter to zoom horizontally from src to tmp */
raster = (Uint8*) my_calloc(in_window_w, 4);
for (k = 0; k < tmp->m_height; ++k) {
get_row(raster, in, int(floorf(in_x0)), in_window_w, k);
for (i = 0; i < tmp->m_width; ++i) {
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
float alpha = 0.0f;
for(j = 0; j < contrib[i].size(); ++j) {
int pixel = contrib[i][j].pixel;
red += raster[pixel * 4 + 0] * contrib[i][j].weight;
green += raster[pixel * 4 + 1] * contrib[i][j].weight;
blue += raster[pixel * 4 + 2] * contrib[i][j].weight;
alpha += raster[pixel * 4 + 3] * contrib[i][j].weight;
}
put_pixel(tmp, i, k, red, green, blue, alpha);
}
}
my_cfree(raster);
contrib.resize(out_height);
if (yscale < 1.0f) {
width = support / yscale;
fscale = 1.0f / yscale;
for (i = 0; i < out_height; ++i) {
contrib[i].resize(0);
center = (float) i / yscale;
left = int(ceilf(center - width));
right = int(floorf(center + width));
for (j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight / fscale) / fscale;
n = iclamp(j, 0, tmp->m_height - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
} else {
for (i = 0; i < out_height; ++i) {
contrib[i].resize(0);
center = (float) i / yscale;
left = int(ceilf(center - support));
right = int(floorf(center + support));
for(j = left; j <= right; ++j) {
weight = center - (float) j;
weight = (*filter_function)(weight);
n = iclamp(j, 0, tmp->m_height - 1);
contrib[i].push_back(CONTRIB(n, weight));
}
}
}
/* apply filter to zoom vertically from tmp to dst */
raster = (Uint8*) my_calloc(tmp->m_height, 4);
for (k = 0; k < tmp->m_width; ++k) {
get_column(raster, tmp, k);
for (i = 0; i < out_height; ++i) {
float red = 0.0f;
float green = 0.0f;
float blue = 0.0f;
float alpha = 0.0f;
for (j = 0; j < contrib[i].size(); ++j) {
int pixel = contrib[i][j].pixel;
red += raster[pixel * 4 + 0] * contrib[i][j].weight;
green += raster[pixel * 4 + 1] * contrib[i][j].weight;
blue += raster[pixel * 4 + 2] * contrib[i][j].weight;
alpha += raster[pixel * 4 + 3] * contrib[i][j].weight;
}
put_pixel(out, k + out_x0, i + out_y0, red, green, blue, alpha);
}
}
my_cfree(raster);
contrib.resize(0);
delete tmp;
}
// tulrich: some interesting scaling code from Vitaly. Looks like a
// fast bilinear scale using fixed point. I haven't validated this
// myself. Note: I would see about losing the sax & say arrays, and
// fold that stuff directly into the pixel loops, to get rid of the
// mallocs.
void zoom(image::rgba* src, image::rgba* dst)
{
typedef struct
{
Uint8 r;
Uint8 g;
Uint8 b;
Uint8 a;
}
rgba;
int x, y, sx, sy, *sax, *say, *csax, *csay, csx, csy, ex, ey, t1, t2;
rgba *c00, *c01, *c10, *c11, *sp, *csp, *dp;
int sgap, dgap;
/* For interpolation: assume source dimension is one pixel */
/* smaller to avoid overflow on right and bottom edge. */
sx = (int) (65536.0 * (float) (src->m_width - 1) / (float) dst->m_width);
sy = (int) (65536.0 * (float) (src->m_height - 1) / (float) dst->m_height);
/* Allocate memory for row increments */
sax = (int*) malloc ((dst->m_width + 1) * sizeof (Uint32));
say = (int*) malloc ((dst->m_height + 1) * sizeof (Uint32));
/* Precalculate row increments */
csx = 0;
csax = sax;
for (x = 0; x <= dst->m_width; x++)
{
*csax = csx;
csax++;
csx &= 0xffff;
csx += sx;
}
csy = 0;
csay = say;
for (y = 0; y <= dst->m_height; y++)
{
*csay = csy;
csay++;
csy &= 0xffff;
csy += sy;
}
/* Pointer setup */
sp = csp = (rgba *) src->m_data;
dp = (rgba *) dst->m_data;
sgap = src->m_pitch - src->m_width * 4;
dgap = dst->m_pitch - dst->m_width * 4;
/* Interpolating Zoom */
/* Scan destination */
csay = say;
for (y = 0; y < dst->m_height; y++)
{
/* Setup color source pointers */
c00 = csp;
c01 = csp;
c01++;
c10 = (rgba *) ((Uint8 *) csp + src->m_pitch);
c11 = c10;
c11++;
csax = sax;
for (x = 0; x < dst->m_width; x++)
{
/* ABGR ordering */
/* Interpolate colors */
ex = (*csax & 0xffff);
ey = (*csay & 0xffff);
t1 = ((((c01->r - c00->r) * ex) >> 16) + c00->r) & 0xff;
t2 = ((((c11->r - c10->r) * ex) >> 16) + c10->r) & 0xff;
dp->r = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->g - c00->g) * ex) >> 16) + c00->g) & 0xff;
t2 = ((((c11->g - c10->g) * ex) >> 16) + c10->g) & 0xff;
dp->g = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->b - c00->b) * ex) >> 16) + c00->b) & 0xff;
t2 = ((((c11->b - c10->b) * ex) >> 16) + c10->b) & 0xff;
dp->b = (((t2 - t1) * ey) >> 16) + t1;
t1 = ((((c01->a - c00->a) * ex) >> 16) + c00->a) & 0xff;
t2 = ((((c11->a - c10->a) * ex) >> 16) + c10->a) & 0xff;
dp->a = (((t2 - t1) * ey) >> 16) + t1;
/* Advance source pointers */
csax++;
int sstep = (*csax >> 16);
c00 += sstep;
c01 += sstep;
c10 += sstep;
c11 += sstep;
/* Advance destination pointer */
dp++;
}
/* Advance source pointer */
csay++;
csp = (rgba *) ((Uint8 *) csp + (*csay >> 16) * src->m_pitch);
/* Advance destination pointers */
dp = (rgba *) ((Uint8 *) dp + dgap);
}
/* Remove temp arrays */
free (sax);
free (say);
}
} // end namespace image
// Local Variables:
// mode: C++
// c-basic-offset: 8
// tab-width: 8
// indent-tabs-mode: t
// End:
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -