You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. /*
  2. * libpipi Proper image processing implementation library
  3. * Copyright (c) 2004-2008 Sam Hocevar <sam@zoy.org>
  4. * All Rights Reserved
  5. *
  6. * $Id$
  7. *
  8. * This library is free software. It comes without any warranty, to
  9. * the extent permitted by applicable law. You can redistribute it
  10. * and/or modify it under the terms of the Do What The Fuck You Want
  11. * To Public License, Version 2, as published by Sam Hocevar. See
  12. * http://sam.zoy.org/wtfpl/COPYING for more details.
  13. */
  14. /*
  15. * blur.c: blur functions
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #include <stdlib.h>
  20. #include <stdio.h>
  21. #include <string.h>
  22. #include <math.h>
  23. #include "pipi.h"
  24. #include "pipi_internals.h"
  25. /* Any standard deviation below this value will be rounded up, in order
  26. * to avoid ridiculously low values. exp(-1/(2*0.2*0.2)) is < 10^-5 so
  27. * there is little chance that any value below 0.2 will be useful. */
  28. #define BLUR_EPSILON 0.2
  29. pipi_image_t *pipi_gaussian_blur(pipi_image_t *src, float radius)
  30. {
  31. return pipi_gaussian_blur_ext(src, radius, radius, 0.0, 0.0, 0.0);
  32. }
  33. pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *src, float rx, float ry,
  34. float angle, float dx, float dy)
  35. {
  36. pipi_image_t *ret;
  37. double *kernel;
  38. double Kx, Ky, t = 0.0, sint, cost, bbx, bby;
  39. int i, j, krx, kry, m, n;
  40. if(rx < BLUR_EPSILON) rx = BLUR_EPSILON;
  41. if(ry < BLUR_EPSILON) ry = BLUR_EPSILON;
  42. sint = sin(angle * M_PI / 180.);
  43. cost = cos(angle * M_PI / 180.);
  44. /* Compute the final ellipse's bounding box */
  45. bbx = sqrt(rx * rx * cost * cost + ry * ry * sint * sint);
  46. bby = sqrt(ry * ry * cost * cost + rx * rx * sint * sint);
  47. /* FIXME: the kernel becomes far too big with large values of dx, because
  48. * we grow both left and right. Fix the growing direction. */
  49. krx = (int)(3. * bbx + .99999 + ceil(abs(dx)));
  50. m = 2 * krx + 1;
  51. Kx = -1. / (2. * rx * rx);
  52. kry = (int)(3. * bby + .99999 + ceil(abs(dy)));
  53. n = 2 * kry + 1;
  54. Ky = -1. / (2. * ry * ry);
  55. kernel = malloc(m * n * sizeof(double));
  56. for(j = -kry; j <= kry; j++)
  57. {
  58. for(i = -krx; i <= krx; i++)
  59. {
  60. /* FIXME: this level of interpolation sucks. We should
  61. * interpolate on the full NxN grid for better quality. */
  62. static double const samples[] =
  63. {
  64. .0, .0, 1,
  65. -.40, -.40, 0.8,
  66. -.30, .0, 0.9,
  67. -.40, .40, 0.8,
  68. .0, .30, 0.9,
  69. .40, .40, 0.8,
  70. .30, .0, 0.9,
  71. .40, -.40, 0.8,
  72. .0, -.30, 0.9,
  73. };
  74. double u, v, ex, ey, d = 0.;
  75. unsigned int k;
  76. for(k = 0; k < sizeof(samples) / sizeof(*samples) / 3; k++)
  77. {
  78. u = ((double)i + samples[k * 3]) * cost
  79. - ((double)j + samples[k * 3 + 1]) * sint + dx;
  80. v = ((double)i + samples[k * 3]) * sint
  81. + ((double)j + samples[k * 3 + 1]) * cost + dy;
  82. ex = Kx * u * u;
  83. ey = Ky * v * v;
  84. d += samples[k * 3 + 2] * exp(ex + ey);
  85. }
  86. kernel[(j + kry) * m + i + krx] = d;
  87. t += d;
  88. }
  89. }
  90. for(j = 0; j < n; j++)
  91. for(i = 0; i < m; i++)
  92. kernel[j * m + i] /= t;
  93. ret = pipi_convolution(src, m, n, kernel);
  94. free(kernel);
  95. return ret;
  96. }
  97. pipi_image_t *pipi_box_blur(pipi_image_t *src, int size)
  98. {
  99. return pipi_box_blur_ext(src, size, size);
  100. }
  101. /* FIXME: split this into templates for wrap-around and proper gray support */
  102. pipi_image_t *pipi_box_blur_ext(pipi_image_t *src, int m, int n)
  103. {
  104. pipi_image_t *dst;
  105. pipi_pixels_t *srcp, *dstp;
  106. float *srcdata, *dstdata;
  107. double *acc;
  108. int x, y, w, h, i, j, size, gray;
  109. w = src->w;
  110. h = src->h;
  111. size = (2 * m + 1) * (2 * n + 1);
  112. gray = (src->last_modified == PIPI_PIXELS_Y_F);
  113. srcp = gray ? pipi_getpixels(src, PIPI_PIXELS_Y_F)
  114. : pipi_getpixels(src, PIPI_PIXELS_RGBA_F);
  115. srcdata = (float *)srcp->pixels;
  116. dst = pipi_new(w, h);
  117. dstp = gray ? pipi_getpixels(dst, PIPI_PIXELS_Y_F)
  118. : pipi_getpixels(dst, PIPI_PIXELS_RGBA_F);
  119. dstdata = (float *)dstp->pixels;
  120. acc = malloc(w * (gray ? 1 : 4) * sizeof(double));
  121. /* Step 1: fill the accumulator */
  122. for(x = 0; x < w; x++)
  123. {
  124. if(gray)
  125. {
  126. double t = 0.;
  127. for(j = -n; j <= n; j++)
  128. {
  129. int j2 = (j < 0) ? h - 1 - ((-j - 1) % h) : j % h;
  130. t += srcdata[j2 * w + x];
  131. }
  132. acc[x] = t;
  133. }
  134. else
  135. {
  136. double r = 0., g = 0., b = 0., a = 0.;
  137. for(j = -n; j <= n; j++)
  138. {
  139. int j2 = (j < 0) ? h - 1 - ((-j - 1) % h) : j % h;
  140. r += srcdata[4 * (j2 * w + x)];
  141. g += srcdata[4 * (j2 * w + x) + 1];
  142. b += srcdata[4 * (j2 * w + x) + 2];
  143. a += srcdata[4 * (j2 * w + x) + 3];
  144. }
  145. acc[4 * x] = r;
  146. acc[4 * x + 1] = g;
  147. acc[4 * x + 2] = b;
  148. acc[4 * x + 3] = a;
  149. }
  150. }
  151. /* Step 2: blur the image, line by line */
  152. for(y = 0; y < h; y++)
  153. {
  154. double r = 0., g = 0., b = 0., a = 0.;
  155. double t = 0.;
  156. /* 2.1: compute the first pixel */
  157. if(gray)
  158. {
  159. for(i = -m; i <= m; i++)
  160. {
  161. int i2 = (i < 0) ? w - 1 - ((-i - 1) % w) : i % w;
  162. t += acc[i2];
  163. }
  164. }
  165. else
  166. {
  167. for(i = -m; i <= m; i++)
  168. {
  169. int i2 = (i < 0) ? w - 1 - ((-i - 1) % w) : i % w;
  170. r += acc[4 * i2];
  171. g += acc[4 * i2 + 1];
  172. b += acc[4 * i2 + 2];
  173. a += acc[4 * i2 + 3];
  174. }
  175. }
  176. /* 2.2: iterate on the whole line */
  177. for(x = 0; x < w; x++)
  178. {
  179. int u, u2, v, v2;
  180. if(gray)
  181. {
  182. dstdata[y * w + x] = t / size;
  183. }
  184. else
  185. {
  186. dstdata[4 * (y * w + x)] = r / size;
  187. dstdata[4 * (y * w + x) + 1] = g / size;
  188. dstdata[4 * (y * w + x) + 2] = b / size;
  189. dstdata[4 * (y * w + x) + 3] = a / size;
  190. }
  191. u = x - m;
  192. u2 = (u < 0) ? w - 1 - ((-u - 1) % w) : u % w;
  193. v = x + m + 1;
  194. v2 = (v < 0) ? w - 1 - ((-v - 1) % w) : v % w;
  195. if(gray)
  196. {
  197. t = t - acc[u2] + acc[v2];
  198. }
  199. else
  200. {
  201. r = r - acc[4 * u2] + acc[4 * v2];
  202. g = g - acc[4 * u2 + 1] + acc[4 * v2 + 1];
  203. b = b - acc[4 * u2 + 2] + acc[4 * v2 + 2];
  204. a = a - acc[4 * u2 + 3] + acc[4 * v2 + 3];
  205. }
  206. }
  207. /* 2.3: update the accumulator */
  208. for(x = 0; x < w; x++)
  209. {
  210. int u, u2, v, v2;
  211. u = y - n;
  212. u2 = (u < 0) ? w - 1 - ((-u - 1) % w) : u % w;
  213. v = y + n + 1;
  214. v2 = (v < 0) ? w - 1 - ((-v - 1) % w) : v % w;
  215. if(gray)
  216. {
  217. acc[x] += srcdata[v2 * w + x] - srcdata[u2 * w + x];
  218. }
  219. else
  220. {
  221. int uoff = 4 * (u2 * w + x);
  222. int voff = 4 * (v2 * w + x);
  223. acc[4 * x] += srcdata[voff] - srcdata[uoff];
  224. acc[4 * x + 1] += srcdata[voff + 1] - srcdata[uoff + 1];
  225. acc[4 * x + 2] += srcdata[voff + 2] - srcdata[uoff + 2];
  226. acc[4 * x + 3] += srcdata[voff + 3] - srcdata[uoff + 3];
  227. }
  228. }
  229. }
  230. free(acc);
  231. return dst;
  232. }