Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.
 
 
 
 
 
 

235 linhas
7.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 <string.h>
  20. #include <stdlib.h>
  21. #include <math.h>
  22. #include "pipi.h"
  23. #include "pipi_internals.h"
  24. #define CELL 16
  25. #define N 7
  26. #define NN ((N * 2 + 1))
  27. /* FIXME: though the algorithm is supposed to stop, we do not have a real,
  28. * guaranteed stop condition here. */
  29. pipi_image_t *pipi_dbs(pipi_image_t *src)
  30. {
  31. double kernel[NN * NN];
  32. double t = 0.;
  33. pipi_image_t *dst, *tmp1, *tmp2;
  34. pipi_pixels_t *srcp, *dstp, *tmp1p, *tmp2p;
  35. int *changelist;
  36. float *srcdata, *dstdata, *tmp1data, *tmp2data;
  37. int i, j, x, y, w, h, cw, ch;
  38. /* Build our human visual system kernel. */
  39. for(j = 0; j < NN; j++)
  40. for(i = 0; i < NN; i++)
  41. {
  42. double a = (double)(i - N);
  43. double b = (double)(j - N);
  44. kernel[j * NN + i] =
  45. exp(-(a * a + b * b) / (2. * 1.6 * 1.6))
  46. + exp(-(a * a + b * b) / (2. * 0.6 * 0.6));
  47. t += kernel[j * NN + i];
  48. }
  49. for(j = 0; j < NN; j++)
  50. for(i = 0; i < NN; i++)
  51. kernel[j * NN + i] /= t;
  52. w = src->w;
  53. h = src->h;
  54. cw = (w + CELL - 1) / CELL;
  55. ch = (h + CELL - 1) / CELL;
  56. changelist = malloc(cw * ch * sizeof(int));
  57. memset(changelist, 0, cw * ch * sizeof(int));
  58. srcp = pipi_getpixels(src, PIPI_PIXELS_Y_F);
  59. srcdata = (float *)srcp->pixels;
  60. tmp1 = pipi_convolution(src, NN, NN, kernel);
  61. tmp1p = pipi_getpixels(tmp1, PIPI_PIXELS_Y_F);
  62. tmp1data = (float *)tmp1p->pixels;
  63. /* The initial dither is an empty image. So is its blurred version,
  64. * but I leave the pipi_convolution() call here in case we choose
  65. * to change the way to create the initial dither. */
  66. dst = pipi_new(w, h);
  67. dstp = pipi_getpixels(dst, PIPI_PIXELS_Y_F);
  68. dstdata = (float *)dstp->pixels;
  69. for(y = 0; y < h; y++)
  70. for(x = 0; x < w; x++)
  71. dstdata[y * w + x] = srcdata[y * w + x] > 0.5 ? 1.0 : 0.0;
  72. tmp2 = pipi_convolution(dst, NN, NN, kernel);
  73. tmp2p = pipi_getpixels(tmp2, PIPI_PIXELS_Y_F);
  74. tmp2data = (float *)tmp2p->pixels;
  75. for(;;)
  76. {
  77. int cx, cy, n;
  78. int allchanges = 0;
  79. for(cy = 0; cy < ch; cy++)
  80. for(cx = 0; cx < cw; cx++)
  81. {
  82. int changes = 0;
  83. if(changelist[cy * cw + cx] >= 2)
  84. continue;
  85. for(y = cy * CELL; y < (cy + 1) * CELL; y++)
  86. for(x = cx * CELL; x < (cx + 1) * CELL; x++)
  87. {
  88. double d, d2, e, best = 0.;
  89. int opx = -1, opy = -1;
  90. d = dstdata[y * w + x];
  91. /* Compute the effect of a toggle */
  92. e = 0.;
  93. for(j = -N; j < N + 1; j++)
  94. {
  95. if(y + j < 0 || y + j >= h)
  96. continue;
  97. for(i = -N; i < N + 1; i++)
  98. {
  99. double m, p, q1, q2;
  100. if(x + i < 0 || x + i >= w)
  101. continue;
  102. m = kernel[(j + N) * NN + i + N];
  103. p = tmp1data[(y + j) * w + x + i];
  104. q1 = tmp2data[(y + j) * w + x + i];
  105. q2 = q1 - m * d + m * (1. - d);
  106. e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
  107. }
  108. }
  109. if(e > best)
  110. {
  111. best = e;
  112. opx = opy = 0;
  113. }
  114. /* Compute the effect of swaps */
  115. for(n = 0; n < 8; n++)
  116. {
  117. static int const step[] =
  118. { 0, 1, 0, -1, -1, 0, 1, 0, -1, -1, -1, 1, 1, -1, 1, 1 };
  119. int idx = step[n * 2], idy = step[n * 2 + 1];
  120. if(y + idy < 0 || y + idy >= h
  121. || x + idx < 0 || x + idx >= w)
  122. continue;
  123. d2 = dstdata[(y + idy) * w + x + idx];
  124. if(d2 == d)
  125. continue;
  126. e = 0.;
  127. for(j = -N; j < N + 1; j++)
  128. {
  129. if(y + j < 0 || y + j >= h)
  130. continue;
  131. if(j - idy + N < 0 || j - idy + N >= NN)
  132. continue;
  133. for(i = -N; i < N + 1; i++)
  134. {
  135. double ma, mb, p, q1, q2;
  136. if(x + i < 0 || x + i >= w)
  137. continue;
  138. if(i - idx + N < 0 || i - idx + N >= NN)
  139. continue;
  140. ma = kernel[(j + N) * NN + i + N];
  141. mb = kernel[(j - idy + N) * NN + i - idx + N];
  142. p = tmp1data[(y + j) * w + x + i];
  143. q1 = tmp2data[(y + j) * w + x + i];
  144. q2 = q1 - ma * d + ma * d2 - mb * d2 + mb * d;
  145. e += (q1 - p) * (q1 - p) - (q2 - p) * (q2 - p);
  146. }
  147. }
  148. if(e > best)
  149. {
  150. best = e;
  151. opx = idx;
  152. opy = idy;
  153. }
  154. }
  155. /* Apply the change if interesting */
  156. if(best <= 0.)
  157. continue;
  158. if(opx || opy)
  159. {
  160. d2 = dstdata[(y + opy) * w + x + opx];
  161. dstdata[(y + opy) * w + x + opx] = d;
  162. }
  163. else
  164. d2 = 1. - d;
  165. dstdata[y * w + x] = d2;
  166. for(j = -N; j < N + 1; j++)
  167. for(i = -N; i < N + 1; i++)
  168. {
  169. double m = kernel[(j + N) * NN + i + N];
  170. if(y + j >= 0 && y + j < h
  171. && x + i >= 0 && x + i < w)
  172. {
  173. t = tmp2data[(y + j) * w + x + i];
  174. tmp2data[(y + j) * w + x + i] = t + m * (d2 - d);
  175. }
  176. if((opx || opy) && y + opy + j >= 0 && y + opy + j < h
  177. && x + opx + i >= 0 && x + opx + i < w)
  178. {
  179. t = tmp2data[(y + opy + j) * w + x + opx + i];
  180. tmp2data[(y + opy + j) * w + x + opx + i]
  181. = t + m * (d - d2);
  182. }
  183. }
  184. changes++;
  185. }
  186. if(changes == 0)
  187. changelist[cy * cw + cx]++;
  188. allchanges += changes;
  189. }
  190. if(allchanges == 0)
  191. break;
  192. }
  193. free(changelist);
  194. pipi_free(tmp1);
  195. pipi_free(tmp2);
  196. return dst;
  197. }