#include #include #include #include "util.h" #ifndef N_THREADS #define N_THREADS 4 #endif static void find_image_in_wimmel(GdkPixbuf *wimmel, GdkPixbuf *match, GdkPixbuf *output) { int wimmel_width, wimmel_height; int width, height; int i, j, k, n; int difference, barrier; wimmel_width = gdk_pixbuf_get_width(wimmel); wimmel_height = gdk_pixbuf_get_height(wimmel); width = gdk_pixbuf_get_width(match); height = gdk_pixbuf_get_height(match); barrier = width * height / 2; int stride = gdk_pixbuf_get_rowstride(wimmel); int nch = gdk_pixbuf_get_n_channels(wimmel); guchar *row = gdk_pixbuf_get_pixels(wimmel); guchar *pix, *pix_m; int stride_m = gdk_pixbuf_get_rowstride(match); for (j = 0; j < wimmel_height - height; ++j, row += stride) { for (i = 0, pix = row; i < wimmel_width - width; ++i, pix += nch) { difference = 0; guchar *row_m = gdk_pixbuf_get_pixels(match); for (n = 0; n < height; ++n, row_m += stride_m) { for (k = 0, pix_m = row_m; k < width; ++k, pix_m += nch) { pix = row + n * stride + (i + k) * nch; if (abs((int)pix[0] - (int)pix_m[0]) > 10) { difference++; if (difference > barrier) break; } } } if (difference < barrier) { g_print("kleeblatt @ %d, %d; difference: %d\n", i, j, difference); color_t color = COLOR(255, 0, 0, 0); for (k = i; k < i+width; k++) { put_pixel(output, POINT(k, j), color); put_pixel(output, POINT(k, j+height), color); } for (n = j; n < j+height; n++) { put_pixel(output, POINT(i, n), color); put_pixel(output, POINT(i+width, n), color); } } } } } struct find_params { GdkPixbuf *wimmel; GdkPixbuf *match; GdkPixbuf *output; }; static gpointer find_thread(gpointer data) { struct find_params *params = data; find_image_in_wimmel(params->wimmel, params->match, params->output); g_object_unref(params->wimmel); g_object_unref(params->match); g_object_unref(params->output); free(params); return NULL; } void monochrome(GdkPixbuf *p) { int x, y, width, height, nch; guchar *d; width = gdk_pixbuf_get_width(p); height = gdk_pixbuf_get_height(p); nch = gdk_pixbuf_get_n_channels(p); for (y = 0; y < height; ++y) { d = gdk_pixbuf_get_pixels(p) + y * gdk_pixbuf_get_rowstride(p); for (x = 0; x < width; ++x, d += nch) { d[0] = MAX(d[0], MAX(d[1], d[2])); } } } int main(int argc, char *argv[]) { char *file; GdkPixbuf *wimmel, *output; GdkPixbuf *match_tmp, *match; int i; int x1, y1, mwidth, mheight, width, height; GThread *thread[N_THREADS]; g_type_init(); if (argc < 5) exit(EXIT_FAILURE); file = argv[1]; x1 = atoi(argv[2]); y1 = atoi(argv[3]); mwidth = atoi(argv[4]); mheight = atoi(argv[5]); wimmel = gdk_pixbuf_new_from_file(file, NULL); if (!wimmel) exit(EXIT_FAILURE); output = gdk_pixbuf_copy(wimmel); monochrome(wimmel); match_tmp = gdk_pixbuf_new_subpixbuf(wimmel, x1, y1, mwidth, mheight); match = gdk_pixbuf_copy(match_tmp); g_object_unref(match_tmp); monochrome(match); width = gdk_pixbuf_get_width(wimmel); height = gdk_pixbuf_get_height(wimmel); int step_y = height / N_THREADS; int y; for (i = 0, y = 0; i < N_THREADS; ++i, y += step_y) { struct find_params *params = malloc(sizeof (struct find_params));; if (!params) exit(EXIT_FAILURE); int h = step_y + mheight; if (y + h > height) h = height - y; params->wimmel = gdk_pixbuf_new_subpixbuf(wimmel, 0, y, width, h); params->output = gdk_pixbuf_new_subpixbuf(output, 0, y, width, h); params->match = g_object_ref(match); thread[i] = g_thread_create(find_thread, params, TRUE, NULL); } for (i = 0; i < N_THREADS; ++i) g_thread_join(thread[i]); gdk_pixbuf_save(output, "output.tiff", "tiff", NULL, NULL); g_object_unref(wimmel); g_object_unref(output); g_object_unref(match); }