implemented basic seam carving
This commit is contained in:
parent
092e993212
commit
98d5d58558
|
@ -3,7 +3,7 @@ project(Juniorcamp C)
|
|||
|
||||
set(CMAKE_C_STANDARD 99)
|
||||
|
||||
add_executable(Juniorcamp main.c)
|
||||
add_executable(Juniorcamp main.c gfx.c)
|
||||
|
||||
target_link_libraries(Juniorcamp imago m)
|
||||
target_link_libraries(Juniorcamp imago m X11)
|
||||
target_link_directories(Juniorcamp PRIVATE /usr/local/lib/)
|
|
@ -0,0 +1,206 @@
|
|||
/*
|
||||
A simple graphics library for CSE 20211 by Douglas Thain
|
||||
|
||||
This work is licensed under a Creative Commons Attribution 4.0 International License. https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
For complete documentation, see:
|
||||
http://www.nd.edu/~dthain/courses/cse20211/fall2013/gfx
|
||||
Version 3, 11/07/2012 - Now much faster at changing colors rapidly.
|
||||
Version 2, 9/23/2011 - Fixes a bug that could result in jerky animation.
|
||||
*/
|
||||
|
||||
#include <X11/Xlib.h>
|
||||
#include <unistd.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "gfx.h"
|
||||
|
||||
/*
|
||||
gfx_open creates several X11 objects, and stores them in globals
|
||||
for use by the other functions in the library.
|
||||
*/
|
||||
|
||||
static Display *gfx_display=0;
|
||||
static Window gfx_window;
|
||||
static GC gfx_gc;
|
||||
static Colormap gfx_colormap;
|
||||
static int gfx_fast_color_mode = 0;
|
||||
|
||||
/* These values are saved by gfx_wait then retrieved later by gfx_xpos and gfx_ypos. */
|
||||
|
||||
static int saved_xpos = 0;
|
||||
static int saved_ypos = 0;
|
||||
|
||||
/* Open a new graphics window. */
|
||||
|
||||
void gfx_open( int width, int height, const char *title )
|
||||
{
|
||||
gfx_display = XOpenDisplay(0);
|
||||
if(!gfx_display) {
|
||||
fprintf(stderr,"gfx_open: unable to open the graphics window.\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
Visual *visual = DefaultVisual(gfx_display,0);
|
||||
if(visual && visual->class==TrueColor) {
|
||||
gfx_fast_color_mode = 1;
|
||||
} else {
|
||||
gfx_fast_color_mode = 0;
|
||||
}
|
||||
|
||||
int blackColor = BlackPixel(gfx_display, DefaultScreen(gfx_display));
|
||||
int whiteColor = WhitePixel(gfx_display, DefaultScreen(gfx_display));
|
||||
|
||||
gfx_window = XCreateSimpleWindow(gfx_display, DefaultRootWindow(gfx_display), 0, 0, width, height, 0, blackColor, blackColor);
|
||||
|
||||
XSetWindowAttributes attr;
|
||||
attr.backing_store = Always;
|
||||
|
||||
XChangeWindowAttributes(gfx_display,gfx_window,CWBackingStore,&attr);
|
||||
|
||||
XStoreName(gfx_display,gfx_window,title);
|
||||
|
||||
XSelectInput(gfx_display, gfx_window, StructureNotifyMask|KeyPressMask|ButtonPressMask);
|
||||
|
||||
XMapWindow(gfx_display,gfx_window);
|
||||
|
||||
gfx_gc = XCreateGC(gfx_display, gfx_window, 0, 0);
|
||||
|
||||
gfx_colormap = DefaultColormap(gfx_display,0);
|
||||
|
||||
XSetForeground(gfx_display, gfx_gc, whiteColor);
|
||||
|
||||
// Wait for the MapNotify event
|
||||
|
||||
for(;;) {
|
||||
XEvent e;
|
||||
XNextEvent(gfx_display, &e);
|
||||
if (e.type == MapNotify)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Draw a single point at (x,y) */
|
||||
|
||||
void gfx_point( int x, int y )
|
||||
{
|
||||
XDrawPoint(gfx_display,gfx_window,gfx_gc,x,y);
|
||||
}
|
||||
|
||||
/* Draw a line from (x1,y1) to (x2,y2) */
|
||||
|
||||
void gfx_line( int x1, int y1, int x2, int y2 )
|
||||
{
|
||||
XDrawLine(gfx_display,gfx_window,gfx_gc,x1,y1,x2,y2);
|
||||
}
|
||||
|
||||
/* Change the current drawing color. */
|
||||
|
||||
void gfx_color( int r, int g, int b )
|
||||
{
|
||||
XColor color;
|
||||
|
||||
if(gfx_fast_color_mode) {
|
||||
/* If this is a truecolor display, we can just pick the color directly. */
|
||||
color.pixel = ((b&0xff) | ((g&0xff)<<8) | ((r&0xff)<<16) );
|
||||
} else {
|
||||
/* Otherwise, we have to allocate it from the colormap of the display. */
|
||||
color.pixel = 0;
|
||||
color.red = r<<8;
|
||||
color.green = g<<8;
|
||||
color.blue = b<<8;
|
||||
XAllocColor(gfx_display,gfx_colormap,&color);
|
||||
}
|
||||
|
||||
XSetForeground(gfx_display, gfx_gc, color.pixel);
|
||||
}
|
||||
|
||||
/* Clear the graphics window to the background color. */
|
||||
|
||||
void gfx_clear()
|
||||
{
|
||||
XClearWindow(gfx_display,gfx_window);
|
||||
}
|
||||
|
||||
/* Change the current background color. */
|
||||
|
||||
void gfx_clear_color( int r, int g, int b )
|
||||
{
|
||||
XColor color;
|
||||
color.pixel = 0;
|
||||
color.red = r<<8;
|
||||
color.green = g<<8;
|
||||
color.blue = b<<8;
|
||||
XAllocColor(gfx_display,gfx_colormap,&color);
|
||||
|
||||
XSetWindowAttributes attr;
|
||||
attr.background_pixel = color.pixel;
|
||||
XChangeWindowAttributes(gfx_display,gfx_window,CWBackPixel,&attr);
|
||||
}
|
||||
|
||||
int gfx_event_waiting()
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
gfx_flush();
|
||||
|
||||
while (1) {
|
||||
if(XCheckMaskEvent(gfx_display,-1,&event)) {
|
||||
if(event.type==KeyPress) {
|
||||
XPutBackEvent(gfx_display,&event);
|
||||
return 1;
|
||||
} else if (event.type==ButtonPress) {
|
||||
XPutBackEvent(gfx_display,&event);
|
||||
return 1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Wait for the user to press a key or mouse button. */
|
||||
|
||||
char gfx_wait()
|
||||
{
|
||||
XEvent event;
|
||||
|
||||
gfx_flush();
|
||||
|
||||
while(1) {
|
||||
XNextEvent(gfx_display,&event);
|
||||
|
||||
if(event.type==KeyPress) {
|
||||
saved_xpos = event.xkey.x;
|
||||
saved_ypos = event.xkey.y;
|
||||
return XLookupKeysym(&event.xkey,0);
|
||||
} else if(event.type==ButtonPress) {
|
||||
saved_xpos = event.xkey.x;
|
||||
saved_ypos = event.xkey.y;
|
||||
return event.xbutton.button;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Return the X and Y coordinates of the last event. */
|
||||
|
||||
int gfx_xpos()
|
||||
{
|
||||
return saved_xpos;
|
||||
}
|
||||
|
||||
int gfx_ypos()
|
||||
{
|
||||
return saved_ypos;
|
||||
}
|
||||
|
||||
/* Flush all previous output to the window. */
|
||||
|
||||
void gfx_flush()
|
||||
{
|
||||
XFlush(gfx_display);
|
||||
}
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
/*
|
||||
A simple graphics library for CSE 20211 by Douglas Thain
|
||||
|
||||
This work is licensed under a Creative Commons Attribution 4.0 International License. https://creativecommons.org/licenses/by/4.0/
|
||||
|
||||
For course assignments, you should not change this file.
|
||||
For complete documentation, see:
|
||||
http://www.nd.edu/~dthain/courses/cse20211/fall2013/gfx
|
||||
Version 3, 11/07/2012 - Now much faster at changing colors rapidly.
|
||||
Version 2, 9/23/2011 - Fixes a bug that could result in jerky animation.
|
||||
*/
|
||||
|
||||
#ifndef GFX_H
|
||||
#define GFX_H
|
||||
|
||||
/* Open a new graphics window. */
|
||||
void gfx_open( int width, int height, const char *title );
|
||||
|
||||
/* Draw a point at (x,y) */
|
||||
void gfx_point( int x, int y );
|
||||
|
||||
/* Draw a line from (x1,y1) to (x2,y2) */
|
||||
void gfx_line( int x1, int y1, int x2, int y2 );
|
||||
|
||||
/* Change the current drawing color. */
|
||||
void gfx_color( int red, int green, int blue );
|
||||
|
||||
/* Clear the graphics window to the background color. */
|
||||
void gfx_clear();
|
||||
|
||||
/* Change the current background color. */
|
||||
void gfx_clear_color( int red, int green, int blue );
|
||||
|
||||
/* Wait for the user to press a key or mouse button. */
|
||||
char gfx_wait();
|
||||
|
||||
/* Return the X and Y coordinates of the last event. */
|
||||
int gfx_xpos();
|
||||
int gfx_ypos();
|
||||
|
||||
/* Return the X and Y dimensions of the window. */
|
||||
int gfx_xsize();
|
||||
int gfx_ysize();
|
||||
|
||||
/* Check to see if an event is waiting. */
|
||||
int gfx_event_waiting();
|
||||
|
||||
/* Flush all previous output to the window. */
|
||||
void gfx_flush();
|
||||
|
||||
#endif
|
Binary file not shown.
After Width: | Height: | Size: 70 KiB |
129
main.c
129
main.c
|
@ -1,15 +1,19 @@
|
|||
#include <stdio.h>
|
||||
#include <stdbool.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <math.h>
|
||||
#include <memory.h>
|
||||
#include <imago2.h>
|
||||
#include "gfx.h"
|
||||
|
||||
#define DEBUG_BUILD 0
|
||||
|
||||
typedef struct {
|
||||
uint32_t width;
|
||||
uint32_t height;
|
||||
uint32_t new_width;
|
||||
uint32_t new_height;
|
||||
uint32_t* buffer;
|
||||
uint32_t* dist_buffer;
|
||||
} image_T;
|
||||
|
@ -40,6 +44,8 @@ image_T* image_load(const char* filename) {
|
|||
image_T* image = malloc(sizeof(image_T));
|
||||
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) {
|
||||
|
@ -54,15 +60,15 @@ void image_calculate_dist_buffer(image_T* image) {
|
|||
memset(image->dist_buffer, 0, image->height * image->width * sizeof(uint32_t));
|
||||
|
||||
uint32_t* last_row = image->buffer;
|
||||
uint32_t* pixel_row = &last_row[image->height+1];
|
||||
uint32_t* pixel_row = &last_row[image->width];
|
||||
uint32_t* dist_last_row = image->dist_buffer;
|
||||
uint32_t* dist_pixel_row = &dist_last_row[image->height+1];
|
||||
uint32_t* dist_pixel_row = &dist_last_row[image->width];
|
||||
|
||||
for (int y = 1; y < image->height; y++) {
|
||||
for (int y = 1; y < image->new_height; y++) {
|
||||
#if DEBUG_BUILD
|
||||
printf(" Y\n");
|
||||
#endif
|
||||
for (int x = 0; x < image->width; x++) {
|
||||
for (int x = 0; x < image->new_width; x++) {
|
||||
uint32_t pixel = pixel_row[x];
|
||||
|
||||
#if DEBUG_BUILD
|
||||
|
@ -70,7 +76,7 @@ void image_calculate_dist_buffer(image_T* image) {
|
|||
#endif
|
||||
|
||||
int32_t shortest_dist = -1;
|
||||
for (int i = (x > 0 ? -1 : 0); i < (x < image->width-1 ? 2 : 1); i++) {
|
||||
for (int i = (x > 0 ? -1 : 0); i < (x < image->new_width-1 ? 2 : 1); i++) {
|
||||
uint32_t dist = pixel_distance(pixel, last_row[x + i]) + dist_last_row[x + i];
|
||||
|
||||
if (shortest_dist == -1 || shortest_dist > dist) {
|
||||
|
@ -89,62 +95,129 @@ void image_calculate_dist_buffer(image_T* image) {
|
|||
}
|
||||
|
||||
last_row = pixel_row;
|
||||
pixel_row = &last_row[image->height+1];
|
||||
pixel_row = &pixel_row[image->width];
|
||||
dist_last_row = dist_pixel_row;
|
||||
dist_pixel_row = &dist_last_row[image->height+1];
|
||||
dist_pixel_row = &dist_pixel_row[image->width];
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t image_find_best_line(image_T* image) {
|
||||
uint32_t* row = &image->dist_buffer[(image->new_height-1) * image->width];
|
||||
uint32_t line_id = 0;
|
||||
int32_t shortest_dist = -1;
|
||||
|
||||
for (uint32_t x = 0; x < image->new_width; x++) {
|
||||
if (shortest_dist == -1 || shortest_dist > row[x]) {
|
||||
shortest_dist = (int32_t)row[x];
|
||||
line_id = x;
|
||||
printf("id: %d dist: %d\n", x, row[x]);
|
||||
}
|
||||
}
|
||||
|
||||
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 = -1;
|
||||
int8_t offset;
|
||||
for (int i = (x > 0 ? -1 : 0); i < (x < image->new_width-1 ? 2 : 1); i++) {
|
||||
uint32_t dist = image->dist_buffer[(image->width * y) + x + i];
|
||||
|
||||
if (shortest_dist == -1 || shortest_dist > dist) {
|
||||
shortest_dist = (int32_t)dist;
|
||||
offset = i;
|
||||
}
|
||||
}
|
||||
x += offset;
|
||||
memcpy(&image->buffer[(image->width * y) + x], &image->buffer[(image->width * y) + x + 1], (image->new_width - x) * sizeof(uint32_t));
|
||||
gfx_color(0, 0xFF, 0);
|
||||
gfx_point(x, y);
|
||||
gfx_flush();
|
||||
}
|
||||
image->new_width -= 1;
|
||||
}
|
||||
|
||||
void image_dump(image_T* image) {
|
||||
#if DEBUG_BUILD
|
||||
printf("Pixels:\n");
|
||||
for (int y = 0; y < image->height; y++) {
|
||||
uint32_t* pixel_row = &image->buffer[y * (image->height+1)];
|
||||
#endif
|
||||
for (int y = 0; y < image->new_height; y++) {
|
||||
uint32_t* pixel_row = &image->buffer[y * image->width];
|
||||
|
||||
#if DEBUG_BUILD
|
||||
printf(" ");
|
||||
for (int x = 0; x < image->width; x++) {
|
||||
#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; y++) {
|
||||
gfx_point(image->new_width, y);
|
||||
}
|
||||
|
||||
gfx_flush();
|
||||
|
||||
#if DEBUG_BUILD
|
||||
printf("Distances:\n");
|
||||
#endif
|
||||
for (int y = 0; y < image->height; y++) {
|
||||
uint32_t* dist_row = &image->dist_buffer[y * (image->height+1)];
|
||||
uint32_t* dist_row = &image->dist_buffer[y * image->width];
|
||||
|
||||
#if DEBUG_BUILD
|
||||
printf(" ");
|
||||
#endif
|
||||
for (int x = 0; x < image->width; x++) {
|
||||
#if DEBUG_BUILD
|
||||
printf("%x ", dist_row[x]);
|
||||
#endif
|
||||
}
|
||||
|
||||
#if DEBUG_BUILD
|
||||
printf("\n");
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t test_array[12] = {
|
||||
0x00000001, 0x00000003, 0x00000005, 0x00000001,
|
||||
0x00000001, 0x00000007, 0x00000001, 0x00000002,
|
||||
0x0000000A, 0x00000003, 0x00000002, 0x00000005
|
||||
};
|
||||
|
||||
int main() {
|
||||
printf("Line Cutter - Juniorcamp Informatik\n");
|
||||
|
||||
// image_T* image = image_load("../paris.png");
|
||||
image_T* image = image_load("../paris.png");
|
||||
|
||||
image_T* image = malloc(sizeof(image_T));
|
||||
image->height = 3;
|
||||
image->width = 4;
|
||||
image->buffer = test_array;
|
||||
image->dist_buffer = calloc(image->width * image->height, sizeof(uint32_t));
|
||||
gfx_open(800, 600, "Juniorcamp Informatik - Line Cutter");
|
||||
|
||||
image_calculate_dist_buffer(image);
|
||||
bool running = true;
|
||||
while(running) {
|
||||
image_dump(image);
|
||||
char c = gfx_wait();
|
||||
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);
|
||||
free(image->dist_buffer);
|
||||
free(image);
|
||||
image_destruct(image);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue