|
- /*
- * filters.c: various image filters
- * $Id$
- *
- * Copyright: (c) 2004 Sam Hocevar <sam@zoy.org>
- * This program is free software. It comes without any warranty, to
- * the extent permitted by applicable law. You can redistribute it
- * and/or modify it under the terms of the Do What The Fuck You Want
- * To Public License, Version 2, as published by Sam Hocevar. See
- * http://sam.zoy.org/wtfpl/COPYING for more details.
- */
-
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <math.h>
-
- #include "config.h"
- #include "common.h"
-
- /* Functions */
- void filter_flood_fill(struct image *img, int x, int y, int r, int g, int b)
- {
- int oldr, oldg, oldb;
- int nextr, nextg, nextb;
-
- if(x < 0 || y < 0 || x >= img->width || y >= img->height)
- return;
-
- getpixel(img, x, y, &oldr, &oldg, &oldb);
- setpixel(img, x, y, r, g, b);
-
- getpixel(img, x + 1, y, &nextr, &nextg, &nextb);
- if(nextr == oldr && nextg == oldg && nextb == oldb)
- filter_flood_fill(img, x + 1, y, r, g, b);
-
- getpixel(img, x - 1, y, &nextr, &nextg, &nextb);
- if(nextr == oldr && nextg == oldg && nextb == oldb)
- filter_flood_fill(img, x - 1, y, r, g, b);
-
- getpixel(img, x, y + 1, &nextr, &nextg, &nextb);
- if(nextr == oldr && nextg == oldg && nextb == oldb)
- filter_flood_fill(img, x, y + 1, r, g, b);
-
- getpixel(img, x, y - 1, &nextr, &nextg, &nextb);
- if(nextr == oldr && nextg == oldg && nextb == oldb)
- filter_flood_fill(img, x, y - 1, r, g, b);
- }
-
- void filter_scale(struct image *img, float ratio)
- {
- struct image *dst;
- int w, h, x, y;
- int r, g, b;
-
- w = ratio * img->width;
- h = ratio * img->height;
-
- dst = image_new(w, h);
-
- for(y = 0; y < h; y++)
- for(x = 0; x < w; x++)
- {
- getpixel(img, x / ratio, y / ratio, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_fill_holes(struct image *img)
- {
- struct image *dst;
- int x, y;
- int r, g, b;
-
- dst = image_new(img->width, img->height);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- }
-
- for(y = 0; y < dst->height; y++)
- for(x = 2; x < dst->width - 2; x++)
- {
- int c1, c2, c3, c4, c5;
- getpixel(img, x-2, y, &c1, &g, &b);
- getpixel(img, x-1, y, &c2, &g, &b);
- getpixel(img, x, y, &c3, &g, &b);
- getpixel(img, x+1, y, &c4, &g, &b);
- getpixel(img, x+2, y, &c5, &g, &b);
- if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127)
- c3 = (c1 + c2 + c4) / 3;
- else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127)
- c3 = (c2 + c4 + c5) / 3;
- setpixel(dst, x, y, c3, c3, c3);
- }
-
- for(x = 0; x < dst->width; x++)
- for(y = 2; y < dst->height - 2; y++)
- {
- int c1, c2, c3, c4, c5;
- getpixel(img, x, y-2, &c1, &g, &b);
- getpixel(img, x, y-1, &c2, &g, &b);
- getpixel(img, x, y, &c3, &g, &b);
- getpixel(img, x, y+1, &c4, &g, &b);
- getpixel(img, x, y+2, &c5, &g, &b);
- if(c1 < 127 && c2 < 127 && c3 > 128 && c4 < 127)
- c3 = (c1 + c2 + c4) / 3;
- else if(c2 < 127 && c3 > 128 && c4 < 127 && c5 < 127)
- c3 = (c2 + c4 + c5) / 3;
- setpixel(dst, x, y, c3, c3, c3);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_black_stuff(struct image *img)
- {
- struct image *dst;
- int x, y;
- int r, ra, rb, g, b;
-
- dst = image_new(img->width, img->height);
-
- /* Remove vertical stuff */
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- if(y > 0 && y < img->height - 1)
- {
- getpixel(img, x, y - 1, &ra, &g, &b);
- getpixel(img, x, y + 1, &rb, &g, &b);
- if(r < ra && (r - ra) * (r - rb) > 5000)
- setpixel(dst, x, y, ra, ra, ra);
- }
- }
-
- /* Remove horizontal stuff */
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- if(x > 0 && x < img->width - 1)
- {
- getpixel(dst, x - 1, y, &ra, &g, &b);
- getpixel(dst, x + 1, y, &rb, &g, &b);
- if(r < ra && (r - ra) * (r - rb) > 5000)
- setpixel(dst, x, y, ra, ra, ra);
- }
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_detect_lines(struct image *img)
- {
- struct image *dst;
- int x, y;
- int r, ra, rb, g, b;
-
- dst = image_new(img->width, img->height);
-
- /* Remove white lines */
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- if(y > 0 && y < img->height - 1)
- {
- getpixel(img, x, y - 1, &ra, &g, &b);
- getpixel(img, x, y + 1, &rb, &g, &b);
- if(r > ra && (r - ra) * (r - rb) > 5000)
- setpixel(dst, x, y, ra, ra, ra);
- }
- }
-
- /* Remove black lines */
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(dst, x, y, &r, &g, &b);
- if(y > 0 && y < img->height - 1)
- {
- getpixel(img, x, y - 1, &ra, &g, &b);
- getpixel(img, x, y + 1, &rb, &g, &b);
- if(r < ra && (r - ra) * (r - rb) > 500)
- setpixel(dst, x, y, ra, ra, ra);
- }
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_threshold(struct image *img, int threshold)
- {
- struct image *dst;
- int x, y;
- int r, g, b;
- int min = 0, max = 255;
-
- dst = image_new(img->width, img->height);
-
- if(threshold < 0)
- {
- min = 255;
- max = 0;
- threshold = -threshold;
- }
-
- threshold *= 3;
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- if(r + g + b < threshold)
- setpixel(dst, x, y, min, min, min);
- else
- setpixel(dst, x, y, max, max, max);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_trick(struct image *img)
- {
- #define TSIZE 3
- struct image *dst;
- int x, y, i, j, val, m, more, l, less;
- int r, g, b;
-
- dst = image_new(img->width, img->height);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- setpixel(dst, x, y, 255, 255, 255);
-
- for(y = TSIZE/2; y < img->height - TSIZE/2; y++)
- for(x = TSIZE/2; x < img->width - TSIZE/2; x++)
- {
- getpixel(img, x + TSIZE - TSIZE/2, y + TSIZE - TSIZE/2, &val, &g, &b);
- m = more = l = less = 0;
- for(i = 0; i < TSIZE; i++)
- for(j = 0; j < TSIZE; j++)
- {
- getpixel(img, x + j - TSIZE/2, y + i - TSIZE/2, &r, &g, &b);
- if(r > val)
- {
- more += r;
- m++;
- }
- else if(r < val)
- {
- less += r;
- l++;
- }
- }
-
- if(l >= 6)
- i = less / l;
- else if(m >= 6)
- i = more / m;
- else
- i = val;
- setpixel(dst, x, y, i, i, i);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_smooth(struct image *img)
- {
- #define SSIZE 3
- struct image *dst;
- int x, y, i, j, val;
- int r, g, b;
-
- dst = image_new(img->width, img->height);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getpixel(img, x, y, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- }
-
- for(y = SSIZE/2; y < img->height - SSIZE/2; y++)
- for(x = SSIZE/2; x < img->width - SSIZE/2; x++)
- {
- val = 0;
- for(i = 0; i < SSIZE; i++)
- for(j = 0; j < SSIZE; j++)
- {
- getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b);
- val += r;
- }
-
- i = val / (SSIZE * SSIZE);
- setpixel(dst, x, y, i, i, i);
- }
-
- /* Remove border */
- for(y = 0; y < dst->height; y++)
- {
- getpixel(dst, 1, y, &r, &g, &b);
- setpixel(dst, 0, y, r, g, b);
- getpixel(dst, dst->width - 2, y, &r, &g, &b);
- setpixel(dst, dst->width - 1, y, r, g, b);
- }
-
- for(x = 0; x < dst->width; x++)
- {
- getpixel(dst, x, 1, &r, &g, &b);
- setpixel(dst, x, 0, r, g, b);
- getpixel(dst, x, dst->height - 2, &r, &g, &b);
- setpixel(dst, x, dst->height - 1, r, g, b);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_median(struct image *img)
- {
- #define MSIZE 3
- struct image *dst;
- int x, y, i, j, val[MSIZE*MSIZE];
- int r, g, b;
-
- dst = image_new(img->width, img->height);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- setpixel(dst, x, y, 255, 255, 255);
-
- for(y = MSIZE/2; y < img->height - MSIZE/2; y++)
- for(x = MSIZE/2; x < img->width - MSIZE/2; x++)
- {
- for(i = 0; i < MSIZE; i++)
- for(j = 0; j < MSIZE; j++)
- {
- getpixel(img, x + j - SSIZE/2, y + i - SSIZE/2, &r, &g, &b);
- val[i * MSIZE + j] = r;
- }
-
- /* Bubble sort power! */
- for(i = 0; i < MSIZE * MSIZE / 2 + 1; i++)
- for(j = i + 1; j < MSIZE * MSIZE; j++)
- if(val[i] > val[j])
- {
- register int k = val[i];
- val[i] = val[j];
- val[j] = k;
- }
-
- i = val[MSIZE * MSIZE / 2];
- setpixel(dst, x, y, i, i, i);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_contrast(struct image *img)
- {
- struct image *dst;
- int histo[256];
- int x, y, i, min = 255, max = 0;
- int r, g, b;
-
- dst = image_new(img->width, img->height);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getgray(img, x, y, &r);
- if(r < min) min = r;
- if(r > max) max = r;
- }
-
- if(min == max)
- histo[min] = 127;
- else
- for(i = min; i < max + 1; i++)
- histo[i] = (i - min) * 255 / (max - min);
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getgray(img, x, y, &r);
- setpixel(dst, x, y, histo[r], histo[r], histo[r]);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- void filter_crop(struct image *img, int xmin, int ymin, int xmax, int ymax)
- {
- struct image *dst;
- int x, y;
- int r, g, b;
-
- if(xmin < 0)
- xmin = 0;
- if(ymin < 0)
- ymin = 0;
- if(xmax >= img->width)
- xmax = img->width - 1;
- if(ymax >= img->height)
- ymax = img->height - 1;
-
- if(xmin >= xmax || ymin >= ymax)
- return;
-
- dst = image_new(xmax - xmin, ymax - ymin);
-
- for(y = 0; y < dst->height; y++)
- for(x = 0; x < dst->width; x++)
- {
- getpixel(img, xmin + x, ymin + y, &r, &g, &b);
- setpixel(dst, x, y, r, g, b);
- }
-
- image_swap(img, dst);
- image_free(dst);
- }
-
- int filter_count(struct image *img)
- {
- int histo[256];
- int x, y, i, count = 0;
- int r, g, b;
-
- for(i = 0; i < 256; i++)
- histo[i] = 0;
-
- for(y = 0; y < img->height; y++)
- for(x = 0; x < img->width; x++)
- {
- getgray(img, x, y, &r);
- histo[r] = 1;
- }
-
- for(i = 0; i < 256; i++)
- count += histo[i];
-
- return count;
- }
|