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-862c8a59935f
remotes/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 *); | ||||