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.
 
 
 
 
 
 

214 rivejä
6.3 KiB

  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. * dbs.c: Direct Binary Search dithering functions
  16. */
  17. #include "config.h"
  18. #include "common.h"
  19. #include <math.h>
  20. #include "pipi.h"
  21. #include "pipi_internals.h"
  22. #define N 5
  23. #define NN ((N * 2 + 1))
  24. /* FIXME: use a better HVS than a simple gaussian; adding two gaussians
  25. * seemed to be a lot more efficient. Get rid of pipi_gaussian_blur calls
  26. * at the same time. */
  27. /* FIXME: though the algorithm is supposed to stop, we do not have a real,
  28. * guaranteed stop condition here. */
  29. static void makegauss(double mat[NN][NN], double sigma)
  30. {
  31. double t = 0;
  32. int i, j;
  33. sigma = 2. * sigma * sigma;
  34. for(j = 0; j < NN; j++)
  35. for(i = 0; i < NN; i++)
  36. {
  37. double a = (double)(i - N);
  38. double b = (double)(j - N);
  39. mat[i][j] = pow(M_E, - (a * a + b * b) / sigma);
  40. t += mat[i][j];
  41. }
  42. for(j = 0; j < NN; j++)
  43. for(i = 0; i < NN; i++)
  44. mat[i][j] /= t;
  45. }
  46. pipi_image_t *pipi_dbs(pipi_image_t *src)
  47. {
  48. double mat[NN][NN];
  49. double sigma = 1.2;
  50. pipi_image_t *dst, *tmp1, *tmp2;
  51. pipi_pixels_t *srcp, *dstp, *tmp1p, *tmp2p;
  52. float *srcdata, *dstdata, *tmp1data, *tmp2data;
  53. int w, h;
  54. makegauss(mat, sigma);
  55. w = src->w;
  56. h = src->h;
  57. srcp = pipi_getpixels(src, PIPI_PIXELS_Y_F);
  58. srcdata = (float *)srcp->pixels;
  59. tmp1 = pipi_gaussian_blur(src, sigma);
  60. tmp1p = pipi_getpixels(tmp1, PIPI_PIXELS_Y_F);
  61. tmp1data = (float *)tmp1p->pixels;
  62. /* The initial dither is an empty image. So is its blurred version,
  63. * but I leave the pipi_gaussian_blur() call here in case we choose
  64. * to change the way to create the initial dither. */
  65. dst = pipi_new(w, h);
  66. dstp = pipi_getpixels(dst, PIPI_PIXELS_Y_F);
  67. dstdata = (float *)dstp->pixels;
  68. tmp2 = pipi_gaussian_blur(dst, sigma);
  69. tmp2p = pipi_getpixels(tmp2, PIPI_PIXELS_Y_F);
  70. tmp2data = (float *)tmp2p->pixels;
  71. for(;;)
  72. {
  73. int changes = 0;
  74. int x, y, i, j, n;
  75. for(y = 0; y < h; y++)
  76. for(x = 0; x < w; x++)
  77. {
  78. double d, d2, e, best = 0.;
  79. int opx = -1, opy = -1;
  80. d = dstdata[y * w + x];
  81. /* Compute the effect of a toggle */
  82. e = 0.;
  83. for(j = -N; j < N + 1; j++)
  84. {
  85. if(y + j < 0 || y + j >= h)
  86. continue;
  87. for(i = -N; i < N + 1; i++)
  88. {
  89. double m, p, q1, q2;
  90. if(x + i < 0 || x + i >= w)
  91. continue;
  92. m = mat[i + N][j + N];
  93. p = tmp1data[(y + j) * w + x + i];
  94. q1 = tmp2data[(y + j) * w + x + i];
  95. q2 = q1 - m * d + m * (1. - d);
  96. e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
  97. }
  98. }
  99. if(e > best)
  100. {
  101. best = e;
  102. opx = opy = 0;
  103. }
  104. /* Compute the effect of swaps */
  105. for(n = 0; n < 8; n++)
  106. {
  107. static int const step[] =
  108. { 0, 1, 0, -1, -1, 0, 1, 0, -1, -1, -1, 1, 1, -1, 1, 1 };
  109. int idx = step[n * 2], idy = step[n * 2 + 1];
  110. if(y + idy < 0 || y + idy >= h
  111. || x + idx < 0 || x + idx >= w)
  112. continue;
  113. d2 = dstdata[(y + idy) * w + x + idx];
  114. if(d2 == d)
  115. continue;
  116. e = 0.;
  117. for(j = -N; j < N + 1; j++)
  118. {
  119. if(y + j < 0 || y + j >= h)
  120. continue;
  121. if(j - idy + N < 0 || j - idy + N >= NN)
  122. continue;
  123. for(i = -N; i < N + 1; i++)
  124. {
  125. double ma, mb, p, q1, q2;
  126. if(x + i < 0 || x + i >= w)
  127. continue;
  128. if(i - idx + N < 0 || i - idx + N >= NN)
  129. continue;
  130. ma = mat[i + N][j + N];
  131. mb = mat[i - idx + N][j - idy + N];
  132. p = tmp1data[(y + j) * w + x + i];
  133. q1 = tmp2data[(y + j) * w + x + i];
  134. q2 = q1 - ma * d + ma * d2 - mb * d2 + mb * d;
  135. e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
  136. }
  137. }
  138. if(e > best)
  139. {
  140. best = e;
  141. opx = idx;
  142. opy = idy;
  143. }
  144. }
  145. /* Apply the change if interesting */
  146. if(best <= 0.)
  147. continue;
  148. if(opx || opy)
  149. {
  150. d2 = dstdata[(y + opy) * w + x + opx];
  151. dstdata[(y + opy) * w + x + opx] = d;
  152. }
  153. else
  154. d2 = 1. - d;
  155. dstdata[y * w + x] = d2;
  156. for(j = -N; j < N + 1; j++)
  157. for(i = -N; i < N + 1; i++)
  158. {
  159. double m = mat[i + N][j + N];
  160. if(y + j >= 0 && y + j < h
  161. && x + i >= 0 && x + i < w)
  162. {
  163. double t = tmp2data[(y + j) * w + x + i];
  164. tmp2data[(y + j) * w + x + i] = t + m * (d2 - d);
  165. }
  166. if((opx || opy) && y + opy + j >= 0 && y + opy + j < h
  167. && x + opx + i >= 0 && x + opx + i < w)
  168. {
  169. double t = tmp2data[(y + opy + j) * w + x + opx + i];
  170. tmp2data[(y + opy + j) * w + x + opx + i]
  171. = t + m * (d - d2);
  172. }
  173. }
  174. changes++;
  175. }
  176. if(changes == 0)
  177. break;
  178. }
  179. pipi_free(tmp1);
  180. pipi_free(tmp2);
  181. return dst;
  182. }