From: Andreas Eversberg Date: Sun, 24 May 2015 12:19:36 +0000 (+0200) Subject: Real time colorization preview rendering X-Git-Url: http://git.eversberg.eu/gitweb.cgi?p=colorize.git;a=commitdiff_plain;h=87eec5927c8f880382762020d544b996e970078b Real time colorization preview rendering --- diff --git a/gui/colorize.c b/gui/colorize.c index bf3bf59..5a8f545 100644 --- a/gui/colorize.c +++ b/gui/colorize.c @@ -17,6 +17,18 @@ #include "palette.h" #include "timeline.h" +enum thread_preview { + PREVIEW_OFF, + PREVIEW_NEW, + PREVIEW_ALLOC, + PREVIEW_ON, + PREVIEW_FREE, +}; + +static int thread_debug = 0; +static int thread_running = 0; +static enum thread_preview thread_preview = PREVIEW_OFF; + struct colorize_priv { GtkWidget *window; GdkPixbuf *pixbuf; @@ -339,3 +351,305 @@ error: darrayDone(); } + +/* real time thread */ + +enum thread_preview { + PREVIEW_OFF, + PREVIEW_NEW, + PREVIEW_ALLOC, + PREVIEW_ON, +}; + +static int thread_debug = 0; +static int thread_running = 0; +static enum thread_preview thread_preview = PREVIEW_OFF; + +static void *colorize_thread(void *arg) +{ + struct colorize *col = NULL; + darray_t *gI = NULL, *cI = NULL, *I = NULL, *mI = NULL; + unsigned char *mark_buffer = NULL; + int dims[4]; + int features, change_bc = 0, change_alpha = 0; + char *feat_names[20]; + int i, j; + int c; + int rc; + if (thread_debug) + printf("%s: thread entered\n", __func__); + +loop: + gdk_threads_enter(); + if (thread_running < 1) { + if (thread_debug) + printf("%s: thread leaving\n", __func__); + thread_running = 0; + goto reset; + } + if (thread_preview == PREVIEW_NEW) { + thread_preview = PREVIEW_ALLOC; + goto reset; + } + if (thread_preview == PREVIEW_ALLOC) { + int width, height; + + if (thread_debug) + printf("%s: new preview\n", __func__); + width = img_width; + height = img_height; + + /* alloc gI and cI array */ + dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1; + gI = darrayCreate(4, dims); + if (!gI) { + printerror("No memory: failed to create grey image array"); + thread_preview = PREVIEW_OFF; + goto reset; + } + dims[0] = width; dims[1] = height; dims[2] = 3; dims[3] = 1; + cI = darrayCreate(4, dims); + if (!cI) { + printerror("No memory: failed to create marked image array"); + thread_preview = PREVIEW_OFF; + goto reset; + } + mark_buffer = malloc(width*height); + if (!mark_buffer) { + printerror("No memory: failed to create marked index image"); + thread_preview = PREVIEW_OFF; + goto reset; + } + thread_preview = PREVIEW_ON; + } + if (thread_preview == PREVIEW_ON) { + int width, height; + double *ptr_gI = NULL, *ptr_cI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL; + + if (thread_debug) + printf("%s: prepare gI/cI\n", __func__); + width = img_width; + height = img_height; + + /* generate grey image array */ + ptr_gI = darrayGetPr(gI); + img2array_short(img_grey_buffer, width, height, ptr_gI, width, height); + /* generade marked color image */ + ptr_cI = darrayGetPr(cI); + img2array_short(img_grey_buffer, width, height, ptr_cI, width, height); + /* copy mark buffer */ + memcpy(mark_buffer, img_mark_buffer, width*height); + + /* prepare while unlocked */ + gdk_threads_leave(); + /* apply marked pixles */ + change_bc = change_alpha = 0; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + /* do not apply mask on index 0 */ + c = mark_buffer[i*width+j]; + if (c == 0) + continue; +#if 0 +iterative colorization does not work with change_bc and change_alpha, because it alters I image before and after colorization + /* check for any brightness/contrast change */ + if (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1) + change_bc = 1; + /* check for any alpha change */ + if (mark_palette[c-1].alpha < 1) + change_alpha = 1; +#endif + /* do not apply white pixles, this meas: keep original color */ + if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255) + continue; + ptr_cI[i*width+j] = mark_palette[c-1].r / 255.0F; + ptr_cI[i*width+j + width*height] = mark_palette[c-1].g / 255.0F; + ptr_cI[i*width+j + width*height*2] = mark_palette[c-1].b / 255.0F; + } + } + + rc = alloc_I_arrays(&I, &mI, width, height, 1, &features, feat_names, change_alpha, change_bc); + if (rc) { + printerror("No memory! Use smaller image or add more memory."); + thread_preview = PREVIEW_OFF; + goto reset; + } + + set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m); + + // convert original image into YUV + rgb2yuv(ptr_gI, ptr_gI, width, height); + // convert maked image into YUV + rgb2yuv(ptr_cI, ptr_cI, width, height); + + /* apply mask to mI */ + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + /* do not apply mask on index 0 */ + c = mark_buffer[i*width+j]; + ptr_m[i*width+j] = (c == 0) ? 0.0F : 1.0F; + } + } + + prepare_arrays(width, height, change_alpha, change_bc, mark_buffer, ptr_gI, ptr_cI, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST); + + /* prepared, so we lock */ + gdk_threads_enter(); + } + if (thread_preview == PREVIEW_ON) { + int width, height; + double *ptr_gI = NULL, *ptr_y = NULL, *ptr_u = NULL, *ptr_v = NULL, *ptr_a = NULL, *ptr_r = NULL, *ptr_b = NULL, *ptr_c = NULL, *ptr_m = NULL; + + if (thread_debug) + printf("%s: render preview\n", __func__); + width = img_width; + height = img_height; + + /* render while unlocked */ + gdk_threads_leave(); + + set_I_ptr(I, mI, width, height, 0, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m); + + /* render u and v change */ + rc = colorize(I, mI, NULL, NULL, 1, 1, 1, 0, feat_names, &col); + if (rc < 0) { + printerror("No memory! Use smaller image or add more memory."); + thread_preview = PREVIEW_OFF; + goto reset; + } + + postpare_arrays(width, height, change_alpha, change_bc, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, NO_TEST); + + /* convert YUV to RGB */ + ptr_gI = darrayGetPr(gI); + yuv2rgb(ptr_y, ptr_gI, width, height); + + /* create image */ + if (change_alpha) { + /* simulate alpha by pattern */ + double pat, a; + for (i = 0; i < height; i++) { + for (j = 0; j < width; j++) { + pat = (((j>>3)&1) == ((i>>3)&1)) ? 0.5 : 0.75; + a = ptr_a[i*width+j]; + ptr_gI[i*width+j] = a * ptr_gI[i*width+j] + (1.0 - a) * pat; + ptr_gI[i*width+j + width*height] = a * ptr_gI[i*width+j + width*height] + (1.0 - a) * pat; + ptr_gI[i*width+j + width*height*2] = a * ptr_gI[i*width+j + width*height*2] + (1.0 - a) * pat; + } + } + } + + /* rendered, so we lock */ + gdk_threads_enter(); + } + if (thread_preview == PREVIEW_ON) { + int width, height; + double *ptr_gI = NULL; + + width = img_width; + height = img_height; + ptr_gI = darrayGetPr(gI); + array2img_short(ptr_gI, width, height, img_preview_buffer, width, height, 0); + draw_image(0, 0, -1, -1); + } + gdk_threads_leave(); + + if (thread_preview == PREVIEW_OFF) + usleep(100000); + + if (thread_preview == PREVIEW_FREE) { + thread_preview = PREVIEW_OFF; + goto reset; + } + + goto loop; + +reset: + if (col) { + colorize_free(col); + col = NULL; + } + if (mark_buffer) { + free(mark_buffer); + mark_buffer = NULL; + } + darrayDestroy(gI); + gI = NULL; + darrayDestroy(cI); + cI = NULL; + darrayDestroy(mI); + mI = NULL; + darrayDestroy(I); + I = NULL; + darrayDone(); + gdk_threads_leave(); + + if (thread_running) + goto loop; + + return NULL; +} + + + +int colorize_preview_init(void) +{ + pthread_t tid; + + if (thread_running) { + /* we want an exit */ + thread_running = -1; + if (thread_debug) + printf("%s: thread already running, terminating\n", __func__); + return -1; + } + + if (pthread_create(&tid, NULL, colorize_thread, NULL) < 0) { + if (thread_debug) + printf("colorize thread creation failed!"); + return -1; + } + + if (thread_debug) + printf("%s: thread created\n", __func__); + thread_running = 1; + + return 0; +} + +void colorize_preview_terminate(void) +{ + colorize_preview_free(); + + if (thread_running > 0) { + if (thread_debug) + printf("%s: threaed is running\n", __func__); + thread_running = -1; + } + if (thread_running) + if (thread_debug) + printf("%s: waiting to terminate thread\n", __func__); + gdk_threads_leave(); + while(thread_running) { + usleep(1000); + } + gdk_threads_enter(); + if (thread_debug) + printf("%s: thread is terminated\n", __func__); +} + +/* indicate a new preview image */ +void colorize_preview_alloc(void) +{ + thread_preview = PREVIEW_NEW; +} + +/* indicate no preview image */ +void colorize_preview_free(void) +{ + if (thread_preview != PREVIEW_OFF) + if (thread_debug) + printf("%s: disable preview\n", __func__); + thread_preview = PREVIEW_FREE; +} + diff --git a/gui/colorize.h b/gui/colorize.h index 33f2a1c..b9f94a5 100644 --- a/gui/colorize.h +++ b/gui/colorize.h @@ -1 +1,5 @@ void colorize_image(void); +int colorize_preview_init(void); +void colorize_preview_terminate(void); +void colorize_preview_alloc(void); +void colorize_preview_free(void); diff --git a/gui/image.c b/gui/image.c index afd572e..bd5804c 100644 --- a/gui/image.c +++ b/gui/image.c @@ -10,6 +10,7 @@ #include "image.h" #include "palette.h" #include "timeline.h" +#include "colorize.h" #include "../src/dir_seperator.h" /* currently loaded image */ @@ -81,6 +82,8 @@ void create_preview() } memcpy(img_preview_buffer, img_grey_buffer, size); + + colorize_preview_alloc(); } void create_rendered(const char *filename) @@ -210,6 +213,7 @@ void destroy_image(void) void destroy_preview(void) { + colorize_preview_free(); free(img_preview_buffer); img_preview_buffer = NULL; } diff --git a/gui/main.c b/gui/main.c index 4eba1f8..207586d 100644 --- a/gui/main.c +++ b/gui/main.c @@ -512,6 +512,9 @@ int main(int argc, char *argv[]) GtkTreeViewColumn *palette_column; GtkCellRenderer *palette_renderer; +// g_thread_init(NULL); (not required, it is done automatically) + gdk_threads_init(); + gdk_threads_enter(); gtk_init(&argc, &argv); main_window = gtk_window_new(GTK_WINDOW_TOPLEVEL); @@ -654,7 +657,10 @@ int main(int argc, char *argv[]) create_image(frame_list[timeline_selected].filename, 1); } + colorize_preview_init(); gtk_main(); + colorize_preview_terminate(); + gdk_threads_leave(); // FIXME: destroy diff --git a/src/process.c b/src/process.c index 1812b97..1eceda7 100644 --- a/src/process.c +++ b/src/process.c @@ -103,8 +103,8 @@ void prepare_arrays(int w, int h, int change_alpha, int change_bc, unsigned char for (x = 0; x < w; x++) { c = mark_buffer[y*w+x]; if (c == 0) { - ptr_u[w*y+x] = ptr_gI[w*h + w*y+x]; - ptr_v[w*y+x] = ptr_gI[w*h*2 + w*y+x]; +// ptr_u[w*y+x] = ptr_gI[w*h + w*y+x]; +// ptr_v[w*y+x] = ptr_gI[w*h*2 + w*y+x]; } else { ptr_u[w*y+x] = ptr_cI[w*h + w*y+x]; ptr_v[w*y+x] = ptr_cI[w*h*2 + w*y+x];