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.
 
 
 
 
 
 

316 lines
8.8 KiB

  1. /*
  2. * libpipi Pathetic image processing interface 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 <stdlib.h>
  19. #include <stdio.h>
  20. #include <string.h>
  21. #include <math.h>
  22. #ifndef M_PI
  23. # define M_PI 3.14159265358979323846
  24. #endif
  25. #include "pipi.h"
  26. #include "pipi_internals.h"
  27. #if !defined TEMPLATE_FILE /* This file uses the template system */
  28. #define TEMPLATE_FLAGS SET_FLAG_GRAY | SET_FLAG_WRAP
  29. #define TEMPLATE_FILE "filter/blur.c"
  30. #include "pipi_template.h"
  31. /* Any standard deviation below this value will be rounded up, in order
  32. * to avoid ridiculously low values. exp(-1/(2*0.2*0.2)) is < 10^-5 so
  33. * there is little chance that any value below 0.2 will be useful. */
  34. #define BLUR_EPSILON 0.2
  35. pipi_image_t *pipi_gaussian_blur(pipi_image_t *src, float radius)
  36. {
  37. return pipi_gaussian_blur_ext(src, radius, radius, 0.0, 0.0, 0.0);
  38. }
  39. pipi_image_t *pipi_gaussian_blur_ext(pipi_image_t *src, float rx, float ry,
  40. float angle, float dx, float dy)
  41. {
  42. pipi_image_t *ret;
  43. double *kernel;
  44. double Kx, Ky, t = 0.0, sint, cost, bbx, bby;
  45. int i, j, krx, kry, m, n;
  46. if(rx < BLUR_EPSILON) rx = BLUR_EPSILON;
  47. if(ry < BLUR_EPSILON) ry = BLUR_EPSILON;
  48. sint = sin(angle * M_PI / 180.);
  49. cost = cos(angle * M_PI / 180.);
  50. /* Compute the final ellipse's bounding box */
  51. bbx = sqrt(rx * rx * cost * cost + ry * ry * sint * sint);
  52. bby = sqrt(ry * ry * cost * cost + rx * rx * sint * sint);
  53. /* FIXME: the kernel becomes far too big with large values of dx, because
  54. * we grow both left and right. Fix the growing direction. */
  55. krx = (int)(3. * bbx + .99999 + ceil(abs(dx)));
  56. m = 2 * krx + 1;
  57. Kx = -1. / (2. * rx * rx);
  58. kry = (int)(3. * bby + .99999 + ceil(abs(dy)));
  59. n = 2 * kry + 1;
  60. Ky = -1. / (2. * ry * ry);
  61. kernel = malloc(m * n * sizeof(double));
  62. for(j = -kry; j <= kry; j++)
  63. {
  64. for(i = -krx; i <= krx; i++)
  65. {
  66. /* FIXME: this level of interpolation sucks. We should
  67. * interpolate on the full NxN grid for better quality. */
  68. static double const samples[] =
  69. {
  70. .0, .0, 1,
  71. -.40, -.40, 0.8,
  72. -.30, .0, 0.9,
  73. -.40, .40, 0.8,
  74. .0, .30, 0.9,
  75. .40, .40, 0.8,
  76. .30, .0, 0.9,
  77. .40, -.40, 0.8,
  78. .0, -.30, 0.9,
  79. };
  80. double u, v, ex, ey, d = 0.;
  81. unsigned int k;
  82. for(k = 0; k < sizeof(samples) / sizeof(*samples) / 3; k++)
  83. {
  84. u = ((double)i + samples[k * 3]) * cost
  85. - ((double)j + samples[k * 3 + 1]) * sint + dx;
  86. v = ((double)i + samples[k * 3]) * sint
  87. + ((double)j + samples[k * 3 + 1]) * cost + dy;
  88. ex = Kx * u * u;
  89. ey = Ky * v * v;
  90. d += samples[k * 3 + 2] * exp(ex + ey);
  91. /* Do not interpolate if this is a standard gaussian. */
  92. if(!dx && !dy && !angle)
  93. break;
  94. }
  95. kernel[(j + kry) * m + i + krx] = d;
  96. t += d;
  97. }
  98. }
  99. for(j = 0; j < n; j++)
  100. for(i = 0; i < m; i++)
  101. kernel[j * m + i] /= t;
  102. ret = pipi_convolution(src, m, n, kernel);
  103. free(kernel);
  104. return ret;
  105. }
  106. pipi_image_t *pipi_box_blur(pipi_image_t *src, int size)
  107. {
  108. return pipi_box_blur_ext(src, size, size);
  109. }
  110. pipi_image_t *pipi_box_blur_ext(pipi_image_t *src, int m, int n)
  111. {
  112. if(src->wrap)
  113. {
  114. if(src->last_modified == PIPI_PIXELS_Y_F32)
  115. return boxblur_gray_wrap(src, m, n);
  116. return boxblur_wrap(src, m, n);
  117. }
  118. else
  119. {
  120. if(src->last_modified == PIPI_PIXELS_Y_F32)
  121. return boxblur_gray(src, m, n);
  122. return boxblur(src, m, n);
  123. }
  124. }
  125. #else /* XXX: the following functions use the template system */
  126. static pipi_image_t *T(boxblur)(pipi_image_t *src, int m, int n)
  127. {
  128. pipi_image_t *dst;
  129. pipi_pixels_t *srcp, *dstp;
  130. float *srcdata, *dstdata;
  131. double *acc;
  132. int x, y, w, h, i, j, i2, j2, size;
  133. w = src->w;
  134. h = src->h;
  135. size = (2 * m + 1) * (2 * n + 1);
  136. srcp = FLAG_GRAY ? pipi_get_pixels(src, PIPI_PIXELS_Y_F32)
  137. : pipi_get_pixels(src, PIPI_PIXELS_RGBA_F32);
  138. srcdata = (float *)srcp->pixels;
  139. dst = pipi_new(w, h);
  140. dstp = FLAG_GRAY ? pipi_get_pixels(dst, PIPI_PIXELS_Y_F32)
  141. : pipi_get_pixels(dst, PIPI_PIXELS_RGBA_F32);
  142. dstdata = (float *)dstp->pixels;
  143. acc = malloc(w * (FLAG_GRAY ? 1 : 4) * sizeof(double));
  144. /* Step 1: fill the accumulator */
  145. for(x = 0; x < w; x++)
  146. {
  147. double r = 0., g = 0., b = 0., a = 0.;
  148. double t = 0.;
  149. for(j = -n; j <= n; j++)
  150. {
  151. if(FLAG_WRAP)
  152. j2 = (j < 0) ? h - 1 - ((-j - 1) % h) : j % h;
  153. else
  154. j2 = (j < 0) ? 0 : (j >= h) ? h - 1 : j;
  155. if(FLAG_GRAY)
  156. t += srcdata[j2 * w + x];
  157. else
  158. {
  159. r += srcdata[4 * (j2 * w + x)];
  160. g += srcdata[4 * (j2 * w + x) + 1];
  161. b += srcdata[4 * (j2 * w + x) + 2];
  162. a += srcdata[4 * (j2 * w + x) + 3];
  163. }
  164. }
  165. if(FLAG_GRAY)
  166. acc[x] = t;
  167. else
  168. {
  169. acc[4 * x] = r;
  170. acc[4 * x + 1] = g;
  171. acc[4 * x + 2] = b;
  172. acc[4 * x + 3] = a;
  173. }
  174. }
  175. /* Step 2: blur the image, line by line */
  176. for(y = 0; y < h; y++)
  177. {
  178. double r = 0., g = 0., b = 0., a = 0.;
  179. double t = 0.;
  180. /* 2.1: compute the first pixel */
  181. for(i = -m; i <= m; i++)
  182. {
  183. if(FLAG_WRAP)
  184. i2 = (i < 0) ? w - 1 - ((-i - 1) % w) : i % w;
  185. else
  186. i2 = (i < 0) ? 0 : (i >= w) ? w - 1 : i;
  187. if(FLAG_GRAY)
  188. t += acc[i2];
  189. else
  190. {
  191. r += acc[4 * i2];
  192. g += acc[4 * i2 + 1];
  193. b += acc[4 * i2 + 2];
  194. a += acc[4 * i2 + 3];
  195. }
  196. }
  197. /* 2.2: iterate on the whole line */
  198. for(x = 0; x < w; x++)
  199. {
  200. int u, u2, v, v2;
  201. if(FLAG_GRAY)
  202. {
  203. dstdata[y * w + x] = t / size;
  204. }
  205. else
  206. {
  207. dstdata[4 * (y * w + x)] = r / size;
  208. dstdata[4 * (y * w + x) + 1] = g / size;
  209. dstdata[4 * (y * w + x) + 2] = b / size;
  210. dstdata[4 * (y * w + x) + 3] = a / size;
  211. }
  212. u = x - m;
  213. if(FLAG_WRAP)
  214. u2 = (u < 0) ? w - 1 - ((-u - 1) % w) : u % w;
  215. else
  216. u2 = (u < 0) ? 0 : (u >= w) ? w - 1 : u;
  217. v = x + m + 1;
  218. if(FLAG_WRAP)
  219. v2 = (v < 0) ? w - 1 - ((-v - 1) % w) : v % w;
  220. else
  221. v2 = (v < 0) ? 0 : (v >= w) ? w - 1 : v;
  222. if(FLAG_GRAY)
  223. {
  224. t = t - acc[u2] + acc[v2];
  225. }
  226. else
  227. {
  228. r = r - acc[4 * u2] + acc[4 * v2];
  229. g = g - acc[4 * u2 + 1] + acc[4 * v2 + 1];
  230. b = b - acc[4 * u2 + 2] + acc[4 * v2 + 2];
  231. a = a - acc[4 * u2 + 3] + acc[4 * v2 + 3];
  232. }
  233. }
  234. /* 2.3: update the accumulator */
  235. for(x = 0; x < w; x++)
  236. {
  237. int u, u2, v, v2;
  238. u = y - n;
  239. if(FLAG_WRAP)
  240. u2 = (u < 0) ? h - 1 - ((-u - 1) % h) : u % h;
  241. else
  242. u2 = (u < 0) ? 0 : (u >= h) ? h - 1 : u;
  243. v = y + n + 1;
  244. if(FLAG_WRAP)
  245. v2 = (v < 0) ? h - 1 - ((-v - 1) % h) : v % h;
  246. else
  247. v2 = (v < 0) ? 0 : (v >= h) ? h - 1 : v;
  248. if(FLAG_GRAY)
  249. {
  250. acc[x] += srcdata[v2 * w + x] - srcdata[u2 * w + x];
  251. }
  252. else
  253. {
  254. int uoff = 4 * (u2 * w + x);
  255. int voff = 4 * (v2 * w + x);
  256. acc[4 * x] += srcdata[voff] - srcdata[uoff];
  257. acc[4 * x + 1] += srcdata[voff + 1] - srcdata[uoff + 1];
  258. acc[4 * x + 2] += srcdata[voff + 2] - srcdata[uoff + 2];
  259. acc[4 * x + 3] += srcdata[voff + 3] - srcdata[uoff + 3];
  260. }
  261. }
  262. }
  263. free(acc);
  264. return dst;
  265. }
  266. #endif