Do not show colorization progress when using quick render mode
[colorize.git] / lib / colorize.c
1 #include <stdio.h>
2 #include <string.h>
3 #include <stdlib.h>
4 #include <math.h>
5 #include "darray.h"
6 #include "multigrid.h"
7 #include "colorize.h"
8
9 /* colorize image array using image_mark
10  *
11  * image:
12  *      first dimansion = width
13  *      second dimension = height
14  *      thrid dimension = components (first component is luminance, other components are features, like u, v)
15  *      fourth dimension = time
16  *
17  * image_mark:
18  *      first dimansion = width
19  *      second dimension = height
20  *      fourth dimension = time
21  */
22 int colorize_prepare(struct colorize *col, int quick, int alloc)
23 {
24         int dimensions[4];
25         int ww, hh, kk, last_kk, d, temp, z;
26         darray_t *luminance = NULL;
27         int rc = -1;
28
29         ASSERT(darrayGetNumberOfDimensions(col->image) == 4, "image array must have 4 dimensions");
30         col->w = darrayGetDimensions(col->image)[0];
31         col->h = darrayGetDimensions(col->image)[1];
32         col->comp = darrayGetDimensions(col->image)[2];
33         col->k = darrayGetDimensions(col->image)[3];
34         ASSERT(col->comp > 0, "image array requires at least one component (Y-component)");
35
36         ASSERT(darrayGetNumberOfDimensions(col->image_mark) == 3, "image_mark array must have 3 dimensions");
37         ASSERT(col->w == darrayGetDimensions(col->image_mark)[0], "image_mark and image must both have same x-size");
38         ASSERT(col->h == darrayGetDimensions(col->image_mark)[1], "image_mark and image must both have same y-size");
39         ASSERT(col->k == darrayGetDimensions(col->image_mark)[2], "image_mark and image must both have same z-size");
40
41         /* Calculate maximum depth
42          * Scale down dimensions until at least 2x2 remains
43          */
44         temp = min(col->w, col->h);
45         for (col->max_depth = 0; temp > 2; col->max_depth++)
46                 temp=(temp+1)>>1;
47         ASSERT(col->max_depth >= 2, "image too small");
48
49         if (alloc)
50                 col->nb_list = calloc(col->max_depth, sizeof(struct neighbors *));
51         if (!col->nb_list) {
52                 rc = -1;
53                 goto error;
54         }
55         if (alloc)
56                 col->marks = calloc(col->max_depth, sizeof(darray_t *));
57         if (!col->marks) {
58                 rc = -1;
59                 goto error;
60         }
61         if (alloc)
62                 col->values = calloc(col->max_depth, sizeof(darray_t *));
63         if (!col->values) {
64                 rc = -1;
65                 goto error;
66         }
67         if (alloc)
68                 col->flows = calloc(col->max_depth, sizeof(darray_t *));
69         if (!col->flows) {
70                 rc = -1;
71                 goto error;
72         }
73         if (alloc)
74                 col->flows_i = calloc(col->max_depth, sizeof(darray_t *));
75         if (!col->flows_i) {
76                 rc = -1;
77                 goto error;
78         }
79         if (col->scalexyz) {
80                 /* the flows_xy are scaled in xy in the current level */
81                 if (alloc)
82                         col->flows_xy = calloc(col->max_depth, sizeof(darray_t *));
83                 if (!col->flows_xy) {
84                         rc = -1;
85                         goto error;
86                 }
87         }
88         dimensions[0] = col->w;
89         dimensions[1] = col->h;
90         dimensions[2] = col->k;
91         luminance = darrayCreate(3, dimensions);
92         if (!luminance) {
93                 rc = -1;
94                 goto error;
95         }
96         /* generate sparse multigrid */
97         last_kk = kk = col->k;
98         if (!quick)
99                 printf("-> prepare sparse grid");
100         for (d = 0, ww=col->w, hh=col->h; d < col->max_depth; d++, ww=(ww+1)>>1, hh=(hh+1)>>1) {
101                 /* create temporary arrays
102                  * copy fist array to level 0 or shrink previous level
103                  */
104                 if (!quick)
105                         printf(" #%d(w=%d h=%d k=%d)", d, ww, hh, kk); fflush(stdout);
106                 dimensions[0] = ww;
107                 dimensions[1] = hh;
108                 dimensions[2] = last_kk;
109                 if (alloc)
110                         col->marks[d] = darrayCreate(3, dimensions);
111                 if (!col->marks[d]) {
112                         rc = -1;
113                         goto error;
114                 }
115                 dimensions[0] = ww;
116                 dimensions[1] = hh;
117                 dimensions[2] = last_kk-1;
118                 dimensions[3] = 2;
119                 if (alloc)
120                         col->flows[d] = darrayCreate(4, dimensions);
121                 if (!col->flows[d]) {
122                         rc = -1;
123                         goto error;
124                 }
125                 if (alloc)
126                         col->flows_i[d] = darrayCreate(4, dimensions);
127                 if (!col->flows_i[d]) {
128                         rc = -1;
129                         goto error;
130                 }
131                 if (d < col->scalexyz) {
132                         dimensions[0] = (ww+1)>>1;
133                         dimensions[1] = (hh+1)>>1;
134                         dimensions[2] = kk-1;
135                         dimensions[3] = 2;
136                         if (alloc)
137                                 col->flows_xy[d] = darrayCreate(4, dimensions);
138                         if (!col->flows_xy[d]) {
139                                 rc = -1;
140                                 goto error;
141                         }
142                 }
143                 if (d == 0) {
144                         for (z = 0; z < kk; z++) {
145                                 darrayCheckPr(luminance, darrayGetPr(luminance) + z*col->w*col->h, col->w*col->h);
146                                 darrayCheckPr(col->image, darrayGetPr(col->image) + z*col->w*col->h*col->comp, col->w*col->h);
147                                 memcpy(darrayGetPr(luminance) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*col->comp, col->w*col->h*sizeof(double));
148                         }
149                         if (col->flow && col->flow_i) {
150                                 darrayCheckPr(col->flows[d], darrayGetPr(col->flows[d]), col->w*col->h*(kk-1)*2);
151                                 darrayCheckPr(col->flow, darrayGetPr(col->flow), col->w*col->h*(kk-1)*2);
152                                 memcpy(darrayGetPr(col->flows[d]), darrayGetPr(col->flow), col->w*col->h*(kk-1)*2*sizeof(double));
153                                 darrayCheckPr(col->flows_i[d], darrayGetPr(col->flows_i[d]), col->w*col->h*(kk-1)*2);
154                                 darrayCheckPr(col->flow_i, darrayGetPr(col->flow_i), col->w*col->h*(kk-1)*2);
155                                 memcpy(darrayGetPr(col->flows_i[d]), darrayGetPr(col->flow_i), col->w*col->h*(kk-1)*2*sizeof(double));
156                         }
157                         darrayCheckPr(col->marks[d], darrayGetPr(col->marks[d]), col->w*col->h*kk);
158                         darrayCheckPr(col->image_mark, darrayGetPr(col->image_mark), col->w*col->h*kk);
159                         memcpy(darrayGetPr(col->marks[d]), darrayGetPr(col->image_mark), col->w*col->h*kk*sizeof(double));
160                         /* invert, so 0 = marked */
161                         quantize(col->marks[d], 0.5, 0, 1);
162                 } else {
163                         rc = shrink_xy(luminance, NULL);
164                         if (rc < 0)
165                                 goto error;
166                         rc = shrink_xy(col->marks[d-1], col->marks[d]);
167                         if (rc < 0)
168                                 goto error;
169                         rc = shrink_xy(col->flows[d-1], col->flows[d]);
170                         if (rc < 0)
171                                 goto error;
172                         rc = shrink_xy(col->flows_i[d-1], col->flows_i[d]);
173                         if (rc < 0)
174                                 goto error;
175                         /* shrink length of flow vector on smaller grid.
176                          * This is not performed when comparing with
177                          * the original algorithm. (it is a bug there)
178                          */
179                         multiply(col->flows[d], 0.5);
180                         multiply(col->flows_i[d], 0.5);
181                         if (d-1 < col->scalexyz) { /* process if previous d shall be shrinked in z direction */
182                                 /* shrink time */
183                                 rc = shrink_z(luminance, NULL, col->flows[d]);
184                                 if (rc < 0)
185                                         goto error;
186                                 rc = shrink_z(col->marks[d], NULL, col->flows[d]);
187                                 if (rc < 0)
188                                         goto error;
189                                 rc = shrink_flow_z(col->flows[d], NULL);
190                                 if (rc < 0)
191                                         goto error;
192                                 rc = shrink_flow_z(col->flows_i[d], NULL);
193                                 if (rc < 0)
194                                         goto error;
195                         }
196                         /* If any of the restricted pixles is 0 (marked),
197                          * the result must be 0 (marked) too.
198                          */
199                         quantize(col->marks[d], 0.9999, 1, 0);
200                 }
201                 if (d < col->scalexyz) {
202                         /* create x and y shrinked flow vectors for restriction and prolonging process */
203                         rc = shrink_xy(col->flows[d], col->flows_xy[d]);
204                         if (rc < 0)
205                                 goto error;
206                         multiply(col->flows_xy[d], 0.5);
207                 }
208
209                 /* generate values array */
210                 dimensions[0] = ww;
211                 dimensions[1] = hh;
212                 dimensions[2] = kk;
213                 if (alloc)
214                         col->values[d] = darrayCreate(3, dimensions);
215                 if (!col->values[d]) {
216                         rc = -1;
217                         goto error;
218                 }
219
220                 /* generate array of neighbors */
221 #ifndef TEST_NO_RENDER
222                 if (alloc)
223                         col->nb_list[d] = gen_neighbor(ww, hh, kk, col->flows[d], col->flows_i[d]);
224                 if (!col->nb_list[d]) {
225                         rc = -1;
226                         goto error;
227                 }
228                 /* weighten */
229                 if (alloc)
230                         weighten(luminance, col->nb_list[d]);
231 #endif
232
233                 last_kk = kk;
234                 if (d < col->scalexyz)
235                         kk = (kk+1)>>1;
236         }
237         darrayDestroy(luminance);
238         luminance = NULL;
239         if (!quick)
240                 printf("\n");
241
242         dimensions[0] = col->w;
243         dimensions[1] = col->h;
244         dimensions[2] = col->k;
245         if (alloc)
246                 col->init = darrayCreate(3, dimensions);
247         if (!col->init) {
248                 rc = -1;
249                 goto error;
250         }
251
252 #ifdef TEST_PYRAMID
253         dimensions[0] = col->w;
254         dimensions[1] = col->h;
255         dimensions[2] = col->k;
256         luminance = darrayCreate(3, dimensions);
257         for (z = 0; z < col->k; z++) {
258                 darrayCheckPr(luminance, darrayGetPr(luminance) + z*col->w*col->h, col->w*col->h);
259                 darrayCheckPr(col->image, darrayGetPr(col->image) + z*col->w*col->h*comp, col->w*col->h);
260                 memcpy(darrayGetPr(luminance) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*comp, col->w*col->h*sizeof(double));
261                 darrayCheckPr(col->values[0], darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h);
262                 darrayCheckPr(col->image, darrayGetPr(col->image) + z*col->w*col->h*comp, col->w*col->h);
263                 memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*comp, col->w*col->h*sizeof(double));
264 #ifdef TEST_FLOW
265                 draw_flow(col->values[0], col->flows[0], col->flows_i[0]);
266 #endif
267 #ifdef TEST_MARKED
268                 paste(col->marks[0], col->values[0], 0, 0, 0);
269 #endif
270
271         }
272         for (d = 1; d < col->max_depth; d++) {
273                 rc = shrink_xy(luminance, NULL);
274                 if (rc < 0)
275                         goto error;
276                 if (d-1 < col->scalexyz)
277                         shrink_z(luminance, NULL, col->flows_xy[d-1]);
278                 paste(luminance, col->values[0], 0, 0, 0);
279 #ifdef TEST_FLOW
280                 draw_flow(col->values[0], col->flows_x[d], col->flows_ix[d]);
281 #endif
282 #ifdef TEST_MARKED
283                 paste(col->marks[d], col->values[0], 0, 0, 0);
284 #endif
285         }
286         darrayDestroy(luminance);
287         luminance = NULL;
288         /* copy test pyramid image as Y-component */
289         for (z = 0; z < col->k; z++) {
290                 darrayCheckPr(col->image, darrayGetPr(col->image) + z*col->w*col->h*col->comp, col->w*col->h);
291                 darrayCheckPr(col->values[0], darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h);
292                 memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
293         }
294 #endif
295
296         rc = 0;
297
298 error:
299         darrayDestroy(luminance);
300
301         return rc;
302 }
303
304 int colorize_solve(struct colorize *col, int quick, char **feat_names)
305 {
306         int z, d, c, ww, hh, kk;
307         int rc = -1;
308
309         if (!quick)
310                 printf("-> apply component to grid and solve");
311         for (c = 1; c < col->comp; c++) {
312                 int pixles, j;
313                 double *value_ptr, *init_ptr, *mark_ptr;
314
315                 if (!quick)
316                         printf(" #%d(%s)", c, feat_names[c-1]); fflush(stdout);
317                 /* apply component
318                  * - copy component into value array (level 0), otherwise 0
319                  * - use maked colors for init array, otherwise use 0
320                  */
321                 for (z = 0; z < col->k; z++) {
322                         darrayCheckPr(col->values[0], darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h);
323                         darrayCheckPr(col->image, darrayGetPr(col->image) + c*col->w*col->h + z*col->w*col->h*col->comp, col->w*col->h);
324                         memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + c*col->w*col->h + z*col->w*col->h*col->comp, col->w*col->h*sizeof(double));
325                 }
326                 for (d = 1, ww=(col->w+1)>>1, hh=(col->h+1)>>1, kk=col->k; d < col->max_depth; d++, ww=(ww+1)>>1, hh=(hh+1)>>1) {
327                         if (d-1 < col->scalexyz) /* scale kk, if last array was scaled */
328                                 kk=(kk+1)>>1;   
329                         value_ptr = darrayGetPr(col->values[d]);
330                         pixles = ww*hh*kk;
331                         for (j = 0; j < pixles; j++) {
332                                 darrayCheckPr(col->values[d], value_ptr, 1);
333                                 *value_ptr++ = 0.0;
334                         }
335                 }
336                 value_ptr = darrayGetPr(col->values[0]);
337                 init_ptr = darrayGetPr(col->init);
338                 mark_ptr = darrayGetPr(col->image_mark);
339                 pixles = col->w*col->h*col->k;
340                 for (j = 0; j < pixles; j++) {
341                         darrayCheckPr(col->image_mark, mark_ptr, 1);
342                         if (*mark_ptr++ > 0.5) {
343                                 darrayCheckPr(col->init, init_ptr, 1);
344                                 darrayCheckPr(col->values[0], value_ptr, 1);
345                                 *init_ptr++ = *value_ptr;
346                         } else {
347                                 darrayCheckPr(col->init, init_ptr, 1);
348                                 *init_ptr++ = 0.0;
349                         }
350                         value_ptr++;
351                 }
352
353 #ifndef TEST_NO_RENDER
354                 /* colorize component */
355                 if (quick) {
356                         rc = solve_mg(col->max_depth, col->inner_iter, 1, col->values, col->marks, col->init, col->nb_list, col->flows_xy, col->scalexyz);
357                         if (rc < 0)
358                                 goto error;
359                 } else {
360                         int i;
361                         for (i = 0; i < col->outer_iter; i++) {
362                                 rc = solve_mg(col->max_depth, col->inner_iter, 2, col->values, col->marks, col->init, col->nb_list, col->flows_xy, col->scalexyz);
363                                 if (rc < 0)
364                                         goto error;
365                                 rc = solve_mg((col->max_depth+1) / 2, col->inner_iter, 2, col->values, col->marks, col->init, col->nb_list, col->flows_xy, col->scalexyz);
366                                 if (rc < 0)
367                                         goto error;
368                                 rc = solve_mg(2, col->inner_iter, 2, col->values, col->marks, col->init, col->nb_list, col->flows_xy, col->scalexyz);
369                                 if (rc < 0)
370                                         goto error;
371                                 rc = solve_mg(1, col->inner_iter, 4, col->values, col->marks, col->init, col->nb_list, col->flows_xy, col->scalexyz);
372                                 if (rc < 0)
373                                         goto error;
374                         }
375                 }
376 #endif
377
378 #ifdef TEST_PYRAMID
379                 for (d = 1; d < col->max_depth; d++)
380                         paste(col->values[d], col->values[0], 0, 0, 0);
381 #endif
382
383                 /* apply colorized component */
384                 for (z = 0; z < col->k; z++) {
385                         darrayCheckPr(col->image, darrayGetPr(col->image) + c*col->w*col->h + z*col->w*col->h*col->comp, col->w*col->h);
386                         darrayCheckPr(col->values[0], darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h);
387                         memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
388                 }
389         }
390         if (!quick)
391                 printf("\n");
392
393 #ifdef TEST_SHRINK_XY
394         for (c = 0; c < col->comp; c++) {
395                 darray_t *temp;
396                 int dimensions[3] = {col->w, col->h, col->k};
397                 for (z = 0; z < col->k; z++)
398                         memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, col->w*col->h*sizeof(double));
399                 dimensions[0] = (col->w+1)>>1;
400                 dimensions[1] = (col->h+1)>>1;
401                 temp = darrayCreate(3, dimensions);
402                 ASSERT(temp, "no memory");
403                 rc = shrink_xy(col->values[0], temp);
404                 ASSERT(rc >= 0, "no memory");
405                 paste(temp, col->values[0], 0, 0, 0);
406                 darrayDestroy(temp);
407                 for (z = 0; z < col->k; z++)
408                         memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
409         }
410 #endif
411
412 #ifdef TEST_SHRINK_Z
413         for (c = 0; c < col->comp; c++) {
414                 darray_t *temp;
415                 int dimensions[3] = {col->w, col->h, col->k};
416                 for (z = 0; z < col->k; z++)
417                         memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, col->w*col->h*sizeof(double));
418                 dimensions[2] = (col->k+1)>>1;
419                 temp = darrayCreate(3, dimensions);
420                 ASSERT(temp, "no memory");
421                 rc = shrink_z(col->values[0], temp, col->flows[0]);
422                 ASSERT(rc >= 0, "no memory");
423                 paste(temp, col->values[0], 0, 0, 0);
424                 darrayDestroy(temp);
425                 for (z = 0; z < col->k; z++)
426                         memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
427         }
428 #endif
429
430 #ifdef TEST_EXPAND_XY
431         for (c = 0; c < col->comp; c++) {
432                 darray_t *temp;
433                 int dimensions[3] = {col->w, col->h, col->k};
434                 for (z = 0; z < col->k; z++)
435                         memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, col->w*col->h*sizeof(double));
436                 dimensions[0] = (col->w+1)>>1;
437                 dimensions[1] = (col->h+1)>>1;
438                 temp = darrayCreate(3, dimensions);
439                 ASSERT(temp, "no memory");
440                 rc = shrink_xy(col->values[0], temp);
441                 ASSERT(rc >= 0, "no memory");
442                 expand_xy(temp, col->values[0]);
443                 darrayDestroy(temp);
444                 for (z = 0; z < col->k; z++)
445                         memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
446         }
447 #endif
448
449 #ifdef TEST_EXPAND_Z
450         for (c = 0; c < col->comp; c++) {
451                 darray_t *temp;
452                 int dimensions[3] = {col->w, col->h, col->k};
453                 for (z = 0; z < col->k; z++)
454                         memcpy(darrayGetPr(col->values[0]) + z*col->w*col->h, darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, col->w*col->h*sizeof(double));
455                 dimensions[2] = (col->k+1)>>1;
456                 temp = darrayCreate(3, dimensions);
457                 ASSERT(temp, "no memory");
458                 rc = shrink_z(col->values[0], temp, col->flows[0]);
459                 ASSERT(rc >= 0, "no memory");
460                 rc = expand_z(temp, col->values[0], col->flows[0]);
461                 ASSERT(rc >= 0, "no memory");
462                 darrayDestroy(temp);
463                 for (z = 0; z < col->k; z++)
464                         memcpy(darrayGetPr(col->image) + z*col->w*col->h*col->comp + c*col->w*col->h, darrayGetPr(col->values[0]) + z*col->w*col->h, col->w*col->h*sizeof(double));
465         }
466 #endif
467
468         rc = 0;
469
470 error:
471         return rc;
472 }
473
474 void colorize_free(struct colorize *col)
475 {
476         int d;
477
478         /* free memory */
479         for (d = 0; d < col->max_depth; d++) {
480                 if (col->nb_list)
481                         free(col->nb_list[d]);
482                 if (col->marks)
483                         darrayDestroy(col->marks[d]);
484                 if (col->values)
485                         darrayDestroy(col->values[d]);
486                 if (col->flows_xy)
487                         darrayDestroy(col->flows_xy[d]);
488                 if (col->flows)
489                         darrayDestroy(col->flows[d]);
490                 if (col->flows_i)
491                         darrayDestroy(col->flows_i[d]);
492         }
493         free(col->nb_list);
494         free(col->marks);
495         free(col->values);
496         free(col->flows_xy);
497         free(col->flows);
498         free(col->flows_i);
499         darrayDestroy(col->init);
500 }
501
502 int colorize(const darray_t *image, const darray_t *image_mark, const darray_t *flow, const darray_t *flow_i, int inner_iter, int outer_iter, int quick, int scalexyz, char **feat_names, struct colorize **_col)
503 {
504         struct colorize *col;
505         int rc = -1;
506         int alloc = 0;
507
508         if (!_col || !(*_col)) {
509                 col = calloc(sizeof(*col), 1);
510                 memset(col, 0, sizeof(*col));
511                 col->image = image;
512                 col->image_mark = image_mark;
513                 col->flow = flow;
514                 col->flow_i = flow_i;
515                 col->inner_iter = inner_iter;
516                 col->outer_iter = outer_iter;
517                 col->scalexyz = scalexyz;
518                 alloc = 1;
519         }
520         /* use or assign *_col */
521         if (_col) {
522                 if (!(*_col))
523                         *_col = col;
524                 else
525                         col = *_col;
526         }
527
528         rc = colorize_prepare(col, quick, alloc);
529         if (rc < 0)
530                 goto error;
531
532         rc = colorize_solve(col, quick, feat_names);
533         if (rc < 0)
534                 goto error;
535
536         rc = 0;
537
538 error:
539         if (!_col)
540                 colorize_free(col);
541
542         return rc;
543 }