Of course since the kernel is no longer separable, it becomes awfully slow with large images. Here is a tileable brushed metal texture: # pipi pipi:random512x512 --wrap --blur 20x0r25 -o image.png git-svn-id: file:///srv/caca.zoy.org/var/lib/svn/libpipi/trunk@2715 92316355-f0b4-4df1-b90c-862c8a59935fremotes/tiles
@@ -61,7 +61,7 @@ int main(int argc, char *argv[]) | |||||
pipi_free(tmp); | pipi_free(tmp); | ||||
/* Compute the fast error */ | /* Compute the fast error */ | ||||
tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, 0.16, 0.26); | |||||
tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, 0.0, 0.16, 0.26); | |||||
e1 = pipi_measure_msd(gauss, tmp); | e1 = pipi_measure_msd(gauss, tmp); | ||||
pipi_free(tmp); | pipi_free(tmp); | ||||
@@ -71,7 +71,7 @@ int main(int argc, char *argv[]) | |||||
for(dy = 0; dy <= Z; dy++) | for(dy = 0; dy <= Z; dy++) | ||||
for(dx = 0; dx <= Z; dx++) | for(dx = 0; dx <= Z; dx++) | ||||
{ | { | ||||
tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, | |||||
tmp = pipi_gaussian_blur_ext(dither, sigma, sigma, 0.0, | |||||
fx + step * dx / Z, | fx + step * dx / Z, | ||||
fy + step * dy / Z); | fy + step * dy / Z); | ||||
e = pipi_measure_msd(gauss, tmp); | e = pipi_measure_msd(gauss, tmp); | ||||
@@ -118,7 +118,7 @@ int pipi_command(pipi_context_t *ctx, char const *cmd, ...) | |||||
pipi_image_t *src, *dst; | pipi_image_t *src, *dst; | ||||
char const *arg; | char const *arg; | ||||
va_list ap; | va_list ap; | ||||
double w, h; | |||||
double w, h, a = 0.0; | |||||
if(ctx->nimages < 1) | if(ctx->nimages < 1) | ||||
return -1; | return -1; | ||||
@@ -128,9 +128,14 @@ int pipi_command(pipi_context_t *ctx, char const *cmd, ...) | |||||
w = h = atof(arg); | w = h = atof(arg); | ||||
arg = strchr(arg, 'x'); | arg = strchr(arg, 'x'); | ||||
if(arg) | if(arg) | ||||
{ | |||||
h = atof(arg + 1); | h = atof(arg + 1); | ||||
arg = strchr(arg, 'r'); | |||||
if(arg) | |||||
a = atof(arg + 1); | |||||
} | |||||
src = ctx->images[ctx->nimages - 1]; | src = ctx->images[ctx->nimages - 1]; | ||||
dst = pipi_gaussian_blur_ext(src, w, h, 0.0, 0.0); | |||||
dst = pipi_gaussian_blur_ext(src, w, h, a, 0.0, 0.0); | |||||
if(dst == NULL) | if(dst == NULL) | ||||
return -1; | return -1; | ||||
pipi_free(src); | pipi_free(src); | ||||
@@ -34,27 +34,34 @@ | |||||
pipi_image_t *pipi_gaussian_blur(pipi_image_t *src, float radius) | pipi_image_t *pipi_gaussian_blur(pipi_image_t *src, float radius) | ||||
{ | { | ||||
return pipi_gaussian_blur_ext(src, radius, radius, 0.0, 0.0); | |||||
return pipi_gaussian_blur_ext(src, radius, radius, 0.0, 0.0, 0.0); | |||||
} | } | ||||
pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *src, float rx, float ry, | pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *src, float rx, float ry, | ||||
float dx, float dy) | |||||
float angle, float dx, float dy) | |||||
{ | { | ||||
pipi_image_t *ret; | pipi_image_t *ret; | ||||
double *kernel; | double *kernel; | ||||
double Kx, Ky, t = 0.0; | |||||
double Kx, Ky, t = 0.0, sint, cost, bbx, bby; | |||||
int i, j, krx, kry, m, n; | int i, j, krx, kry, m, n; | ||||
if(rx < BLUR_EPSILON) rx = BLUR_EPSILON; | if(rx < BLUR_EPSILON) rx = BLUR_EPSILON; | ||||
if(ry < BLUR_EPSILON) ry = BLUR_EPSILON; | if(ry < BLUR_EPSILON) ry = BLUR_EPSILON; | ||||
sint = sin(angle * M_PI / 180.); | |||||
cost = cos(angle * M_PI / 180.); | |||||
/* Compute the final ellipse's bounding box */ | |||||
bbx = sqrt(rx * rx * cost * cost + ry * ry * sint * sint); | |||||
bby = sqrt(ry * ry * cost * cost + rx * rx * sint * sint); | |||||
/* FIXME: the kernel becomes far too big with large values of dx, because | /* FIXME: the kernel becomes far too big with large values of dx, because | ||||
* we grow both left and right. Fix the growing direction. */ | * we grow both left and right. Fix the growing direction. */ | ||||
krx = (int)(3. * rx + .99999 + ceil(abs(dx))); | |||||
krx = (int)(3. * bbx + .99999 + ceil(abs(dx))); | |||||
m = 2 * krx + 1; | m = 2 * krx + 1; | ||||
Kx = -1. / (2. * rx * rx); | Kx = -1. / (2. * rx * rx); | ||||
kry = (int)(3. * ry + .99999 + ceil(abs(dy))); | |||||
kry = (int)(3. * bby + .99999 + ceil(abs(dy))); | |||||
n = 2 * kry + 1; | n = 2 * kry + 1; | ||||
Ky = -1. / (2. * ry * ry); | Ky = -1. / (2. * ry * ry); | ||||
@@ -62,11 +69,12 @@ pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *src, float rx, float ry, | |||||
for(j = -kry; j <= kry; j++) | for(j = -kry; j <= kry; j++) | ||||
{ | { | ||||
double ey = Ky * ((double)j + dy) * ((double)j + dy); | |||||
for(i = -krx; i <= krx; i++) | for(i = -krx; i <= krx; i++) | ||||
{ | { | ||||
double ex = Kx * ((double)i + dx) * ((double)i + dx); | |||||
double u = (double)i * cost - (double)j * sint + dx; | |||||
double v = (double)j * cost + (double)i * sint + dy; | |||||
double ex = Kx * u * u; | |||||
double ey = Ky * v * v; | |||||
double d = exp(ex + ey); | double d = exp(ex + ey); | ||||
kernel[(j + kry) * m + i + krx] = d; | kernel[(j + kry) * m + i + krx] = d; | ||||
@@ -99,7 +99,7 @@ extern pipi_image_t *pipi_overlay(pipi_image_t *, pipi_image_t *); | |||||
extern pipi_image_t *pipi_convolution(pipi_image_t *, int, int, double[]); | extern pipi_image_t *pipi_convolution(pipi_image_t *, int, int, double[]); | ||||
extern pipi_image_t *pipi_gaussian_blur(pipi_image_t *, float); | extern pipi_image_t *pipi_gaussian_blur(pipi_image_t *, float); | ||||
extern pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *, | extern pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *, | ||||
float, float, float, float); | |||||
float, float, float, float, float); | |||||
extern pipi_image_t *pipi_box_blur(pipi_image_t *, int); | extern pipi_image_t *pipi_box_blur(pipi_image_t *, int); | ||||
extern pipi_image_t *pipi_box_blur_ext(pipi_image_t *, int, int); | extern pipi_image_t *pipi_box_blur_ext(pipi_image_t *, int, int); | ||||
extern pipi_image_t *pipi_autocontrast(pipi_image_t *); | extern pipi_image_t *pipi_autocontrast(pipi_image_t *); | ||||