Real time colorization preview rendering
authorAndreas Eversberg <jolly@eversberg.eu>
Sun, 24 May 2015 12:19:36 +0000 (14:19 +0200)
committerAndreas Eversberg <jolly@eversberg.eu>
Sat, 20 Jun 2015 04:41:34 +0000 (06:41 +0200)
gui/colorize.c
gui/colorize.h
gui/image.c
gui/main.c
src/process.c

index bf3bf59..5a8f545 100644 (file)
 #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;
+}
+
index 33f2a1c..b9f94a5 100644 (file)
@@ -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);
index afd572e..bd5804c 100644 (file)
@@ -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;
 }
index 4eba1f8..207586d 100644 (file)
@@ -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
 
index 1812b97..1eceda7 100644 (file)
@@ -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];