8 /* just process, but do not generate neighbor list and do not solve multigrid */
9 //#define TEST_NO_RENDER
11 /* paste all color+luminance pyramids (from large to small) into result */
12 //#define TEST_PYRAMID
14 /* test flow planes by drawing vectors into image
15 * note: this only works in combination with TEST_PYRAMID
19 /* test makred planes as pyramid on the result
20 * note: this only works in combination with TEST_PYRAMID
24 /* test shrinking of X and Y only */
25 //#define TEST_SHRINK_XY
27 /* test shrinking of X, Y and Z */
28 //#define TEST_SHRINK_Z
30 /* test expanding of X and Y only */
31 //#define TEST_EXPAND_XY
33 /* test expanding of X, Y and Z */
34 //#define TEST_EXPAND_Z
36 /* print error message b, if a is false */
37 #define ASSERT(a, b) \
38 { if (!(a)) { fprintf(stderr, "%s %s() Error in line %d: %s\n", __FILE__, __func__, __LINE__, (b)); abort(); } }
40 void ASSERT_FLOW(int w, int h, int k, const darray_t *flow_x, const darray_t *flow_y, const darray_t *flow_ix, const darray_t *flow_iy)
43 ASSERT(darrayGetNumberOfDimensions(flow_x) == 3, "flow_x array must have 3 dimensions");
44 ASSERT(w == darrayGetDimensions(flow_x)[0], "x-sizes of flow_x vectors are different");
45 ASSERT(h == darrayGetDimensions(flow_x)[1], "y-sizes of flow_x vectors are different");
46 ASSERT(k-1 == darrayGetDimensions(flow_x)[2], "z-sizes of flow_x vectors are not k-1");
49 ASSERT(darrayGetNumberOfDimensions(flow_y) == 3, "flow_y array must have 3 dimensions");
50 ASSERT(w == darrayGetDimensions(flow_y)[0], "x-sizes of flow_y vectors are different");
51 ASSERT(h == darrayGetDimensions(flow_y)[1], "y-sizes of flow_y vectors are different");
52 ASSERT(k-1 == darrayGetDimensions(flow_y)[2], "z-sizes of flow_y vectors are not k-1");
55 ASSERT(darrayGetNumberOfDimensions(flow_ix) == 3, "flow_ix array must have 3 dimensions");
56 ASSERT(w == darrayGetDimensions(flow_ix)[0], "x-sizes of flow_ix vectors are different");
57 ASSERT(h == darrayGetDimensions(flow_ix)[1], "y-sizes of flow_ix vectors are different");
58 ASSERT(k-1 == darrayGetDimensions(flow_ix)[2], "z-sizes of flow_ix vectors are not k-1");
61 ASSERT(darrayGetNumberOfDimensions(flow_iy) == 3, "flow_iy array must have 3 dimensions");
62 ASSERT(w == darrayGetDimensions(flow_iy)[0], "x-sizes of flow_iy vectors are different");
63 ASSERT(h == darrayGetDimensions(flow_iy)[1], "y-sizes of flow_iy vectors are different");
64 ASSERT(k-1 == darrayGetDimensions(flow_iy)[2], "z-sizes of flow_iy vectors are not k-1");
68 #define min(a, b) ((a < b) ? a : b)
69 #define max(a, b) ((a > b) ? a : b)
71 #define NEIGHBORS_2D 9
72 #define NEIGHBORS_3D 27
75 int num; /* # of neighbors */
76 int index[NEIGHBORS_2D]; /* index of neighbors in an array */
77 double weight[NEIGHBORS_2D]; /* calculated weight of neighbors */
80 int num; /* # of neighbors */
81 int index[NEIGHBORS_3D]; /* index of neighbors in an array */
82 double weight[NEIGHBORS_3D]; /* calculated weight of neighbors */
85 static struct neigh_off {
87 } neigh_off[NEIGHBORS_3D] = {
88 { 0, 0, 0 }, /* entry [0] always points to the same point */
97 { 0, 0, 1 }, /* here begins the 3D part */
117 /* Shrink matrix by reducing z planes
119 * Every second (odd) plane is removed in the followin way:
120 * - The even plane is taken and the following odd plane is summed, using
121 * forward motion flow vectors. (If the motion vectors are not ouside the
123 * - The result is averaged.
125 * if the number of planes are odd, the last (even) plane is just copied.
127 * src plane 0 ---->_(+) dst plane 0
130 * / forward flow plane 0
135 * src plane 2 ---->_(+) dst plane 1
138 * / forward flow plane 2
143 * src plane 4 -------> dst plane 2
145 static int shrink_z(darray_t *src, darray_t *dst, const darray_t *flow_x, const darray_t *flow_y)
147 int x, y, z, xx, yy, w, h, ks, kd;
149 double *src_ptr, *dst_ptr, *sum_ptr, *flow_x_ptr, *flow_y_ptr;
150 darray_t *sum = NULL;
153 ASSERT(darrayGetNumberOfDimensions(src) == 3, "src array must have 3 dimensions");
154 w = darrayGetDimensions(src)[0];
155 h = darrayGetDimensions(src)[1];
156 ks = darrayGetDimensions(src)[2];
159 /* create dst, if not given */
161 int dimensions[3] = {w, h, kd};
163 dst = darrayCreate(3, dimensions);
169 ASSERT(darrayGetNumberOfDimensions(dst) == 3, "dst array must have 3 dimensions");
170 ASSERT(w == darrayGetDimensions(dst)[0], "x-size of source and destination must be equal");
171 ASSERT(h == darrayGetDimensions(dst)[1], "y-size of source and destination must be equal");
172 ASSERT(kd == ((ks+1)>>1), "z-size of destination must be half of the source (+an extra plane if source z-size is odd)");
173 ASSERT_FLOW(w, h, ks, flow_x, flow_y, NULL, NULL);
175 sum = darrayCreate(3, darrayGetDimensions(dst));
179 /* clear dst array with zeros, fill sum array with ones */
181 dst_ptr = darrayGetPr(dst);
182 for (i = 0; i < pixles; i++)
184 sum_ptr = darrayGetPr(sum);
185 for (i = 0; i < pixles; i++)
188 /* first copy all even planes */
189 for (z = 0; z < ks; z++) {
192 memcpy(darrayGetPr(dst) + (z/2)*w*h, darrayGetPr(src) + z*w*h, w*h*sizeof(double));
195 /* project all odd planes */
196 for (z = 0; z < ks; z++) {
199 /* project up via forward flow */
200 src_ptr = darrayGetPr(src) + z*w*h;
201 dst_ptr = darrayGetPr(dst) + (z/2)*w*h;
202 sum_ptr = darrayGetPr(sum) + (z/2)*w*h;
203 flow_x_ptr = darrayGetPr(flow_x) + (z-1)*w*h;
204 flow_y_ptr = darrayGetPr(flow_y) + (z-1)*w*h;
205 for (y = 0; y < h; y++) {
206 for (x = 0; x < w; x++) {
207 xx = x + *flow_x_ptr++;
208 yy = y + *flow_y_ptr++;
209 if (xx>=0 && yy>=0 && xx<w && yy<h) {
210 *dst_ptr += src_ptr[xx + yy*w];
219 /* average projected pixles */
221 dst_ptr = darrayGetPr(dst);
222 sum_ptr = darrayGetPr(sum);
223 for (i = 0; i < pixles; i++)
224 *dst_ptr++ /= *sum_ptr++;
228 darrayMove(dst, src);
241 /* Expand matrix by expanding z planes
243 * The array is expanded by inserting new planes in the following way:
244 * - Forward flow vectors are used to project previous src plane to inserted
245 * odd destination plane. The weight is A.
246 * - Also forward flow vectors are used to project next src plane to inserted
247 * odd destination plane. The weight is B.
248 * - The result is averaged.
249 * - First border plane is just copied. (weighted 1.0)
250 * - Last border plane is projected using forward flow vector. (weighted 1.0)
251 * - Forward flow vectors are used to project previous source plane to even
252 * destination plane. The weight is B.
253 * - the source plane is copied to even destination plane. The weight is A.
254 * - All pixles pixles on the new plane result from two planes. Due
255 * to optical flow, none or many pixles are summed. All pixles on the
256 * new plane are summed and then averaged. At locations where no pixle
257 * was projected, the result is 0.
259 * If the number of planes in the result array is odd, it is just copied.
261 * The array (src) is scaled to array (dst) as shown:
264 * dst[1] = src[0] * A + src[1] * B
265 * dst[2] = src[1] * A + src[0] * B
266 * dst[3] = src[1] * A + src[2] * B
267 * dst[4] = src[2] * A + src[1] * B
270 * The scaling shown in a different way:
272 * src plane 0 -------> dst plane 0
276 * \ dst forward flow plane 0
280 * / dst forward flow plane 1
286 * \ dst forward flow plane 0
287 * \ dst forward flow plane 1
289 * src plane 1 -*A-->(+) dst plane 2
293 * \ dst forward flow plane 2
297 * / dst forward flow plane 3
303 * \ dst forward flow plane 2
304 * \ dst forward flow plane 3
306 * src plane 2 -*A-->(+) dst plane 4
310 * \ dst forward flow plane 4
315 * if odd number of dst planes:
316 * src plane 3 -------> dst plane 6
321 static int expand_z(darray_t *src, const darray_t *dst, const darray_t *flow_x, const darray_t *flow_y)
323 int x, y, z, xx, yy, xxx, yyy, w, h, ks, kd, k_;
326 double *src1_ptr, *src2_ptr, *dst1_ptr, *dst2_ptr, *sum1_ptr, *sum2_ptr, *flow_x1_ptr, *flow_y1_ptr, *flow_x2_ptr, *flow_y2_ptr;
327 darray_t *sum = NULL;
328 double A = sqrt(2) / 2;
331 ASSERT(darrayGetNumberOfDimensions(src) == 3, "src array must have 3 dimensions");
332 ASSERT(darrayGetNumberOfDimensions(dst) == 3, "dst array must have 3 dimensions");
333 w = darrayGetDimensions(src)[0];
334 h = darrayGetDimensions(src)[1];
335 ks = darrayGetDimensions(src)[2];
336 kd = darrayGetDimensions(dst)[2];
337 ASSERT(w == darrayGetDimensions(dst)[0], "x-size of source and destination must be equal");
338 ASSERT(h == darrayGetDimensions(dst)[1], "y-size of source and destination must be equal");
339 ASSERT(ks == ((kd+1)>>1), "z-size of source must be half of the destination (+an extra plane if destination z-size is odd)");
340 ASSERT_FLOW(w, h, kd, flow_x, flow_y, NULL, NULL);
342 sum = darrayCreate(3, darrayGetDimensions(dst));
346 /* clear dst array with zeroes, keep sum with zeroes */
348 dst1_ptr = darrayGetPr(dst);
349 for (i = 0; i < pixles; i++)
353 k_ = kd&(~1); /* even number of planes */
355 /* copy first plane with weight 1.0 */
356 memcpy(darrayGetPr(dst) + z*w*h, darrayGetPr(src) + (z/2)*w*h, w*h*sizeof(double));
357 /* fill sum array with ones */
359 sum1_ptr = darrayGetPr(sum) + z*w*h;
360 for (i = 0; i < pixles; i++)
364 /* project planes in between */
365 for (z = 0; z < k_-2; z+=2) {
366 dst1_ptr = darrayGetPr(dst) + z*w*h;
367 dst2_ptr = dst1_ptr + w*h;
368 sum1_ptr = darrayGetPr(sum) + z*w*h;
369 sum2_ptr = sum1_ptr + w*h;
370 src1_ptr = darrayGetPr(src) + (z/2)*w*h;
371 src2_ptr = src1_ptr + w*h;
372 flow_x1_ptr = darrayGetPr(flow_x) + z*w*h;
373 flow_y1_ptr = darrayGetPr(flow_y) + z*w*h;
374 flow_x2_ptr = flow_x1_ptr + w*h;
375 flow_y2_ptr = flow_y1_ptr + w*h;
376 for (y = 0; y < h; y++) {
377 for (x = 0; x < w; x++) {
378 /* even plane (weight A) */
379 dst2_ptr[x + y*w] += src2_ptr[x + y*w] * A;
380 sum2_ptr[x + y*w] += A;
381 /* get position via firt plane */
386 if (xx<0 || yy<0 || xx>=w || yy>=h)
388 /* odd plane (weight A)*/
389 dst1_ptr[xx + yy*w] += src1_ptr[x + y*w] * A;
390 sum1_ptr[xx + yy*w] += A;
391 /* follow position via second plane */
392 _x += flow_x2_ptr[xx + yy*w];
393 _y += flow_y2_ptr[xx + yy*w];
396 if (xxx<0 || yyy<0 || xxx>=w || yyy>=h)
398 /* even plane (weight B) */
399 dst2_ptr[xxx + yyy*w] += src1_ptr[x + y*w] * B;
400 sum2_ptr[xxx + yyy*w] += B;
401 /* odd plane (weigth B) */
402 dst1_ptr[xx + yy*w] += src2_ptr[xxx + yyy*w] * B;
403 sum1_ptr[xx + yy*w] += B;
408 /* project last plane with weight 1.0 */
409 dst1_ptr = darrayGetPr(dst) + z*w*h;
410 sum1_ptr = darrayGetPr(sum) + z*w*h;
411 src1_ptr = darrayGetPr(src) + (z/2)*w*h;
412 flow_x1_ptr = darrayGetPr(flow_x) + z*w*h;
413 flow_y1_ptr = darrayGetPr(flow_y) + z*w*h;
414 for (y = 0; y < h; y++) {
415 for (x = 0; x < w; x++) {
416 /* get position via firt plane */
421 if (xx<0 || yy<0 || xx>=w || yy>=h)
423 /* border (odd) plane (weight 1.0)*/
424 dst1_ptr[xx + yy*w] += src1_ptr[x + y*w];
425 sum1_ptr[xx + yy*w] += 1.0;
431 /* copy extra plane, if destiantion size is odd */
433 memcpy(darrayGetPr(dst) + z*w*h, darrayGetPr(src) + (z/2)*w*h, w*h*sizeof(double));
434 /* fill sum array with ones */
436 sum1_ptr = darrayGetPr(sum) + z*w*h;
437 for (i = 0; i < pixles; i++)
441 /* average projected pixles */
443 dst1_ptr = darrayGetPr(dst);
444 sum1_ptr = darrayGetPr(sum);
445 for (i = 0; i < pixles; i++) {
446 /* only if there is a sum */
448 *dst1_ptr++ /= *sum1_ptr;
465 /* Shrink flow planes
467 * Each pair of flow planes is shrinked by combining (tracing) two planes
468 * in forward direction.
470 * If the number of flow planes is odd, the extra plane is removed.
472 static int shrink_flow_z(darray_t *src_x, darray_t *src_y, darray_t *dst_x, darray_t *dst_y)
474 int w, h, ks, kd, x, y, z, xx, yy;
476 double *src_x1_ptr, *src_x2_ptr, *src_y1_ptr, *src_y2_ptr, *dst_x_ptr, *dst_y_ptr;
477 int dst_x_move = 0, dst_y_move = 0;
479 ASSERT(darrayGetNumberOfDimensions(src_x) == 3, "src_x array must have 3 dimensions");
480 ASSERT(darrayGetNumberOfDimensions(src_y) == 3, "src_y array must have 3 dimensions");
481 w = darrayGetDimensions(src_x)[0];
482 h = darrayGetDimensions(src_x)[1];
483 ks = darrayGetDimensions(src_x)[2];
485 ASSERT(w == darrayGetDimensions(src_y)[0], "x-size must be equal");
486 ASSERT(h == darrayGetDimensions(src_y)[1], "y-size must be equal");
487 ASSERT(ks == darrayGetDimensions(src_y)[2], "z-size must be equal");
490 int dimensions[3] = {w, h, kd};
492 dst_x = darrayCreate(3, dimensions);
498 int dimensions[3] = {w, h, kd};
500 dst_y = darrayCreate(3, dimensions);
506 ASSERT(darrayGetNumberOfDimensions(dst_x) == 3, "flow_x array must have 3 dimensions");
507 ASSERT(darrayGetNumberOfDimensions(dst_y) == 3, "flow_y array must have 3 dimensions");
508 ASSERT(w == darrayGetDimensions(dst_x)[0], "x-size must be equal");
509 ASSERT(h == darrayGetDimensions(dst_x)[1], "y-size must be equal");
510 ASSERT(kd == darrayGetDimensions(dst_x)[2], "z-size of dest must be half of the planes + optional odd plane");
511 ASSERT(w == darrayGetDimensions(dst_y)[0], "x-size must be equal");
512 ASSERT(h == darrayGetDimensions(dst_y)[1], "y-size must be equal");
513 ASSERT(kd == darrayGetDimensions(dst_y)[2], "z-size of dest must be half of the planes + optional odd plane");
515 for (z = 0; z < kd; z++) {
516 src_x1_ptr = darrayGetPr(src_x) + (z*2)*w*h;
517 src_y1_ptr = darrayGetPr(src_y) + (z*2)*w*h;
518 dst_x_ptr = darrayGetPr(dst_x) + z*w*h;
519 dst_y_ptr = darrayGetPr(dst_y) + z*w*h;
520 src_x2_ptr = darrayGetPr(src_x) + (z*2+1)*w*h;
521 src_y2_ptr = darrayGetPr(src_y) + (z*2+1)*w*h;
522 for (y = 0; y < h; y++) {
523 for (x = 0; x < w; x++) {
524 /* get position via first plane */
529 if (xx<0 || yy<0 || xx>=w || yy>=h) {
530 /* use an outside value when outside in the first plane */
535 /* follow position via second plane */
536 _x += src_x2_ptr[xx + yy*w];
537 _y += src_y2_ptr[xx + yy*w];
538 /* store displacement result */
546 darrayMove(dst_x, src_x);
548 darrayMove(dst_y, src_y);
554 darrayDestroy(dst_x);
556 darrayDestroy(dst_y);
561 /* Shrink source matrix to half width and height and store into destinaction
564 * The destination matrix must be half in width and heit of the source matrix.
565 * The z-depth is not changed, so the destination matrix has same z-dimension.
567 * If a dimension of a source matrix is odd, the end of the dimension is just
568 * copied and not scaled.
570 * The points in a plane are shrinked from 2x2x2 to 1x1x1 by calculating the mean
571 * of all eight values.
573 static int shrink_xy(darray_t *src, darray_t *dst)
575 int x, xx, y, z, ws, wd, w_, hs, hd, h_, k;
579 ASSERT(darrayGetNumberOfDimensions(src) == 3, "Source array must have 3 dimensions");
580 ws = darrayGetDimensions(src)[0];
582 hs = darrayGetDimensions(src)[1];
584 k = darrayGetDimensions(src)[2];
586 /* create dst, if not given */
588 int dimensions[3] = {(ws+1)>>1, (hs+1)>>1, k};
590 dst = darrayCreate(3, dimensions);
596 ASSERT(darrayGetNumberOfDimensions(dst) == 3, "Destination array must have 3 dimensions");
597 wd = darrayGetDimensions(dst)[0];
598 hd = darrayGetDimensions(dst)[1];
599 ASSERT((ws&1) || ws == wd*2, "x-size of source must be twice the size of destination (this is even source size)");
600 ASSERT(!(ws&1) || ws-1 == (wd-1)*2, "x-size of source-1 must be twice the size of destination-1 (this odd source size)");
601 ASSERT((hs&1) || hs == hd*2, "y-size of source must be twice the size of destination (this is even source size)");
602 ASSERT(!(hs&1) || hs-1 == (hd-1)*2, "y-size of source-1 must be twice the size of destination-1 (this odd source size)");
603 ASSERT(k == darrayGetDimensions(dst)[2], "z-size must be equal");
605 for (z = 0; z < k; z++) {
606 for (y = 0; y < h_; y++) {
608 s1 = darrayGetPr(src) + y*2*ws + z*ws*hs;
610 d = darrayGetPr(dst) + y*wd + z*wd*hd;
611 for (x = 0, xx = 0; x < w_; x++, xx+=2)
612 d[x] = (s1[xx] + s1[xx+1] + s2[xx] + s2[xx+1]) * 0.25;
615 d[x] = (s1[xx] + s2[xx]) * 0.5;
619 s1 = darrayGetPr(src) + y*2*ws + z*ws*hs;
620 d = darrayGetPr(dst) + y*wd + z*wd*hd;
621 for (x = 0, xx = 0; x < w_; x++, xx+=2)
622 d[x] = (s1[xx] + s1[xx+1]) * 0.5;
630 darrayMove(dst, src);
641 /* Expand X and Y using a simple linear filter
643 * The array (src) is scaled to array (dst) as shown:
646 * dst[1] = src[0] * A + src[1] * B
647 * dst[2] = src[1] * A + src[0] * B
648 * dst[3] = src[1] * A + src[2] * B
649 * dst[4] = src[2] * A + src[1] * B
650 * dst[5] = src[2] * A + src[3] * B
651 * dst[6] = src[3] * A + src[2] * B
654 * Optional if the source grid has odd dimension:
658 * First the x-dimension is scaled, then the y-dimension is scaled
664 static void expand_xy(darray_t *src, const darray_t *dst)
666 int x, y, z, ws, wd, w_, hs, hd, h_, k;
667 double *s, *s1, *s2, *d, *d1, *d2;
668 double A = sqrt(2) / 2;
671 ASSERT(darrayGetNumberOfDimensions(dst) == 3, "nvalue array must have 3 dimensions");
672 ASSERT(darrayGetNumberOfDimensions(src) == 3, "value array must have 3 dimensions");
673 ws = darrayGetDimensions(src)[0];
674 wd = darrayGetDimensions(dst)[0];
676 hs = darrayGetDimensions(src)[1];
677 hd = darrayGetDimensions(dst)[1];
679 k = darrayGetDimensions(src)[2];
680 ASSERT((wd&1) || wd == ws*2, "x-size of destination must be twice the size of source (this is even destination size)");
681 ASSERT(!(wd&1) || wd-1 == (ws-1)*2, "x-size of destination-1 must be twice the size of source-1 (this odd destination size)");
682 ASSERT((hd&1) || hd == hs*2, "y-size of destination must be twice the size of source (this is even destination size)");
683 ASSERT(!(hd&1) || hd-1 == (hs-1)*2, "y-size of destination-1 must be twice the size of source-1 (this odd destination size)");
684 ASSERT(k == darrayGetDimensions(dst)[2], "z-size of source and destination must be equal");
686 /* Expand x-dimension
687 * src is scaled in x-direction and stored in dst. In y-
688 * direction it is stored in the upper half */
689 for (z = 0; z < k; z++) {
690 for (y = 0; y < hs; y++) {
691 s = darrayGetPr(src) + y*ws + z*ws*hs;
692 d = darrayGetPr(dst) + (y+h_)*wd + z*wd*hd;
693 *d++ = *s; /* x=0 plane */
694 for (x = 0; x < w_-1; x++) {
695 *d++ = A*s[0] + B*s[1];
696 *d++ = A*s[1] + B*s[0];
699 *d++ = *s++; /* x=w-1 plane */
700 /* extra plane (odd fine grid) */
706 /* Expand y-dimension
707 * upper half of dst is scaled in y-direction. */
708 for (z = 0; z < k; z++) {
710 s = darrayGetPr(dst) + h_*wd + z*wd*hd;
711 d = darrayGetPr(dst) + z*wd*hd;
712 for (x = 0; x < wd; x++)
713 *d++ = *s++; /* y=0 plane */
714 for (y = 0; y < h_-1; y++) {
715 s1 = darrayGetPr(dst) + (y+h_)*wd + z*wd*hd;
717 d1 = darrayGetPr(dst) + (y*2+1)*wd + z*wd*hd;
719 for (x = 0; x < wd; x++) {
720 *d1++ = A * *s1 + B * *s2;
721 *d2++ = A * *s2 + B * *s1;
726 /* y=h-1 plane and extra plane (already there) */
730 /* Quantize the binary information (for marked arrays)
732 * If an element is greater theshold, the element is set to gt, otherwise le.
734 static void quantize(const darray_t *array, double threshold, double gt, double le)
739 ASSERT(darrayGetNumberOfDimensions(array) == 3, "array must have 3 dimensions");
740 n *= darrayGetDimensions(array)[0];
741 n *= darrayGetDimensions(array)[1];
742 n *= darrayGetDimensions(array)[2];
743 ptr = darrayGetPr(array);
745 for (i = 0; i < n; i++, ptr++) {
746 if (*ptr > threshold)
753 /* multiply the array content with a value
755 static void multiply(const darray_t *array, double factor)
760 ASSERT(darrayGetNumberOfDimensions(array) == 3, "array must have 3 dimensions");
761 n *= darrayGetDimensions(array)[0];
762 n *= darrayGetDimensions(array)[1];
763 n *= darrayGetDimensions(array)[2];
764 ptr = darrayGetPr(array);
766 for (i = 0; i < n; i++, ptr++)
770 /* create an array of neighbors and use flow vectors
771 * flow_x and flow_x are the vectors that point to neighbors of the next z plane
772 * flow_x and flow_x are the vectors that point to neighbors of the previous z plane
774 static unsigned char *gen_neighbor(int w, int h, int k, const darray_t *flow_x, const darray_t *flow_y, const darray_t *flow_ix, const darray_t *flow_iy)
776 int x, y, z, xx, yy, zz, i, j, n;
779 double *flow_x_ptr, *flow_y_ptr, *flow_ix_ptr, *flow_iy_ptr;
780 unsigned char *neighbors, *ret_neighbors;
781 unsigned long nb_size;
785 ASSERT_FLOW(w, h, k, flow_x, flow_y, flow_ix, flow_iy);
786 flow_x_ptr = darrayGetPr(flow_x);
787 flow_y_ptr = darrayGetPr(flow_y);
788 flow_ix_ptr = darrayGetPr(flow_ix);
789 flow_iy_ptr = darrayGetPr(flow_iy);
791 nb_num = (k==1) ? NEIGHBORS_2D : NEIGHBORS_3D;
792 nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
793 ret_neighbors = neighbors = calloc(w*h*k, nb_size);
794 // printf("alloc neighbor grid=%lu Mbytes\n", nb_size*w*h*k/1024/1024);
795 if (!ret_neighbors) {
796 printf("failed to allocate neighbor grid\n");
800 for (z = 0; z < k; z++) {
801 for (y = 0; y < h; y++) {
802 for (x = 0; x < w; x++) {
804 i_index = ((struct neighbors_2d *)neighbors)->index;
806 i_index = ((struct neighbors_3d *)neighbors)->index;
807 for (i = 0, n = 0; i < nb_num; i++) {
808 /* xx, yy, zz is the neighbor of color source
809 * The first neighbor is always the point itself!
811 xx = x+neigh_off[i].x;
812 yy = y+neigh_off[i].y;
813 zz = z+neigh_off[i].z;
814 if (xx < 0 || yy < 0 || zz < 0)
816 if (xx >= w || yy >= h || zz >= k)
819 _x = flow_x_ptr[xx + yy*w + (zz-1)*w*h];
820 _y = flow_y_ptr[xx + yy*w + (zz-1)*w*h];
824 _x = flow_ix_ptr[xx + yy*w + zz*w*h];
825 _y = flow_iy_ptr[xx + yy*w + zz*w*h];
829 if (xx < 0 || yy < 0)
831 if (xx >= w || yy >= h)
833 index = xx + yy*w + zz*w*h;
834 /* eliminate double entries */
835 for (j = 0; j < n; j++) {
836 if (i_index[j] == index)
841 i_index[n++] = index;
844 ((struct neighbors_2d *)neighbors)->num = n;
846 ((struct neighbors_3d *)neighbors)->num = n;
847 neighbors += nb_size;
852 return ret_neighbors;
855 /* weighten neighbors */
856 static void weighten(const darray_t *luminance, unsigned char *neighbors)
858 int x, y, z, i, w, h, k, num;
859 double val, nval, mean, variance, sigma, sum, weight, min;
860 double sqdiff[NEIGHBORS_3D];
861 double log0_01 = log(0.01);
863 unsigned long nb_size;
864 int *i_index; double *w_index;
866 ASSERT(darrayGetNumberOfDimensions(luminance) == 3, "luminance array must have 3 dimensions");
867 w = darrayGetDimensions(luminance)[0];
868 h = darrayGetDimensions(luminance)[1];
869 k = darrayGetDimensions(luminance)[2];
870 lum_ptr = darrayGetPr(luminance);
872 nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
874 for (z = 0; z < k; z++) {
875 for (y = 0; y < h; y++) {
876 for (x = 0; x < w; x++, neighbors += nb_size) {
878 num = ((struct neighbors_2d *)neighbors)->num;
879 i_index = ((struct neighbors_2d *)neighbors)->index;
880 w_index = ((struct neighbors_2d *)neighbors)->weight;
882 num = ((struct neighbors_3d *)neighbors)->num;
883 i_index = ((struct neighbors_3d *)neighbors)->index;
884 w_index = ((struct neighbors_3d *)neighbors)->weight;
886 /* Be sure that we have at least 3 neighbors.
887 * This applies for every corner in a plane.
888 * The first point in the neighbor list iss the point itself.
890 ASSERT(num > 3, "Every point must have at least 3 neighbors");
891 /* value of current pixle */
892 val = lum_ptr[i_index[0]];
895 for (i = 0; i < num; i++) {
896 /* value of neighbor pixles, including current pixle */
897 nval = lum_ptr[i_index[i]];
898 /* squared diffs between current pixle and each neighbor */
899 sqdiff[i] = (nval-val) * (nval-val);
901 variance += nval * nval;
909 variance -= mean * mean;
911 sigma = variance * 0.6;
913 for (i = 2; i < num; i++) {
917 if (sigma < -min / log0_01)
918 sigma = -min / log0_01;
919 if (sigma < 0.000002)
923 for (i = 0; i < num; i++) {
924 sum += exp(-sqdiff[i]/sigma);
926 /* each weight (divided by sum) */
927 for (i = 0; i < num; i++) {
928 weight = exp(-sqdiff[i]/sigma) / sum;
929 /* substract 1, if point is the point, not neighbor */
939 /* Smooth the value array
941 * If a pixle is marked (0 in mark array), the value at level 0 is taken from
942 * the init array (color of marked pixle). At other level the color is not
945 * If a pixle is not marked, the value is calculated as below.
947 static void smooth(int level, darray_t *value, const darray_t *mark, const darray_t *init, unsigned char *neighbors)
949 int x, y, z, w, h, k, i, num;
950 double *value_ptr, *value_line_ptr, *mark_line_ptr, *init_line_ptr;
952 unsigned long nb_size;
953 int *i_index; double *w_index;
955 ASSERT(darrayGetNumberOfDimensions(value) == 3, "value array must have 3 dimensions");
956 ASSERT(darrayGetNumberOfDimensions(mark) == 3, "mark array must have 3 dimensions");
957 ASSERT(darrayGetNumberOfDimensions(init) == 3, "init array must have 3 dimensions");
958 w = darrayGetDimensions(value)[0];
959 h = darrayGetDimensions(value)[1];
960 k = darrayGetDimensions(value)[2];
961 ASSERT(w == darrayGetDimensions(mark)[0], "x-sizes of mark array is different");
962 ASSERT(h == darrayGetDimensions(mark)[1], "y-sizes of mark array is different");
963 ASSERT(k == darrayGetDimensions(mark)[2], "z-sizes of mark array is different");
964 value_ptr = darrayGetPr(value);
966 nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
968 for (z = 0; z < k; z++) {
969 for (y = 0; y < h; y++) {
970 value_line_ptr = darrayGetPr(value) + y*w + z*w*h;
971 mark_line_ptr = darrayGetPr(mark) + y*w + z*w*h;
972 init_line_ptr = darrayGetPr(init) + y*w + z*w*h;
973 for (x = 0; x < w; x++, neighbors += nb_size) {
975 num = ((struct neighbors_2d *)neighbors)->num;
976 i_index = ((struct neighbors_2d *)neighbors)->index;
977 w_index = ((struct neighbors_2d *)neighbors)->weight;
979 num = ((struct neighbors_3d *)neighbors)->num;
980 i_index = ((struct neighbors_3d *)neighbors)->index;
981 w_index = ((struct neighbors_3d *)neighbors)->weight;
983 /* if pixle is marked */
984 if (mark_line_ptr[x] < 0.5) {
985 /* always use initial color on marked plane, otherwise do not smooth */
987 value_line_ptr[x] = init_line_ptr[x];
990 /* Calculate value */
992 for (i = 1; i < num; i++) /* sum value without point itself */
993 val += w_index[i] * value_ptr[i_index[i]];
995 value_line_ptr[x] = (init_line_ptr[x] - val) / w_index[0];
997 value_line_ptr[x] = (-val) / w_index[0];
1003 /* Calculate residual
1005 static double residual(int level, darray_t *value, const darray_t *mark, const darray_t *init, unsigned char *neighbors)
1007 int x, y, z, w, h, k, i, num;
1008 double *value_ptr, *mark_line_ptr, *init_line_ptr;
1009 double val, residual = 0;
1010 unsigned long nb_size;
1011 int *i_index; double *w_index;
1013 ASSERT(darrayGetNumberOfDimensions(value) == 3, "value array must have 3 dimensions");
1014 ASSERT(darrayGetNumberOfDimensions(mark) == 3, "mark array must have 3 dimensions");
1015 ASSERT(darrayGetNumberOfDimensions(init) == 3, "init array must have 3 dimensions");
1016 w = darrayGetDimensions(value)[0];
1017 h = darrayGetDimensions(value)[1];
1018 k = darrayGetDimensions(value)[2];
1019 ASSERT(w == darrayGetDimensions(mark)[0], "x-sizes of mark array is different");
1020 ASSERT(h == darrayGetDimensions(mark)[1], "y-sizes of mark array is different");
1021 ASSERT(k == darrayGetDimensions(mark)[2], "z-sizes of mark array is different");
1022 value_ptr = darrayGetPr(value);
1024 nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
1026 for (z = 0; z < k; z++) {
1027 for (y = 0; y < h; y++) {
1028 init_line_ptr = darrayGetPr(init) + y*w + z*w*h;
1029 mark_line_ptr = darrayGetPr(mark) + y*w + z*w*h;
1030 for (x = 0; x < w; x++, neighbors += nb_size) {
1032 num = ((struct neighbors_2d *)neighbors)->num;
1033 i_index = ((struct neighbors_2d *)neighbors)->index;
1034 w_index = ((struct neighbors_2d *)neighbors)->weight;
1036 num = ((struct neighbors_3d *)neighbors)->num;
1037 i_index = ((struct neighbors_3d *)neighbors)->index;
1038 w_index = ((struct neighbors_3d *)neighbors)->weight;
1040 /* if pixle is marked, no residual */
1041 if (mark_line_ptr[x] < 0.5)
1043 /* Calculate value */
1045 for (i = 0; i < num; i++) /* sum value including point itself */
1046 val += w_index[i] * value_ptr[i_index[i]];
1048 val = init_line_ptr[x] - val;
1051 residual += val * val;
1061 * Given are arrays for value and value of next level.
1063 * If value and next value have not only different width/height, but also
1064 * different depth (z dimension), a temporary array (temp) is used to
1065 * perform the intermediate step of scaling x,y,z.
1067 * Note that the flow vectors must be scaled xy already!
1069 static int restrict(const darray_t *value, darray_t *nvalue, const darray_t *flow_x, const darray_t *flow_y)
1072 darray_t *temp = NULL;
1075 ASSERT(darrayGetNumberOfDimensions(value) == 3, "Source array must have 3 dimensions");
1076 ASSERT(darrayGetNumberOfDimensions(nvalue) == 3, "Destination array must have 3 dimensions");
1077 wd = darrayGetDimensions(nvalue)[0];
1078 hd = darrayGetDimensions(nvalue)[1];
1079 kd = darrayGetDimensions(nvalue)[2];
1080 ks = darrayGetDimensions(value)[2];
1082 ASSERT(flow_x && flow_y, "when scaling z, flow vectors must be given");
1085 int dimensions[3] = {wd, hd, ks};
1087 /* Cube that is only shrinked in x and y */
1088 temp = darrayCreate(3, dimensions);
1092 rc = shrink_xy((darray_t *)value, temp);
1095 rc = shrink_z(temp, nvalue, flow_x, flow_y);
1099 rc = shrink_xy((darray_t *)value, nvalue);
1107 darrayDestroy(temp);
1114 * Given are arrays for value and value of next level.
1116 * If value and next value have not only different width/height, but also
1117 * different depth (z dimension), a temporary array (temp3) is used to
1118 * perform the intermediate step of scaling x,y,z.
1120 * Note that the flow vectors must be scaled xy already!
1122 * First the value is shrinked to the size of the value of the next level.
1123 * The error is calculated by substracting the values of the next level
1124 * from the value. The error is then expanded. The expanded error is
1125 * substracted from the value. So the changes in the next level's value are
1126 * prolonged to the value.
1128 static int prolong(darray_t *value, const darray_t *nvalue, const darray_t *flow_x, const darray_t *flow_y)
1130 int ws, hs, ks, wd, hd, kd;
1132 darray_t *temp1 = NULL, *temp2 = NULL, *temp3 = NULL;
1133 double *value_ptr, *nvalue_ptr, *temp1_ptr, *temp2_ptr;
1136 ASSERT(darrayGetNumberOfDimensions(value) == 3, "nvalue array must have 3 dimensions");
1137 ASSERT(darrayGetNumberOfDimensions(nvalue) == 3, "value array must have 3 dimensions");
1138 ws = darrayGetDimensions(nvalue)[0];
1139 hs = darrayGetDimensions(nvalue)[1];
1140 ks = darrayGetDimensions(nvalue)[2];
1141 wd = darrayGetDimensions(value)[0];
1142 hd = darrayGetDimensions(value)[1];
1143 kd = darrayGetDimensions(value)[2];
1145 ASSERT(flow_x && flow_y, "when scaling z, flow vectors must be given");
1147 /* generate temporary arrays */
1148 temp1 = darrayCreate(3, darrayGetDimensions(value));
1151 temp2 = darrayCreate(3, darrayGetDimensions(nvalue));
1155 int dimensions[3] = {ws, hs, kd};
1157 /* Cube that is only shrinked in x and y */
1158 temp3 = darrayCreate(3, dimensions);
1163 /* temp2 = shrink(value) */
1165 rc = shrink_xy(value, temp3);
1168 rc = shrink_z(temp3, temp2, flow_x, flow_y);
1172 rc = shrink_xy(value, temp2);
1177 /* temp2 -= nvalue */
1178 temp2_ptr = darrayGetPr(temp2);
1179 nvalue_ptr = darrayGetPr(nvalue);
1181 for (i = 0; i < pixles; i++)
1182 *temp2_ptr++ -= *nvalue_ptr++;
1184 /* Expand (temp2 -> temp1) */
1186 rc = expand_z(temp2, temp3, flow_x, flow_y);
1189 expand_xy(temp3, temp1);
1191 expand_xy(temp2, temp1);
1193 /* value -= temp1 */
1194 temp1_ptr = darrayGetPr(temp1);
1195 value_ptr = darrayGetPr(value);
1197 for (i = 0; i < pixles; i++)
1198 *value_ptr++ -= *temp1_ptr++;
1203 /* destroy arrays */
1204 darrayDestroy(temp1);
1205 darrayDestroy(temp2);
1206 darrayDestroy(temp3);
1211 /* Paste one array into anothter */
1212 void paste(const darray_t *src, darray_t *dst, int xoff, int yoff, int zoff)
1214 int ws, hs, ks, wd, hd, /*kd,*/ x, y, z;
1215 double *src_ptr, *dst_ptr;
1217 ws = darrayGetDimensions(src)[0];
1218 hs = darrayGetDimensions(src)[1];
1219 ks = darrayGetDimensions(src)[2];
1220 wd = darrayGetDimensions(dst)[0];
1221 hd = darrayGetDimensions(dst)[1];
1222 // kd = darrayGetDimensions(dst)[2];
1223 src_ptr = darrayGetPr(src);
1224 dst_ptr = darrayGetPr(dst);
1226 for (z = 0; z < ks; z++) {
1227 for (y = 0; y < hs; y++) {
1228 for (x = 0; x < ws; x++) {
1229 dst_ptr[(x+xoff) + (y+yoff)*wd + (z+zoff)*wd*hd] = src_ptr[x + y*ws + z*ws*hs];
1235 inline void draw_line(double *ptr, int w, int h, int x0, int y0, int x1, int y1, double color)
1237 int dx, dy, sx, sy, err, e2;
1251 if (x0 > 0 && x0 < w && y0 > 0 && y0 < h)
1252 ptr[x0 + y0*w] = color;
1253 if (x0 == x1 && y0 == y1)
1267 /* Draw motion flow vectors into dst
1269 * The forward vectors are drawn white, the inverse vectors black.
1271 * The flow vectors are drawn to the upper left corner of the dst, which
1272 * may be larger in size than the flow arrays.
1274 void draw_flow(darray_t *dst, const darray_t *flow_x, const darray_t *flow_y, const darray_t *flow_ix, const darray_t *flow_iy)
1276 int wd, hd, ws, hs, ks, x, y, z;
1277 double *flow_x_ptr, *flow_y_ptr, *flow_ix_ptr, *flow_iy_ptr;
1280 wd = darrayGetDimensions(dst)[0];
1281 hd = darrayGetDimensions(dst)[1];
1282 ws = darrayGetDimensions(flow_x)[0];
1283 hs = darrayGetDimensions(flow_x)[1];
1284 ks = darrayGetDimensions(flow_x)[2];
1285 flow_x_ptr = darrayGetPr(flow_x);
1286 flow_y_ptr = darrayGetPr(flow_y);
1287 flow_ix_ptr = darrayGetPr(flow_ix);
1288 flow_iy_ptr = darrayGetPr(flow_iy);
1290 for (z = 0; z <= ks; z++) {
1291 for (y = step/2; y < hs-step/2+1; y+=step) {
1292 for (x = step/2; x < ws-step/2+1; x+=step) {
1295 draw_line(darrayGetPr(dst) + z*wd*hd, wd, hd, x, y, x+round(flow_x_ptr[x + y*ws + z*ws*hs]), y+(int)(flow_y_ptr[x + y*ws + z*ws*hs]+0.5), 1.0);
1298 draw_line(darrayGetPr(dst) + z*wd*hd, wd, hd, x, y, x+round(flow_ix_ptr[x + y*ws + (z-1)*ws*hs]), y+(int)(flow_iy_ptr[x + y*ws + (z-1)*ws*hs]+0.5), 0.0);
1306 * Note that the flow vectors must be scaled xy already!
1308 static int solve_mg(int nlevel, int iters, int ncycle, darray_t **values, darray_t **marks, const darray_t *init, unsigned char **nb_list, darray_t **flows_xy_x, darray_t **flows_xy_y, int scalexyz)
1310 double curr_residual, prev_residual = 10000000000000.0;
1311 int cycle, level, i;
1314 for (cycle = 0; cycle < ncycle; cycle++) {
1317 for (level = 0; level < nlevel-1; level++) {
1318 for (i = 0; i < iters; i++)
1319 smooth(level, values[level], marks[level], init, nb_list[level]);
1320 curr_residual += residual(level, values[level], marks[level], init, nb_list[level]);
1321 if (level < scalexyz)
1322 rc = restrict(values[level], values[level+1], flows_xy_x[level], flows_xy_y[level]);
1324 rc = restrict(values[level], values[level+1], NULL, NULL);
1329 /* end of going donw */
1330 for (i = 0; i < iters*5; i++)
1331 smooth(nlevel-1, values[nlevel-1], marks[nlevel-1], init, nb_list[nlevel-1]);
1334 for (level = nlevel-2; level >= 0; level--) {
1335 if (level < scalexyz)
1336 rc = prolong(values[level], values[level+1], flows_xy_x[level], flows_xy_y[level]);
1338 rc = prolong(values[level], values[level+1], NULL, NULL);
1341 for (i = 0; i < iters; i++)
1342 smooth(level, values[level], marks[level], init, nb_list[level]);
1345 /* end if residual raises again */
1346 // if (prev_residual < curr_residual)
1348 curr_residual = prev_residual;
1357 /* colorize image array using image_mark
1360 * first dimansion = width
1361 * second dimension = height
1362 * thrid dimension = components (first component is luminance, other components are features, like u, v)
1363 * fourth dimension = time
1366 * first dimansion = width
1367 * second dimension = height
1368 * fourth dimension = time
1370 darray_t *colorize(const darray_t *image, const darray_t *image_mark, const darray_t *flow_x, const darray_t *flow_y, const darray_t *flow_ix, const darray_t *flow_iy, int inner_iter, int outer_iter, int scalexyz)
1372 unsigned char **nb_list = NULL;
1373 darray_t **values = NULL, **marks = NULL, *init = NULL, **flows_x = NULL, **flows_y = NULL, **flows_ix = NULL, **flows_iy = NULL, **flows_xy_x = NULL, **flows_xy_y = NULL;
1374 darray_t *result = NULL, *luminance = NULL;
1376 int w, h, k, ww, hh, kk, last_kk, comp, d, max_depth, temp, z, c;
1379 ASSERT(darrayGetNumberOfDimensions(image) == 4, "image array must have 4 dimensions");
1380 w = darrayGetDimensions(image)[0];
1381 h = darrayGetDimensions(image)[1];
1382 comp = darrayGetDimensions(image)[2];
1383 k = darrayGetDimensions(image)[3];
1384 ASSERT(comp > 0, "image array requires at least one component (Y-component)");
1386 ASSERT(darrayGetNumberOfDimensions(image_mark) == 3, "image_mark array must have 3 dimensions");
1387 ASSERT(w == darrayGetDimensions(image_mark)[0], "image_mark and image must both have same x-size");
1388 ASSERT(h == darrayGetDimensions(image_mark)[1], "image_mark and image must both have same y-size");
1389 ASSERT(k == darrayGetDimensions(image_mark)[2], "image_mark and image must both have same z-size");
1391 /* Calculate maximum depth
1392 * Scale down dimensions until at least 2x2 remains
1395 for (max_depth = 0; temp > 2; max_depth++)
1397 ASSERT(max_depth >= 2, "image too small");
1399 nb_list = calloc(max_depth, sizeof(struct neighbors *));
1402 marks = calloc(max_depth, sizeof(darray_t *));
1405 ASSERT(marks, "no memory");
1406 values = calloc(max_depth, sizeof(darray_t *));
1409 ASSERT(values, "no memory");
1410 flows_x = calloc(max_depth, sizeof(darray_t *));
1413 ASSERT(flows_x, "no memory");
1414 flows_y = calloc(max_depth, sizeof(darray_t *));
1417 ASSERT(flows_y, "no memory");
1418 flows_ix = calloc(max_depth, sizeof(darray_t *));
1421 ASSERT(flows_ix, "no memory");
1422 flows_iy = calloc(max_depth, sizeof(darray_t *));
1425 ASSERT(flows_iy, "no memory");
1427 /* the flows_xy are scaled in xy in the current level */
1428 flows_xy_x = calloc(max_depth, sizeof(darray_t *));
1431 flows_xy_y = calloc(max_depth, sizeof(darray_t *));
1438 luminance = darrayCreate(3, dimensions);
1441 /* generate sparse multigrid */
1443 printf("-> prepare sparse grid");
1444 for (d = 0, ww=w, hh=h; d < max_depth; d++, ww=(ww+1)>>1, hh=(hh+1)>>1) {
1445 /* create temporary arrays
1446 * copy fist array to level 0 or shrink previous level
1448 printf(" #%d(w=%d h=%d k=%d)", d, ww, hh, kk); fflush(stdout);
1451 dimensions[2] = last_kk;
1452 marks[d] = darrayCreate(3, dimensions);
1457 dimensions[2] = last_kk-1;
1458 flows_x[d] = darrayCreate(3, dimensions);
1461 flows_y[d] = darrayCreate(3, dimensions);
1464 flows_ix[d] = darrayCreate(3, dimensions);
1467 flows_iy[d] = darrayCreate(3, dimensions);
1471 dimensions[0] = (ww+1)>>1;
1472 dimensions[1] = (hh+1)>>1;
1473 dimensions[2] = kk-1;
1474 flows_xy_x[d] = darrayCreate(3, dimensions);
1477 flows_xy_y[d] = darrayCreate(3, dimensions);
1482 for (z = 0; z < kk; z++)
1483 memcpy(darrayGetPr(luminance) + z*w*h, darrayGetPr(image) + z*w*h*comp, w*h*sizeof(double));
1484 if (flow_x && flow_y && flow_ix && flow_iy) {
1485 memcpy(darrayGetPr(flows_x[d]), darrayGetPr(flow_x), w*h*(kk-1)*sizeof(double));
1486 memcpy(darrayGetPr(flows_y[d]), darrayGetPr(flow_y), w*h*(kk-1)*sizeof(double));
1487 memcpy(darrayGetPr(flows_ix[d]), darrayGetPr(flow_ix), w*h*(kk-1)*sizeof(double));
1488 memcpy(darrayGetPr(flows_iy[d]), darrayGetPr(flow_iy), w*h*(kk-1)*sizeof(double));
1490 memcpy(darrayGetPr(marks[d]), darrayGetPr(image_mark), w*h*kk*sizeof(double));
1491 /* invert, so 0 = marked */
1492 quantize(marks[d], 0.5, 0, 1);
1494 rc = shrink_xy(luminance, NULL);
1497 rc = shrink_xy(marks[d-1], marks[d]);
1500 rc = shrink_xy(flows_x[d-1], flows_x[d]);
1503 rc = shrink_xy(flows_y[d-1], flows_y[d]);
1506 rc = shrink_xy(flows_ix[d-1], flows_ix[d]);
1509 rc = shrink_xy(flows_iy[d-1], flows_iy[d]);
1512 /* shrink length of flow vector on smaller grid.
1513 * This is not performed when comparing with
1514 * the original algorithm. (it is a bug there)
1516 multiply(flows_x[d], 0.5);
1517 multiply(flows_y[d], 0.5);
1518 multiply(flows_ix[d], 0.5);
1519 multiply(flows_iy[d], 0.5);
1520 if (d-1 < scalexyz) { /* process if previous d shall be shrinked in z direction */
1522 rc = shrink_z(luminance, NULL, flows_x[d], flows_y[d]);
1525 rc = shrink_z(marks[d], NULL, flows_x[d], flows_y[d]);
1528 rc = shrink_flow_z(flows_x[d], flows_y[d], NULL, NULL);
1531 rc = shrink_flow_z(flows_ix[d], flows_iy[d], NULL, NULL);
1535 /* If any of the restricted pixles is 0 (marked),
1536 * the result must be 0 (marked) too.
1538 quantize(marks[d], 0.9999, 1, 0);
1541 /* create x and y shrinked flow vectors for restriction and prolonging process */
1542 rc = shrink_xy(flows_x[d], flows_xy_x[d]);
1545 rc = shrink_xy(flows_y[d], flows_xy_y[d]);
1548 multiply(flows_xy_x[d], 0.5);
1549 multiply(flows_xy_y[d], 0.5);
1552 /* generate values array */
1556 values[d] = darrayCreate(3, dimensions);
1560 /* generate array of neighbors */
1561 #ifndef TEST_NO_RENDER
1562 nb_list[d] = gen_neighbor(ww, hh, kk, flows_x[d], flows_y[d], flows_ix[d], flows_iy[d]);
1566 weighten(luminance, nb_list[d]);
1573 darrayDestroy(luminance);
1580 init = darrayCreate(3, dimensions);
1584 /* result array for all components */
1587 dimensions[2] = comp;
1589 result = darrayCreate(4, dimensions);
1597 luminance = darrayCreate(3, dimensions);
1598 for (z = 0; z < k; z++) {
1599 memcpy(darrayGetPr(luminance) + z*w*h, darrayGetPr(image) + z*w*h*comp, w*h*sizeof(double));
1600 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(image) + z*w*h*comp, w*h*sizeof(double));
1602 draw_flow(values[0], flows_x[0], flows_y[0], flows_ix[0], flows_iy[0]);
1605 paste(marks[0], values[0], 0, 0, 0);
1609 for (d = 1; d < max_depth; d++) {
1610 rc = shrink_xy(luminance, NULL);
1614 shrink_z(luminance, NULL, flows_xy_x[d-1], flows_xy_y[d-1]);
1615 paste(luminance, values[0], 0, 0, 0);
1617 draw_flow(values[0], flows_x[d], flows_y[d], flows_ix[d], flows_iy[d]);
1620 paste(marks[d], values[0], 0, 0, 0);
1623 darrayDestroy(luminance);
1625 /* copy test pyramid image as Y-component */
1626 for (z = 0; z < k; z++)
1627 memcpy(darrayGetPr(result) + z*w*h*comp, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1629 /* copy Y-component */
1630 for (z = 0; z < k; z++)
1631 memcpy(darrayGetPr(result) + z*w*h*comp, darrayGetPr(image) + z*w*h*comp, w*h*sizeof(double));
1634 printf("-> apply component to grid and solve");
1635 for (c = 1; c < comp; c++) {
1637 double *value_ptr, *init_ptr, *mark_ptr;
1639 printf(" #%d", c); fflush(stdout);
1641 * - copy component into value array (level 0), otherwise 0
1642 * - use maked colors for init array, otherwise use 0
1644 for (z = 0; z < k; z++)
1645 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(image) + c*w*h + z*w*h*comp, w*h*sizeof(double));
1646 for (d = 1, ww=(w+1)>>1, hh=(h+1)>>1, kk=k; d < max_depth; d++, ww=(ww+1)>>1, hh=(hh+1)>>1) {
1647 if (d-1 < scalexyz) /* scale kk, if last array was scaled */
1649 value_ptr = darrayGetPr(values[d]);
1651 for (j = 0; j < pixles; j++)
1654 value_ptr = darrayGetPr(values[0]);
1655 init_ptr = darrayGetPr(init);
1656 mark_ptr = darrayGetPr(image_mark);
1658 for (j = 0; j < pixles; j++) {
1659 if (*mark_ptr++ > 0.5)
1660 *init_ptr++ = *value_ptr;
1666 #ifndef TEST_NO_RENDER
1667 /* colorize component */
1669 for (i = 0; i < outer_iter; i++) {
1670 rc = solve_mg(max_depth, inner_iter, 2, values, marks, init, nb_list, flows_xy_x, flows_xy_y, scalexyz);
1673 rc = solve_mg((max_depth+1) / 2, inner_iter, 2, values, marks, init, nb_list, flows_xy_x, flows_xy_y, scalexyz);
1676 rc = solve_mg(2, inner_iter, 2, values, marks, init, nb_list, flows_xy_x, flows_xy_y, scalexyz);
1679 rc = solve_mg(1, inner_iter, 4, values, marks, init, nb_list, flows_xy_x, flows_xy_y, scalexyz);
1686 for (d = 1; d < max_depth; d++)
1687 paste(values[d], values[0], 0, 0, 0);
1690 /* apply colorized component */
1691 for (z = 0; z < k; z++)
1692 memcpy(darrayGetPr(result) + z*w*h*comp + c*w*h, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1696 #ifdef TEST_SHRINK_XY
1697 for (c = 0; c < comp; c++) {
1699 int dimensions[3] = {w, h, k};
1700 for (z = 0; z < k; z++)
1701 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(result) + z*w*h*comp + c*w*h, w*h*sizeof(double));
1702 dimensions[0] = (w+1)>>1;
1703 dimensions[1] = (h+1)>>1;
1704 temp = darrayCreate(3, dimensions);
1705 ASSERT(temp, "no memory");
1706 rc = shrink_xy(values[0], temp);
1707 ASSERT(rc >= 0, "no memory");
1708 paste(temp, values[0], 0, 0, 0);
1709 darrayDestroy(temp);
1710 for (z = 0; z < k; z++)
1711 memcpy(darrayGetPr(result) + z*w*h*comp + c*w*h, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1715 #ifdef TEST_SHRINK_Z
1716 for (c = 0; c < comp; c++) {
1718 int dimensions[3] = {w, h, k};
1719 for (z = 0; z < k; z++)
1720 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(result) + z*w*h*comp + c*w*h, w*h*sizeof(double));
1721 dimensions[2] = (k+1)>>1;
1722 temp = darrayCreate(3, dimensions);
1723 ASSERT(temp, "no memory");
1724 rc = shrink_z(values[0], temp, flows_x[0], flows_y[0]);
1725 ASSERT(rc >= 0, "no memory");
1726 paste(temp, values[0], 0, 0, 0);
1727 darrayDestroy(temp);
1728 for (z = 0; z < k; z++)
1729 memcpy(darrayGetPr(result) + z*w*h*comp + c*w*h, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1733 #ifdef TEST_EXPAND_XY
1734 for (c = 0; c < comp; c++) {
1736 int dimensions[3] = {w, h, k};
1737 for (z = 0; z < k; z++)
1738 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(result) + z*w*h*comp + c*w*h, w*h*sizeof(double));
1739 dimensions[0] = (w+1)>>1;
1740 dimensions[1] = (h+1)>>1;
1741 temp = darrayCreate(3, dimensions);
1742 ASSERT(temp, "no memory");
1743 rc = shrink_xy(values[0], temp);
1744 ASSERT(rc >= 0, "no memory");
1745 expand_xy(temp, values[0]);
1746 darrayDestroy(temp);
1747 for (z = 0; z < k; z++)
1748 memcpy(darrayGetPr(result) + z*w*h*comp + c*w*h, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1752 #ifdef TEST_EXPAND_Z
1753 for (c = 0; c < comp; c++) {
1755 int dimensions[3] = {w, h, k};
1756 for (z = 0; z < k; z++)
1757 memcpy(darrayGetPr(values[0]) + z*w*h, darrayGetPr(result) + z*w*h*comp + c*w*h, w*h*sizeof(double));
1758 dimensions[2] = (k+1)>>1;
1759 temp = darrayCreate(3, dimensions);
1760 ASSERT(temp, "no memory");
1761 rc = shrink_z(values[0], temp, flows_x[0], flows_y[0]);
1762 ASSERT(rc >= 0, "no memory");
1763 rc = expand_z(temp, values[0], flows_x[0], flows_y[0]);
1764 ASSERT(rc >= 0, "no memory");
1765 darrayDestroy(temp);
1766 for (z = 0; z < k; z++)
1767 memcpy(darrayGetPr(result) + z*w*h*comp + c*w*h, darrayGetPr(values[0]) + z*w*h, w*h*sizeof(double));
1775 for (d = 0; d < max_depth; d++) {
1779 darrayDestroy(marks[d]);
1781 darrayDestroy(values[d]);
1783 darrayDestroy(flows_xy_x[d]);
1785 darrayDestroy(flows_xy_y[d]);
1787 darrayDestroy(flows_x[d]);
1789 darrayDestroy(flows_y[d]);
1791 darrayDestroy(flows_ix[d]);
1793 darrayDestroy(flows_iy[d]);
1804 darrayDestroy(init);
1805 darrayDestroy(luminance);
1807 darrayDestroy(result);
1809 return (rc < 0) ? NULL : result;