#include #include #include #include #include #include #include #include "gfx.h" #define DEBUG_BUILD 0 #define MASK_MULTIPLIER 50 typedef struct { uint32_t width; uint32_t height; uint32_t new_width; uint32_t new_height; uint32_t* buffer; int32_t* dist_buffer; uint32_t* mask_buffer; } image_T; int32_t pixel_distance(uint32_t pixel_a, uint32_t pixel_b, uint32_t pixel_m) { uint8_t r_a = (pixel_a) & 0xFF; uint8_t g_a = (pixel_a >> 8) & 0xFF; uint8_t b_a = (pixel_a >> 16) & 0xFF; uint8_t r_b = (pixel_b) & 0xFF; uint8_t g_b = (pixel_b >> 8) & 0xFF; uint8_t b_b = (pixel_b >> 16) & 0xFF; uint8_t r_m = (pixel_m) & 0xFF; uint8_t g_m = (pixel_m >> 8) & 0xFF; int32_t dist = (int32_t)sqrt(pow(r_a - r_b, 2) + pow(g_a - g_b, 2) + pow(b_a - b_b, 2)) + (r_m * MASK_MULTIPLIER) - (g_m * MASK_MULTIPLIER); return dist; } image_T* image_load(const char* filename, const char* filename_mask) { printf("loading '%s'...\n", filename); image_T* image = malloc(sizeof(image_T)); image->mask_buffer = img_load_pixels(filename_mask, (int*)&image->width, (int*)&image->height, IMG_FMT_RGBA32); image->buffer = img_load_pixels(filename, (int*)&image->width, (int*)&image->height, IMG_FMT_RGBA32); image->dist_buffer = calloc(image->width * image->height, sizeof(uint32_t)); image->new_width = image->width; image->new_height = image->height; } void image_destruct(image_T* image) { printf("destructing resources\n"); img_free_pixels(image->buffer); img_free_pixels(image->mask_buffer); free(image->dist_buffer); free(image); } void image_calculate_dist_buffer(image_T* image) { memset(image->dist_buffer, 0, image->height * image->width * sizeof(int32_t)); uint32_t* last_row = image->buffer; uint32_t* pixel_row = &last_row[image->width]; int32_t* dist_last_row = image->dist_buffer; int32_t* dist_pixel_row = &dist_last_row[image->width]; for (int y = 1; y < image->new_height; y++) { for (int x = 0; x < image->new_width; x++) { uint32_t pixel = pixel_row[x]; int32_t shortest_dist; bool found_dist = false; for (int i = (x > 0 ? -1 : 0); i < (x < image->new_width-1 ? 2 : 1); i++) { int32_t dist = pixel_distance(pixel, last_row[x + i], image->mask_buffer[(y * image->width) + x + i]) + dist_last_row[x + i]; if (!found_dist || shortest_dist > dist) { shortest_dist = dist; found_dist = true; } } dist_pixel_row[x] = shortest_dist; } last_row = pixel_row; pixel_row = &pixel_row[image->width]; dist_last_row = dist_pixel_row; dist_pixel_row = &dist_pixel_row[image->width]; } } uint32_t image_find_best_line(image_T* image) { int32_t* row = &image->dist_buffer[(image->new_height-1) * image->width]; uint32_t line_id = 0; int32_t shortest_dist; bool found_dist = false; for (uint32_t x = 0; x < image->new_width; x++) { if (!found_dist || shortest_dist > row[x]) { shortest_dist = row[x]; line_id = x; found_dist = true; } } return line_id; } void image_cut_line(image_T* image, uint32_t line_id) { uint32_t x = line_id; for (uint32_t y = image->height-1; y > 0; y--) { int32_t shortest_dist; int8_t offset; bool found_dist = false; for (int i = (x > 0 ? -1 : 0); i < (x < image->new_width-1 ? 2 : 1); i++) { int32_t dist = image->dist_buffer[(image->width * y) + x + i]; if (!found_dist || shortest_dist > dist) { shortest_dist = dist; offset = (int8_t)i; found_dist = true; } } x += offset; memcpy(&image->buffer[(image->width * y) + x], &image->buffer[(image->width * y) + x + 1], (image->new_width - x) * sizeof(uint32_t)); memcpy(&image->mask_buffer[(image->width * y) + x], &image->mask_buffer[(image->width * y) + x + 1], (image->new_width - x) * sizeof(uint32_t)); gfx_color(0, 0xFF, 0); gfx_point(x, y); } image->new_width -= 1; gfx_flush(); } void image_dump(image_T* image) { #if DEBUG_BUILD printf("Pixels:\n"); #endif for (int y = 0; y < image->new_height; y++) { uint32_t* pixel_row = &image->buffer[y * image->width]; #if DEBUG_BUILD printf(" "); #endif for (int x = 0; x < image->new_width; x++) { #if DEBUG_BUILD printf("%x ", pixel_row[x]); #endif gfx_color((uint8_t)(pixel_row[x] & 0xFF), (uint8_t)((pixel_row[x] >> 8) & 0xFF), (uint8_t)((pixel_row[x] >> 16) & 0xFF)); gfx_point(x, y); } #if DEBUG_BUILD printf("\n"); #endif } gfx_color(0, 0, 0); for (int y = 0; y < image->new_height*2; y++) { gfx_point(image->new_width, y); } gfx_flush(); #if DEBUG_BUILD printf("Distances:\n"); for (int y = 0; y < image->height; y++) { uint32_t* dist_row = &image->dist_buffer[y * image->width]; printf(" "); for (int x = 0; x < image->width; x++) { printf("%x ", dist_row[x]); } printf("\n"); } #endif } int main() { printf("Line Cutter - Juniorcamp Informatik\n"); image_T* image = image_load("../paris.png", "../paris_mask.png"); gfx_open(800, 600, "Juniorcamp Informatik - Line Cutter"); image_dump(image); bool running = true; while(running) { char c = gfx_wait(); image_dump(image); switch (c) { case 's': { image_calculate_dist_buffer(image); image_cut_line(image, image_find_best_line(image)); break; } case 'q': { running = false; break; } } } image_destruct(image); return 0; }