From dcc2856b6e8ee30ffbcc33e8305d3ea3e96fe7f7 Mon Sep 17 00:00:00 2001 From: Søren Sandmann Pedersen Date: Thu, 28 Jul 2011 18:39:29 -0400 Subject: Add pngtrans.c --- fft.c | 14 +++ fft.h | 19 +++- pngtrans.c | 295 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 327 insertions(+), 1 deletion(-) create mode 100644 pngtrans.c diff --git a/fft.c b/fft.c index 46215cb..96dbdaa 100644 --- a/fft.c +++ b/fft.c @@ -166,3 +166,17 @@ shift_2d (complex_t *buffer, int n) } } } + +void +fft_shift_2d (complex_t *buffer, int n) +{ + fft_2d (buffer, n); + shift_2d (buffer, n); +} + +void +ifft_shift_2d (complex_t *buffer, int n) +{ + shift_2d (buffer, n); + ifft_2d (buffer, n); +} diff --git a/fft.h b/fft.h index 31d7667..61d4ba9 100644 --- a/fft.h +++ b/fft.h @@ -55,7 +55,18 @@ complex_mag (complex_t a) static inline double complex_arg (complex_t a) { - return atan2 (a.im, a.re) + M_PI; + return fmod (atan2 (a.im, a.re) + 2 * M_PI, 2 * M_PI); +} + +static inline complex_t +complex_from_mag_arg (double mag, double arg) +{ + complex_t r; + + r.re = mag * cos (arg); + r.im = mag * sin (arg); + + return r; } static inline double @@ -84,5 +95,11 @@ shift (complex_t *buffer, int n); void shift_2d (complex_t *buffer, int n); +void +fft_shift_2d (complex_t *buffer, int n); + +void +ifft_shift_2d (complex_t *buffer, int n); + void show_image (const char *name, complex_t *image, int n); diff --git a/pngtrans.c b/pngtrans.c new file mode 100644 index 0000000..37cb1c8 --- /dev/null +++ b/pngtrans.c @@ -0,0 +1,295 @@ +#include +#include +#include +#include +#include +#include "fft.h" + +typedef struct complex_image_t complex_image_t; +struct complex_image_t +{ + int width; + int height; + complex_t *red; + complex_t *green; + complex_t *blue; +}; + +static complex_image_t * +complex_image_new (int width, int height) +{ + complex_image_t *image = g_new0 (complex_image_t, 1); + + image->width = width; + image->height = height; + image->red = g_new0 (complex_t, width * height); + image->green = g_new0 (complex_t, width * height); + image->blue = g_new0 (complex_t, width * height); + + return image; +} + +static complex_image_t * +complex_image_from_pixbuf (GdkPixbuf *pixbuf) +{ + complex_image_t *result; + uint8_t *pdata; + int w, h, s; + int i, j; + gboolean has_alpha; + int n_channels; + + w = gdk_pixbuf_get_width (pixbuf); + h = gdk_pixbuf_get_height (pixbuf); + s = gdk_pixbuf_get_rowstride (pixbuf); + pdata = gdk_pixbuf_get_pixels (pixbuf); + has_alpha = gdk_pixbuf_get_has_alpha (pixbuf); + n_channels = 3 + has_alpha; + + printf ("has alpha: %d\n", has_alpha); + + result = complex_image_new (w, h); + + for (i = 0; i < h; ++i) + { + for (j = 0; j < w; ++j) + { + uint8_t *p = &pdata[i * s + j * n_channels]; + int idx = i * w + j; + + result->red[idx].re = p[0] / 255.0; + result->green[idx].re = p[1] / 255.0; + result->blue[idx].re = p[2] / 255.0; + } + } + + return result; +} + +typedef uint8_t (* convert_t) (complex_t c); + +static GdkPixbuf * +pixbuf_from_complex_image (complex_image_t *image, convert_t convert) +{ + int w = image->width; + int h = image->height; + GdkPixbuf *pixbuf = gdk_pixbuf_new (GDK_COLORSPACE_RGB, TRUE, 8, w, h); + uint8_t *p_bits = (uint8_t *)gdk_pixbuf_get_pixels (pixbuf); + int s = gdk_pixbuf_get_rowstride (pixbuf); + int i, j; + + for (i = 0; i < h; ++i) + { + for (j = 0; j < w; ++j) + { + uint8_t *p = &(p_bits[i * s + j * 4]); + int idx = i * w + j; + + p[0] = convert (image->red[idx]); + p[1] = convert (image->green[idx]); + p[2] = convert (image->blue[idx]); + p[3] = 0xff; // convert (image->alpha[idx]); + } + } + + return pixbuf; +} + +#define SIZE 1024 +#define SIZE 1024 + +static gboolean +on_expose (GtkWidget *widget, GdkEventExpose *expose, gpointer data) +{ + GdkPixbuf *pixbuf = data; + int i, j; + int pwidth = gdk_pixbuf_get_width (pixbuf); + int pheight = gdk_pixbuf_get_height (pixbuf); + int dwidth, dheight; + + gdk_drawable_get_size (widget->window, &dwidth, &dheight); + + for (i = 0; i < dheight; i += pheight) + { + for (j = 0; j < dwidth; j += pwidth) + { + gdk_draw_pixbuf (widget->window, NULL, + pixbuf, 0, 0, j, i, pwidth, pheight, + GDK_RGB_DITHER_NONE, + 0, 0); + } + } + return TRUE; +} + +typedef enum +{ + DISPLAY_MAG, + DISPLAY_RE +} display_type_t; + +static uint8_t +convert_mag (complex_t d) +{ + double m = complex_mag (d); + + m = log (m) / 10.0; + + if (m > 1.0) + { + printf ("%f\n", m); + m = 1.0; + } + + if (m < 0) + m = 0; + + return (uint8_t) (m * 255.0 + 0.5); +} + +static uint8_t +convert_re (complex_t c) +{ + if (c.re > 1.0) + c.re = 1.0; + if (c.re < 0) + c.re = 0; + + return c.re * 255.0 + 0.5; +} + +static void +display (const char *name, complex_image_t *image, display_type_t type) +{ + GtkWidget *window, *da; + GdkPixbuf *pixbuf; + int argc; + char **argv; + char *arg0 = g_strdup (name); + convert_t convert; + + argc = 1; + argv = (char **)&arg0; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + da = gtk_drawing_area_new (); + + gtk_container_add (GTK_CONTAINER (window), da); + + gtk_window_set_default_size (GTK_WINDOW (window), SIZE, SIZE); + + switch (type) + { + case DISPLAY_MAG: convert = convert_mag; break; + case DISPLAY_RE: convert = convert_re; break; + default: + g_assert_not_reached(); + } + + pixbuf = pixbuf_from_complex_image (image, convert); + + g_signal_connect (da, "expose_event", G_CALLBACK (on_expose), pixbuf); + g_signal_connect (window, "delete_event", G_CALLBACK (gtk_main_quit), NULL); + + gtk_widget_show_all (window); + + gtk_main (); +} + +static void +image_fft (complex_image_t *image) +{ + fft_shift_2d (image->red, image->width); + fft_shift_2d (image->green, image->width); + fft_shift_2d (image->blue, image->width); +} + +static void +image_ifft (complex_image_t *image) +{ + ifft_shift_2d (image->red, image->width); + ifft_shift_2d (image->green, image->width); + ifft_shift_2d (image->blue, image->width); +} + +static complex_t +filter (complex_t c, double dist) +{ + double m = complex_mag (c); + double arg = complex_arg (c); + + return complex_from_mag_arg (m * (1/(pow (sqrt (dist) / 16.0, 4) + 1)) , arg); +} + +static void +low_pass (complex_image_t *image, double d) +{ + int w = image->width; + int h = image->height; + int i, j; + double d2 = d * d; + int c = h / 2; + + for (i = 0; i < h; ++i) + { + for (j = 0; j < w; ++j) + { + int idx = i * w + j; + double dist = (c - i) * (c - i) + (c - j) * (c -j); + double t; + + image->red[idx] = filter (image->red[idx], dist); + image->green[idx] = filter (image->green[idx], dist); + image->blue[idx] = filter (image->blue[idx], dist); + } + } +} + +int +main (int argc, char **argv) +{ + char *input, *output; + GdkPixbuf *pb; + complex_image_t *image; + + g_type_init (); + + if (argc < 3) + { + printf ("Usage: %s \n\n", argv[0]); + return 1; + } + + input = argv[1]; + output = argv[2]; + + if (!(pb = gdk_pixbuf_new_from_file (input, NULL))) + { + printf ("Could not open %s\n", input); + return -1; + } + + image = complex_image_from_pixbuf (pb); + + g_print ("width, height %d %d\n", image->width, image->height); + + image_fft (image); + + + low_pass (image, 2 * image->width); + +#if 0 + display ("test", image, DISPLAY_MAG); +#endif +#if 0 +#endif + + image_ifft (image); + + display ("test", image, DISPLAY_RE); + + return 0; +} -- cgit v1.2.3