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.
 
 
 
 
 
 

464 lines
12 KiB

  1. /*
  2. * filters.c: various image filters
  3. * $Id$
  4. *
  5. * Copyright: (c) 2004 Sam Hocevar <sam@zoy.org>
  6. * This program is free software. It comes without any warranty, to
  7. * the extent permitted by applicable law. You can redistribute it
  8. * and/or modify it under the terms of the Do What The Fuck You Want
  9. * To Public License, Version 2, as published by Sam Hocevar. See
  10. * http://sam.zoy.org/wtfpl/COPYING for more details.
  11. */
  12. #include <stdio.h>
  13. #include <stdlib.h>
  14. #include <string.h>
  15. #include <math.h>
  16. #include "config.h"
  17. #include "common.h"
  18. /* Functions */
  19. void filter_flood_fill(struct image *img, int x, int y, int r, int g, int b)
  20. {
  21. int oldr, oldg, oldb;
  22. int nextr, nextg, nextb;
  23. if(x < 0 || y < 0 || x >= img->width || y >= img->height)
  24. return;
  25. getpixel(img, x, y, &oldr, &oldg, &oldb);
  26. setpixel(img, x, y, r, g, b);
  27. getpixel(img, x + 1, y, &nextr, &nextg, &nextb);
  28. if(nextr == oldr && nextg == oldg && nextb == oldb)
  29. filter_flood_fill(img, x + 1, y, r, g, b);
  30. getpixel(img, x - 1, y, &nextr, &nextg, &nextb);
  31. if(nextr == oldr && nextg == oldg && nextb == oldb)
  32. filter_flood_fill(img, x - 1, y, r, g, b);
  33. getpixel(img, x, y + 1, &nextr, &nextg, &nextb);
  34. if(nextr == oldr && nextg == oldg && nextb == oldb)
  35. filter_flood_fill(img, x, y + 1, r, g, b);
  36. getpixel(img, x, y - 1, &nextr, &nextg, &nextb);
  37. if(nextr == oldr && nextg == oldg && nextb == oldb)
  38. filter_flood_fill(img, x, y - 1, r, g, b);
  39. }
  40. void filter_scale(struct image *img, float ratio)
  41. {
  42. struct image *dst;
  43. int w, h, x, y;
  44. int r, g, b;
  45. w = ratio * img->width;
  46. h = ratio * img->height;
  47. dst = image_new(w, h);
  48. for(y = 0; y < h; y++)
  49. for(x = 0; x < w; x++)
  50. {
  51. getpixel(img, x / ratio, y / ratio, &r, &g, &b);
  52. setpixel(dst, x, y, r, g, b);
  53. }
  54. image_swap(img, dst);
  55. image_free(dst);
  56. }
  57. void filter_fill_holes(struct image *img)
  58. {
  59. struct image *dst;
  60. int x, y;
  61. int r, g, b;
  62. dst = image_new(img->width, img->height);
  63. for(y = 0; y < img->height; y++)
  64. for(x = 0; x < img->width; x++)
  65. {
  66. getpixel(img, x, y, &r, &g, &b);
  67. setpixel(dst, x, y, r, g, b);
  68. }
  69. for(y = 0; y < dst->height; y++)
  70. for(x = 2; x < dst->width - 2; x++)
  71. {
  72. int c1, c2, c3, c4, c5;
  73. getpixel(img, x-2, y, &c1, &g, &b);
  74. getpixel(img, x-1, y, &c2, &g, &b);
  75. getpixel(img, x, y, &c3, &g, &b);
  76. getpixel(img, x+1, y, &c4, &g, &b);
  77. getpixel(img, x+2, y, &c5, &g, &b);
  78. if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127)
  79. c3 = (c1 + c2 + c4) / 3;
  80. else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127)
  81. c3 = (c2 + c4 + c5) / 3;
  82. setpixel(dst, x, y, c3, c3, c3);
  83. }
  84. for(x = 0; x < dst->width; x++)
  85. for(y = 2; y < dst->height - 2; y++)
  86. {
  87. int c1, c2, c3, c4, c5;
  88. getpixel(img, x, y-2, &c1, &g, &b);
  89. getpixel(img, x, y-1, &c2, &g, &b);
  90. getpixel(img, x, y, &c3, &g, &b);
  91. getpixel(img, x, y+1, &c4, &g, &b);
  92. getpixel(img, x, y+2, &c5, &g, &b);
  93. if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127)
  94. c3 = (c1 + c2 + c4) / 3;
  95. else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127)
  96. c3 = (c2 + c4 + c5) / 3;
  97. setpixel(dst, x, y, c3, c3, c3);
  98. }
  99. image_swap(img, dst);
  100. image_free(dst);
  101. }
  102. void filter_black_stuff(struct image *img)
  103. {
  104. struct image *dst;
  105. int x, y;
  106. int r, ra, rb, g, b;
  107. dst = image_new(img->width, img->height);
  108. /* Remove vertical stuff */
  109. for(y = 0; y < img->height; y++)
  110. for(x = 0; x < img->width; x++)
  111. {
  112. getpixel(img, x, y, &r, &g, &b);
  113. setpixel(dst, x, y, r, g, b);
  114. if(y > 0 && y < img->height - 1)
  115. {
  116. getpixel(img, x, y - 1, &ra, &g, &b);
  117. getpixel(img, x, y + 1, &rb, &g, &b);
  118. if(r < ra && (r - ra) * (r - rb) > 5000)
  119. setpixel(dst, x, y, ra, ra, ra);
  120. }
  121. }
  122. /* Remove horizontal stuff */
  123. for(y = 0; y < img->height; y++)
  124. for(x = 0; x < img->width; x++)
  125. {
  126. getpixel(img, x, y, &r, &g, &b);
  127. if(x > 0 && x < img->width - 1)
  128. {
  129. getpixel(dst, x - 1, y, &ra, &g, &b);
  130. getpixel(dst, x + 1, y, &rb, &g, &b);
  131. if(r < ra && (r - ra) * (r - rb) > 5000)
  132. setpixel(dst, x, y, ra, ra, ra);
  133. }
  134. }
  135. image_swap(img, dst);
  136. image_free(dst);
  137. }
  138. void filter_detect_lines(struct image *img)
  139. {
  140. struct image *dst;
  141. int x, y;
  142. int r, ra, rb, g, b;
  143. dst = image_new(img->width, img->height);
  144. /* Remove white lines */
  145. for(y = 0; y < img->height; y++)
  146. for(x = 0; x < img->width; x++)
  147. {
  148. getpixel(img, x, y, &r, &g, &b);
  149. setpixel(dst, x, y, r, g, b);
  150. if(y > 0 && y < img->height - 1)
  151. {
  152. getpixel(img, x, y - 1, &ra, &g, &b);
  153. getpixel(img, x, y + 1, &rb, &g, &b);
  154. if(r > ra && (r - ra) * (r - rb) > 5000)
  155. setpixel(dst, x, y, ra, ra, ra);
  156. }
  157. }
  158. /* Remove black lines */
  159. for(y = 0; y < img->height; y++)
  160. for(x = 0; x < img->width; x++)
  161. {
  162. getpixel(dst, x, y, &r, &g, &b);
  163. if(y > 0 && y < img->height - 1)
  164. {
  165. getpixel(img, x, y - 1, &ra, &g, &b);
  166. getpixel(img, x, y + 1, &rb, &g, &b);
  167. if(r < ra && (r - ra) * (r - rb) > 500)
  168. setpixel(dst, x, y, ra, ra, ra);
  169. }
  170. }
  171. image_swap(img, dst);
  172. image_free(dst);
  173. }
  174. void filter_threshold(struct image *img, int threshold)
  175. {
  176. struct image *dst;
  177. int x, y;
  178. int r, g, b;
  179. int min = 0, max = 255;
  180. dst = image_new(img->width, img->height);
  181. if(threshold < 0)
  182. {
  183. min = 255;
  184. max = 0;
  185. threshold = -threshold;
  186. }
  187. threshold *= 3;
  188. for(y = 0; y < img->height; y++)
  189. for(x = 0; x < img->width; x++)
  190. {
  191. getpixel(img, x, y, &r, &g, &b);
  192. if(r + g + b < threshold)
  193. setpixel(dst, x, y, min, min, min);
  194. else
  195. setpixel(dst, x, y, max, max, max);
  196. }
  197. image_swap(img, dst);
  198. image_free(dst);
  199. }
  200. void filter_trick(struct image *img)
  201. {
  202. #define TSIZE 3
  203. struct image *dst;
  204. int x, y, i, j, val, m, more, l, less;
  205. int r, g, b;
  206. dst = image_new(img->width, img->height);
  207. for(y = 0; y < img->height; y++)
  208. for(x = 0; x < img->width; x++)
  209. setpixel(dst, x, y, 255, 255, 255);
  210. for(y = TSIZE/2; y < img->height - TSIZE/2; y++)
  211. for(x = TSIZE/2; x < img->width - TSIZE/2; x++)
  212. {
  213. getpixel(img, x + TSIZE - TSIZE/2, y + TSIZE - TSIZE/2, &val, &g, &b);
  214. m = more = l = less = 0;
  215. for(i = 0; i < TSIZE; i++)
  216. for(j = 0; j < TSIZE; j++)
  217. {
  218. getpixel(img, x + j - TSIZE/2, y + i - TSIZE/2, &r, &g, &b);
  219. if(r > val)
  220. {
  221. more += r;
  222. m++;
  223. }
  224. else if(r < val)
  225. {
  226. less += r;
  227. l++;
  228. }
  229. }
  230. if(l >= 6)
  231. i = less / l;
  232. else if(m >= 6)
  233. i = more / m;
  234. else
  235. i = val;
  236. setpixel(dst, x, y, i, i, i);
  237. }
  238. image_swap(img, dst);
  239. image_free(dst);
  240. }
  241. void filter_smooth(struct image *img)
  242. {
  243. #define SSIZE 3
  244. struct image *dst;
  245. int x, y, i, j, val;
  246. int r, g, b;
  247. dst = image_new(img->width, img->height);
  248. for(y = 0; y < img->height; y++)
  249. for(x = 0; x < img->width; x++)
  250. {
  251. getpixel(img, x, y, &r, &g, &b);
  252. setpixel(dst, x, y, r, g, b);
  253. }
  254. for(y = SSIZE/2; y < img->height - SSIZE/2; y++)
  255. for(x = SSIZE/2; x < img->width - SSIZE/2; x++)
  256. {
  257. val = 0;
  258. for(i = 0; i < SSIZE; i++)
  259. for(j = 0; j < SSIZE; j++)
  260. {
  261. getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b);
  262. val += r;
  263. }
  264. i = val / (SSIZE * SSIZE);
  265. setpixel(dst, x, y, i, i, i);
  266. }
  267. /* Remove border */
  268. for(y = 0; y < dst->height; y++)
  269. {
  270. getpixel(dst, 1, y, &r, &g, &b);
  271. setpixel(dst, 0, y, r, g, b);
  272. getpixel(dst, dst->width - 2, y, &r, &g, &b);
  273. setpixel(dst, dst->width - 1, y, r, g, b);
  274. }
  275. for(x = 0; x < dst->width; x++)
  276. {
  277. getpixel(dst, x, 1, &r, &g, &b);
  278. setpixel(dst, x, 0, r, g, b);
  279. getpixel(dst, x, dst->height - 2, &r, &g, &b);
  280. setpixel(dst, x, dst->height - 1, r, g, b);
  281. }
  282. image_swap(img, dst);
  283. image_free(dst);
  284. }
  285. void filter_median(struct image *img)
  286. {
  287. #define MSIZE 3
  288. struct image *dst;
  289. int x, y, i, j, val[MSIZE*MSIZE];
  290. int r, g, b;
  291. dst = image_new(img->width, img->height);
  292. for(y = 0; y < img->height; y++)
  293. for(x = 0; x < img->width; x++)
  294. setpixel(dst, x, y, 255, 255, 255);
  295. for(y = MSIZE/2; y < img->height - MSIZE/2; y++)
  296. for(x = MSIZE/2; x < img->width - MSIZE/2; x++)
  297. {
  298. for(i = 0; i < MSIZE; i++)
  299. for(j = 0; j < MSIZE; j++)
  300. {
  301. getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b);
  302. val[i * MSIZE + j] = r;
  303. }
  304. /* Bubble sort power! */
  305. for(i = 0; i < MSIZE * MSIZE / 2 + 1; i++)
  306. for(j = i + 1; j < MSIZE * MSIZE; j++)
  307. if(val[i] > val[j])
  308. {
  309. register int k = val[i];
  310. val[i] = val[j];
  311. val[j] = k;
  312. }
  313. i = val[MSIZE * MSIZE / 2];
  314. setpixel(dst, x, y, i, i, i);
  315. }
  316. image_swap(img, dst);
  317. image_free(dst);
  318. }
  319. void filter_contrast(struct image *img)
  320. {
  321. struct image *dst;
  322. int histo[256];
  323. int x, y, i, min = 255, max = 0;
  324. int r, g, b;
  325. dst = image_new(img->width, img->height);
  326. for(y = 0; y < img->height; y++)
  327. for(x = 0; x < img->width; x++)
  328. {
  329. getgray(img, x, y, &r);
  330. if(r < min) min = r;
  331. if(r > max) max = r;
  332. }
  333. if(min == max)
  334. histo[min] = 127;
  335. else
  336. for(i = min; i < max + 1; i++)
  337. histo[i] = (i - min) * 255 / (max - min);
  338. for(y = 0; y < img->height; y++)
  339. for(x = 0; x < img->width; x++)
  340. {
  341. getgray(img, x, y, &r);
  342. setpixel(dst, x, y, histo[r], histo[r], histo[r]);
  343. }
  344. image_swap(img, dst);
  345. image_free(dst);
  346. }
  347. void filter_crop(struct image *img, int xmin, int ymin, int xmax, int ymax)
  348. {
  349. struct image *dst;
  350. int x, y;
  351. int r, g, b;
  352. if(xmin < 0)
  353. xmin = 0;
  354. if(ymin < 0)
  355. ymin = 0;
  356. if(xmax >= img->width)
  357. xmax = img->width - 1;
  358. if(ymax >= img->height)
  359. ymax = img->height - 1;
  360. if(xmin >= xmax || ymin >= ymax)
  361. return;
  362. dst = image_new(xmax - xmin, ymax - ymin);
  363. for(y = 0; y < dst->height; y++)
  364. for(x = 0; x < dst->width; x++)
  365. {
  366. getpixel(img, xmin + x, ymin + y, &r, &g, &b);
  367. setpixel(dst, x, y, r, g, b);
  368. }
  369. image_swap(img, dst);
  370. image_free(dst);
  371. }
  372. int filter_count(struct image *img)
  373. {
  374. int histo[256];
  375. int x, y, i, count = 0;
  376. int r, g, b;
  377. for(i = 0; i < 256; i++)
  378. histo[i] = 0;
  379. for(y = 0; y < img->height; y++)
  380. for(x = 0; x < img->width; x++)
  381. {
  382. getgray(img, x, y, &r);
  383. histo[r] = 1;
  384. }
  385. for(i = 0; i < 256; i++)
  386. count += histo[i];
  387. return count;
  388. }