8 #include "../lib/darray.h"
9 #include "../lib/colorize.h"
15 #include "dir_seperator.h"
17 #include "opticalflow.h"
20 static void print_help(const char *app);
21 static void print_test_help();
24 //#define SINGLE_K_TEST 2
33 static struct sequence *sequence = NULL;
35 /* load sequence list and return number of images in sequence */
36 static int load_sequence(int *start, int *next, char *first_filename)
38 const char *name = "sequence";
40 int i, j, keyframe_before_start, eof;
44 /* free previously used sequence */
50 /* get number of frames until next keyframe or end of squence */
51 fp = fopen(name, "r");
53 printf("failed to load sequence '%s'\n", name);
59 keyframe_before_start = 0;
60 while(fgets(buffer, sizeof(buffer), fp)) {
61 p = strchr(buffer + 1, '\"');
66 strcpy(first_filename, buffer + 1);
68 if ((*start) && j == (*start) - 1) {
69 if (strstr(p, "keyframe"))
70 keyframe_before_start = 1;
77 printf("counting %d\n", j);
81 /* skip start frame, since it is always a keyframe */
84 if (strstr(p, "keyframe")) {
91 /* end of file case */
100 #ifdef DEBUG_SEQUENCE
104 #ifdef DEBUG_SEQUENCE
105 puts("end of file at last frame");
110 /* we are done, because we already had the last sequence */
111 if (!keyframe_before_start) {
112 #ifdef DEBUG_SEQUENCE
113 puts("no keyframe before start");
118 #ifdef DEBUG_SEQUENCE
119 puts("keyframe before start");
121 /* we just have a single last frame */
123 (*next) = (*start) + 1;
125 /* if we have two keyframes side by side, we ignore it */
126 if (count == 2 && !eof) {
127 #ifdef DEBUG_SEQUENCE
130 /* only if the frame before start is not a keyframe
131 * and we are not the first sequence, because that would mean
132 * that the first frame is a single sequence */
133 if (!keyframe_before_start && (*start) > 0) {
134 #ifdef DEBUG_SEQUENCE
135 puts("no keyframe before start");
140 #ifdef DEBUG_SEQUENCE
141 puts("keyframe before start or first frame");
143 /* now the start frame has one keyframe before and one after */
145 (*next) = (*start) + 1;
147 (*next) = (*start) + count - 1;
150 /* alloc memory for sequence and fill with data */
151 sequence = (struct sequence *)malloc(sizeof(struct sequence) * count);
153 printf("no memory for sequence\n");
156 memset((struct sequence *)sequence, 0, sizeof(struct sequence) * count);
157 fp = fopen(name, "r");
159 printf("failed to load sequence '%s'\n", name);
164 while(fgets(buffer, sizeof(buffer), fp)) {
165 p = strchr(buffer + 1, '\"');
173 strcpy(sequence[i].filename, buffer + 1);
187 static int in_itr_num = 5, out_itr_num = 10, quick = 0, optical_flow = 1, bright_contrast = 1, alpha_change = 1;
188 static double target_residual_change = 0.01;
189 int scale = 1, scalexyz = 999;
190 static char output_prefix[256] = "";
192 static enum test test = NO_TEST;
194 static int parse_test(const char *arg)
196 if (!strcmp(arg, "help")) {
201 if (!strcmp(arg, "flow-next"))
203 if (!strcmp(arg, "flow-prev"))
206 if (!strcmp(arg, "marked"))
208 if (!strcmp(arg, "mask"))
210 if (!strcmp(arg, "mask+color"))
212 if (!strcmp(arg, "bc-only"))
214 if (!strcmp(arg, "bc-image"))
216 if (!strcmp(arg, "alpha"))
218 if (!strcmp(arg, "no-alpha"))
220 if (!strcmp(arg, "removal-image"))
221 return REMOVAL_IMAGE;
226 static int handle_options(int argc, char **argv)
231 int option_index = 0, c;
232 static struct option long_options[] = {
234 {"depth", 1, 0, 'd'},
235 {"output-prefix", 1, 0, 'O'},
236 {"in-itr-num", 1, 0, 'i'},
237 {"out-itr-num", 1, 0, 'o'},
238 {"residual-change", 1, 0, 'r'},
239 {"quick", 0, 0, 'q'},
240 {"zscale", 1, 0, 'z'},
241 {"brightness-contrast", 1, 0, 'b'},
242 {"optical-flow", 1, 0, 'f'},
243 {"scale", 1, 0, 's'},
248 c = getopt_long(argc, argv, "hd:O:i:o:r:qz:b:f:s:t:", long_options, &option_index);
258 save_depth = atoi(optarg);
262 strcpy(output_prefix, optarg);
266 in_itr_num = atoi(optarg);
270 out_itr_num = atoi(optarg);
274 target_residual_change = atoi(optarg) / 100.0;
282 scalexyz = atoi(optarg);
286 bright_contrast = atoi(optarg);
290 alpha_change = atoi(optarg);
294 optical_flow = atoi(optarg);
298 scale = atoi(optarg);
302 test = parse_test(optarg);
304 fprintf(stderr, "Invalid test '%s', use '--test help' to get a list of tests\n", optarg);
321 static void print_help(const char *app)
323 printf("Colorize version %s\n\n",
324 #include "../version.h"
326 printf("Usage: %s [options] <grey ppm image> <marked ppm image> <result ppm image> [<frames> <start>]\n", app);
327 printf(" Colorize grey image using marked image and save to result image.\n");
328 printf(" If frames and start frame is given, image names must include printf integer formatting (e.g. %%04d).\n");
329 printf("Usage: %s [options] <grey ppm image> marked <result ppm image>\n", app);
330 printf(" Colorize grey image using marked mask + palette and save to result image.\n");
331 printf("Usage: %s [options] sequence [list | <start with frame> [<stop with frame>]]\n", app);
332 printf(" Colorize movie sequence (generated by colorize gui) as found in the current directory.\n");
333 printf(" Use list to view sequence segments between keyframes.\n");
334 printf("\nOptions:\n");
335 printf(" -h --help This help\n");
336 printf(" -d --depth <bits> Save images with given color bit depth (default=%d)\n", save_depth);
337 printf(" -O --output-prefix <path>/<prefix> Store result image of a sequence using this prefix\n");
338 printf(" -i --in-itr-num <num> Alter inner iterations (smoothing count) of colorization algorithm (default=%d)\n", in_itr_num);
339 printf(" -o --out-itr-num <num> Set iterations (fixed turns) of colorization algorithm (default=%d)\n", out_itr_num);
340 printf(" -r --residual-change <percent> Abort iterations if residual has reached minimum change (default=%.0f)\n", target_residual_change*100);
341 printf(" -q --quick Use quick render, but sufaces may be colorized incomplete\n");
342 printf(" -z --zscale <levels> How many grids (staring with the finest) should be scaled in z direction to generate the next coarse grid ");
344 printf("(default=%d)\n", scalexyz);
346 printf("(default=infinite)\n");
347 printf(" -b --brightness-contrast [0 | 1] Apply brightnes and contrast, if defined in palette by GUI (default=%d)\n", bright_contrast);
348 printf(" -a --alpha-change [0 | 1] Apply alpha channel change, if defined in palette by GUI (default=%d)\n", alpha_change);
350 printf(" -f --optical-flow [0 | 1] Apply optical flow, if defined by GUI (default=%d)\n", optical_flow);
352 printf(" -s --scale [1..n] Scale down by the given factor for quick and dirty previews (default=%d)\n", scale);
353 printf(" -t --test <test> Generate test images. Use 'help' for list of tests\n");
356 static void print_test_help()
358 printf(" -t --test <test> Generate test images...\n");
360 printf(" flow-next Optical flow plane to next image\n");
361 printf(" flow-prev Optical flow plane to previous image\n");
363 printf(" marked Only apply marked colors to grey image\n");
364 printf(" mask Show mask of marked areas\n");
365 printf(" mask+color Show mask of marked areas + color\n");
366 printf(" bc-only Only apply brightness+contrast, leave colors of grey image as is\n");
367 printf(" bc-image Show brightness+contrast change on grey image as uv components\n");
368 printf(" alpha Show the image with alpha channel only\n");
369 printf(" no-alpha Show the image without alpha channel, to see pixles that are made transparent\n");
370 printf(" removal-image Show the image with \"transparency removal layer\" only, but keep u and v\n");
377 int main(int argc, char *argv[])
379 darray_t *gI = NULL, *cI = NULL, *mI = NULL, *I = NULL;
380 darray_t *flow = NULL, *flow_i = NULL;
381 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;
384 int w = 0, h = 0, load_w, load_h, k = 1, index = 0, z;
385 unsigned short *img = NULL;
386 unsigned char *mark_buffer = NULL;
389 const char* filename;
390 char first_filename[256];
391 int seq_offset = 0, seq_next = 0;
392 int features, change_bc, change_alpha;
393 char *feat_names[20];
396 skip_args = handle_options(argc, argv);
406 if (argc > 1 && !strcmp(argv[1], "sequence")) {
407 k = load_sequence(&seq_offset, &seq_next, first_filename);
410 printf("Got %d frames from sequence (frames %d..%d)\n", k, seq_offset, seq_offset + k - 1);
411 if (argc > 2 && (!strcmp(argv[2], "list") || atoi(argv[2]) > seq_offset)) {
412 seq_offset = seq_next;
415 } else if (argc <= 3) {
418 } else if (argc > 5) {
420 index = atoi(argv[5]);
426 if (k > SINGLE_K_TEST)
432 change_bc = change_alpha = 0;
433 for (z = 0; z < k; z++) {
435 filename = sequence[z].filename;
436 /* first_filename is set by load_sequence */
439 strcpy(first_filename, argv[1]);
442 // load flow settings
443 if (sequence && optical_flow)
446 load_settings(first_filename);
448 // load flow settings
449 if (sequence && optical_flow) {
450 if (flow_enable == 0 && (test == FLOW_NEXT || test == FLOW_PREV)) {
451 fprintf(stderr, "Cannot test optical flow, because it is not enabled by GUI.\n");
456 // load original image and convert their RGB components to double RGB array
457 img = load_img(&load_w, &load_h, filename, index + z);
459 fprintf(stderr, "Failed to load grey image '%s'\n", filename);
462 scale_img(img, load_w, load_h, scale);
467 if (load_w/scale != w || load_h/scale != h) {
468 fprintf(stderr, "Error: All input images must have equal dimenstions.\n");
471 // now we know the dimensions, so we can create input arrays
473 dims[0] = w; dims[1] = h; dims[2] = 3; dims[3] = k;
474 gI = darrayCreate(4, dims);
477 printf("failed to create grey image array\n");
481 dims[0] = w; dims[1] = h; dims[2] = 3; dims[3] = k;
482 cI = darrayCreate(4, dims);
485 printf("failed to create marked image array\n");
488 img2array_short(img, w, h, darrayGetPr(gI) + w*h*3*z, w, h);
491 if (sequence || !strcmp(argv[2], "marked")) {
494 // load marked mask and convert their RGB components to double YUV array
495 memcpy(darrayGetPr(cI) + w*h*3*z, darrayGetPr(gI) + w*h*3*z, w*h*3 * sizeof(double));
496 /* add extra memory for unscaled data to prevent buffer overflow */
498 mark_buffer = (unsigned char *)malloc(w*h*k + load_w*load_h);
500 printf("no memory for mark buffer\n");
503 if (load_palette(first_filename)) {
504 printf("failed to load palette for file: '%s'\n", filename);
507 sprintf(name, filename, index + z);
508 /* always load full unscaled image, then scale down */
509 if (load_marked(mark_buffer + w*h*z, load_w, load_h, name) == 0) {
510 scale_mark(mark_buffer + w*h*z, load_w, load_h, scale);
511 ptr_cI = darrayGetPr(cI) + w*h*3*z;
512 for (y = 0; y < h; y++) {
513 for (x = 0; x < w; x++) {
514 /* do not apply mask on index 0 */
515 c = mark_buffer[y*w+x + w*h*z];
518 /* check for any brightness/contrast change */
519 if (bright_contrast && (mark_palette[c-1].bright != 0 || mark_palette[c-1].contrast != 1))
521 /* check for any alpha change */
522 if (alpha_change && mark_palette[c-1].alpha < 1)
524 /* do not apply white pixles, this meas: keep original color */
525 if (mark_palette[c-1].r == 255 && mark_palette[c-1].g == 255 && mark_palette[c-1].b == 255)
527 ptr_cI[y*w+x] = mark_palette[c-1].r / 255.0F;
528 ptr_cI[y*w+x + w*h] = mark_palette[c-1].g / 255.0F;
529 ptr_cI[y*w+x + w*h*2] = mark_palette[c-1].b / 255.0F;
533 memset(mark_buffer + w*h*z, 0, w*h);
535 // load marked image and convert their RGB components to double YUV array
536 img = load_img(&load_w, &load_h, argv[2], index + z);
538 scale_img(img, load_w, load_h, scale);
539 if (load_w/scale != w || load_h/scale != h) {
540 fprintf(stderr, "Error: All input images must have equal dimenstions.\n");
543 img2array_short(img, w, h, darrayGetPr(cI) + w*h*3*z, w, h);
546 fprintf(stderr, "Failed to load marked image, omitting...\n");
547 memcpy(darrayGetPr(cI) + w*h*3*z, darrayGetPr(gI) + w*h*3*z, w*h*3 * sizeof(double));
552 rc = alloc_I_arrays(&I, &mI, w, h, k, &features, feat_names, change_alpha, change_bc);
556 for (z = 0; z < k; z++) {
557 set_I_ptr(I, mI, w, h, z, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
558 ptr_gI = darrayGetPr(gI) + w*h*3*z;
559 ptr_cI = darrayGetPr(cI) + w*h*3*z;
561 // convert original image into YUV
562 rgb2yuv(ptr_gI, ptr_gI, w, h);
563 // convert maked image into YUV
564 rgb2yuv(ptr_cI, ptr_cI, w, h);
566 if (sequence || !strcmp(argv[2], "marked")) {
568 // use marked mask to fill markIm
569 for (y = 0; y < h; y++) {
570 for (x = 0; x < w; x++) {
571 /* do not apply mask on index 0 */
572 c = mark_buffer[y*w+x + w*h*z];
580 // fill color image with marked pixles
581 // - calculate the difference between two images (original image - color image)
582 // - convert into absolute (positive values)
583 // - sum all components to get grey image
584 // - apply threshold (pixle is 1F, if the absolute difference is > 0.01F)
585 // original code: markIm=(sum(abs(gI-cI),3)>0.01); (according to developers of the algorithm)
586 for (i = 0, ii = w * h; i < ii; i++) {
588 sum = ptr_gI[i] - ptr_cI[i];
593 sum = ptr_gI[i + ii] - ptr_cI[i + ii];
598 sum = ptr_gI[i + ii + ii] - ptr_cI[i + ii + ii];
610 prepare_arrays(w, h, change_alpha, change_bc, mark_buffer+w*h*z, ptr_gI, ptr_cI, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, test);
614 if (k > 1 && flow_enable) {
615 /* create flow vectors */
616 dims[0] = w; dims[1] = h; dims[2] = k - 1; dims[3] = 2;
617 flow = darrayCreate(4, dims);
619 printf("failed to create array\n");
622 flow_i = darrayCreate(4, dims);
624 printf("failed to create array\n");
627 printf("Calculating optical flow for %d frames: window=%d\n", k, flow_window/scale);
629 printf("Note: Optical flow is not activated!\n");
630 for (z = 0; z < k-1; z++) {
632 create_flow_maps(NULL, darrayGetPr(gI) + w*h*3*(z+1), darrayGetPr(gI) + w*h*3*z, w, h, flow_window/scale, 0, NULL, NULL, darrayGetPr(flow) + w*h*z, darrayGetPr(flow) + w*h*z + w*h*(k-1), NULL);
634 create_flow_maps(darrayGetPr(gI) + w*h*3*z, NULL, darrayGetPr(gI) + w*h*3*(z+1), w, h, flow_window/scale, 0, darrayGetPr(flow_i) + w*h*z, darrayGetPr(flow_i) + w*h*z + w*h*(k-1), NULL, NULL, NULL);
638 printf("Note: Optical flow is not compiled in!\n");
646 if (test != FLOW_NEXT && test != FLOW_PREV && test != MARKED && test != MASK && test != MASK_COLOR && test != BC_ONLY && test != BC_IMAGE) {
647 printf("Colorizing %d frames, please wait...\n", k);
648 rc = colorize(I, mI, flow, flow_i, in_itr_num, out_itr_num, target_residual_change, quick, scalexyz, feat_names, NULL);
651 printf("No memory! Use smaller frames or less frames between key frames or add more memory.\n");
653 printf("No memory! Use smaller image or add more memory.\n");
658 for (z = 0; z < k; z++) {
659 set_I_ptr(I, mI, w, h, z, features, change_alpha, change_bc, &ptr_y, &ptr_u, &ptr_v, &ptr_a, &ptr_r, &ptr_b, &ptr_c, &ptr_m);
660 postpare_arrays(w, h, change_alpha, change_bc, ptr_y, ptr_u, ptr_v, ptr_a, ptr_r, ptr_b, ptr_c, ptr_m, test);
663 if (test == FLOW_NEXT || test == FLOW_PREV) {
664 double *ptr_f1 = NULL, *ptr_f2 = NULL;
665 /* apply flow planes to result image as u and y vector */
666 if (test == FLOW_NEXT) {
668 ptr_f1 = darrayGetPr(flow) + w*h*z;
669 ptr_f2 = darrayGetPr(flow) + w*h*z*(k-1);
673 ptr_f1 = darrayGetPr(flow_i) + w*h*z;
674 ptr_f2 = darrayGetPr(flow_i) + w*h*z*(k-1);
677 if (ptr_f1 && ptr_f1) {
678 for (y = 0; y < h; y++) {
679 for (x = 0; x < w; x++) {
682 ptr_u[w*y+x] = ptr_f1[w * y + x] / 50;
683 ptr_v[w*y+x] = ptr_f2[w * y + x] / 50;
694 // save result YUV array to image with RGB components
695 yuv2rgb(ptr_y, ptr_y, w, h);
697 static char name[256], *p, *q;
698 p = sequence[z].filename;
699 while((q = strchr(p, DIR_SEPERATOR)))
701 if (output_prefix[0] == '\0') {
702 strcpy(name, sequence[z].filename);
703 name[p - sequence[z].filename] = '\0';
704 strcat(name, "colorized_");
706 strcpy(name, output_prefix);
712 /* don't save alpha on these tests */
713 if (test == ALPHA || test == REMOVAL_IMAGE || test == NO_ALPHA)
714 save_img_array(ptr_y, w, h, 0, filename, index + z);
716 save_img_array(ptr_y, w, h, change_alpha, filename, index + z);
720 printf("Elapsed time: %d minutes, %d seconds\n", (int)(end-start)/60, (int)(end-start)%60);
729 darrayDestroy(flow_i);
741 /* if end frame is not given or if not reached */
742 if (argc <= 3 || atoi(argv[3]) > seq_offset + k) {
743 seq_offset = seq_offset + k - 1;