Stop if residual is 0
[colorize.git] / lib / multigrid.c
index 1687d07..a2409c8 100644 (file)
@@ -6,8 +6,8 @@
 #include "multigrid.h"
 
 /* if defined, residual is calculated and loop is aborted, if no improvement
- * is reached. this does not seem to work, so it should be undefined */
-//#define RESIDUAL
+ * is reached or the target resudual change is reached. */
+#define RESIDUAL
 
 /* just process, but do not generate neighbor list and do not solve multigrid */
 //#define TEST_NO_RENDER
@@ -58,17 +58,6 @@ void ASSERT_FLOW(int w, int h, int k, const darray_t *flow, const darray_t *flow
 #define NEIGHBORS_2D 9
 #define NEIGHBORS_3D 27
 
-struct neighbors_2d {
-       int num;                        /* # of neighbors */
-       int index[NEIGHBORS_2D];        /* index of neighbors in an array */
-       double weight[NEIGHBORS_2D];    /* calculated weight of neighbors */
-};
-struct neighbors_3d {
-       int num;                        /* # of neighbors */
-       int index[NEIGHBORS_3D];        /* index of neighbors in an array */
-       double weight[NEIGHBORS_3D];    /* calculated weight of neighbors */
-};
-
 static struct neigh_off {
        int x, y, z;
 } neigh_off[NEIGHBORS_3D] = {
@@ -827,6 +816,16 @@ void multiply(const darray_t *array, double factor)
 }
 
 /* create an array of neighbors and use flow vectors
+ *
+ * the elements of the array consist of:
+ *  int num
+ *  int index[neighbors]
+ *  double weight[neighbors]
+ * num specifies the number of neighbors used.
+ * neighbors is fixed for all entries in the array and depends on 2d or 3d
+ * image. since the number of neighbors depends on the dimensions of an image,
+ * they are not fixed. a structure cannot be used in this case.
+ *
  * flow_x and flow_x are the vectors that point to neighbors of the next z plane
  * flow_x and flow_x are the vectors that point to neighbors of the previous z plane
  */
@@ -837,8 +836,8 @@ unsigned char *gen_neighbor(int w, int h, int k, const darray_t *flow, const dar
        int index;
        double *flow_x_ptr, *flow_y_ptr, *flow_ix_ptr, *flow_iy_ptr;
        unsigned char *neighbors, *ret_neighbors;
+       int nb_num, index_offset;
        unsigned long nb_size;
-       int nb_num;
        int *i_index;
 
        ASSERT_FLOW(w, h, k, flow, flow_i);
@@ -848,21 +847,19 @@ unsigned char *gen_neighbor(int w, int h, int k, const darray_t *flow, const dar
        flow_iy_ptr = flow_ix_ptr + w*h*(k-1);
 
        nb_num = (k==1) ? NEIGHBORS_2D : NEIGHBORS_3D;
-       nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
+       nb_size = sizeof(int) + (sizeof(int) + sizeof(double)) * nb_num;
+       index_offset = sizeof(int);
        ret_neighbors = neighbors = calloc(w*h*k, nb_size);
 //     printf("alloc neighbor grid=%lu Mbytes\n", nb_size*w*h*k/1024/1024);
        if (!ret_neighbors) {
-               printf("failed to allocate neighbor grid\n");
+               printf("failed to allocate neighbor grid (%lu megabytes)\n", nb_size * w*h*k / 1024 / 1024 );
                return NULL;
        }
 
        for (z = 0; z < k; z++) {
                for (y = 0; y < h; y++) {
                        for (x = 0; x < w; x++) {
-                               if (k==1)
-                                       i_index = ((struct neighbors_2d *)neighbors)->index;
-                               else
-                                       i_index = ((struct neighbors_3d *)neighbors)->index;
+                               i_index = (int *)(neighbors+index_offset);
                                for (i = 0, n = 0; i < nb_num; i++) {
                                        /* xx, yy, zz is the neighbor of color source
                                         * The first neighbor is always the point itself!
@@ -903,10 +900,7 @@ unsigned char *gen_neighbor(int w, int h, int k, const darray_t *flow, const dar
                                                continue;
                                        i_index[n++] = index;
                                }
-                               if (k == 1)
-                                       ((struct neighbors_2d *)neighbors)->num = n;
-                               else
-                                       ((struct neighbors_3d *)neighbors)->num = n;
+                               *((int *)neighbors) = n;
                                neighbors += nb_size;
                        }
                }
@@ -923,6 +917,7 @@ void weighten(const darray_t *luminance, unsigned char *neighbors)
        double sqdiff[NEIGHBORS_3D];
        double log0_01 = log(0.01);
        double *lum_ptr;
+       int nb_num, index_offset, weight_offset;
        unsigned long nb_size;
        int *i_index; double *w_index;
 
@@ -932,20 +927,17 @@ void weighten(const darray_t *luminance, unsigned char *neighbors)
        k = darrayGetDimensions(luminance)[2];
        lum_ptr = darrayGetPr(luminance);
 
-       nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
+       nb_num = (k==1) ? NEIGHBORS_2D : NEIGHBORS_3D;
+       nb_size = sizeof(int) + (sizeof(int) + sizeof(double)) * nb_num;
+       index_offset = sizeof(int);
+       weight_offset = sizeof(int) + sizeof(int) * nb_num;
 
        for (z = 0; z < k; z++) {
                for (y = 0; y < h; y++) {
                        for (x = 0; x < w; x++, neighbors += nb_size) {
-                               if (k==1) {
-                                       num = ((struct neighbors_2d *)neighbors)->num;
-                                       i_index = ((struct neighbors_2d *)neighbors)->index;
-                                       w_index = ((struct neighbors_2d *)neighbors)->weight;
-                               } else {
-                                       num = ((struct neighbors_3d *)neighbors)->num;
-                                       i_index = ((struct neighbors_3d *)neighbors)->index;
-                                       w_index = ((struct neighbors_3d *)neighbors)->weight;
-                               }
+                               num = *((int *)neighbors);
+                               i_index = (int *)(neighbors+index_offset);
+                               w_index = (double *)(neighbors+weight_offset);
                                /* Be sure that we have at least 3 neighbors.
                                 * This applies for every corner in a plane.
                                 * The first point in the neighbor list iss the point itself.
@@ -1013,6 +1005,7 @@ static void smooth(int level, darray_t *value, const darray_t *mark, const darra
        int x, y, z, w, h, k, i, num;
        double *value_ptr, *value_line_ptr, *mark_line_ptr, *init_line_ptr;
        double val;
+       int nb_num, index_offset, weight_offset;
        unsigned long nb_size;
        int *i_index; double *w_index;
 
@@ -1027,7 +1020,10 @@ static void smooth(int level, darray_t *value, const darray_t *mark, const darra
        ASSERT(k == darrayGetDimensions(mark)[2], "z-sizes of mark array is different");
        value_ptr = darrayGetPr(value);
 
-       nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
+       nb_num = (k==1) ? NEIGHBORS_2D : NEIGHBORS_3D;
+       nb_size = sizeof(int) + (sizeof(int) + sizeof(double)) * nb_num;
+       index_offset = sizeof(int);
+       weight_offset = sizeof(int) + sizeof(int) * nb_num;
 
        for (z = 0; z < k; z++) {
                for (y = 0; y < h; y++) {
@@ -1035,15 +1031,9 @@ static void smooth(int level, darray_t *value, const darray_t *mark, const darra
                        mark_line_ptr = darrayGetPr(mark) + y*w + z*w*h;
                        init_line_ptr = darrayGetPr(init) + y*w + z*w*h;
                        for (x = 0; x < w; x++, neighbors += nb_size) {
-                               if (k==1) {
-                                       num = ((struct neighbors_2d *)neighbors)->num;
-                                       i_index = ((struct neighbors_2d *)neighbors)->index;
-                                       w_index = ((struct neighbors_2d *)neighbors)->weight;
-                               } else {
-                                       num = ((struct neighbors_3d *)neighbors)->num;
-                                       i_index = ((struct neighbors_3d *)neighbors)->index;
-                                       w_index = ((struct neighbors_3d *)neighbors)->weight;
-                               }
+                               num = *((int *)neighbors);
+                               i_index = (int *)(neighbors+index_offset);
+                               w_index = (double *)(neighbors+weight_offset);
                                /* if pixle is marked */
                                darrayCheckPr(mark, mark_line_ptr + x, 1);
                                if (mark_line_ptr[x] < 0.5) {
@@ -1082,6 +1072,7 @@ static double residual(int level, darray_t *value, const darray_t *mark, const d
        int x, y, z, w, h, k, i, num;
        double *value_ptr, *mark_line_ptr, *init_line_ptr;
        double val, residual = 0;
+       int nb_num, index_offset, weight_offset;
        unsigned long nb_size;
        int *i_index; double *w_index;
 
@@ -1096,22 +1087,19 @@ static double residual(int level, darray_t *value, const darray_t *mark, const d
        ASSERT(k == darrayGetDimensions(mark)[2], "z-sizes of mark array is different");
        value_ptr = darrayGetPr(value);
 
-       nb_size = (k==1) ? sizeof(struct neighbors_2d) : sizeof(struct neighbors_3d);
+       nb_num = (k==1) ? NEIGHBORS_2D : NEIGHBORS_3D;
+       nb_size = sizeof(int) + (sizeof(int) + sizeof(double)) * nb_num;
+       index_offset = sizeof(int);
+       weight_offset = sizeof(int) + sizeof(int) * nb_num;
 
        for (z = 0; z < k; z++) {
                for (y = 0; y < h; y++) {
                        init_line_ptr = darrayGetPr(init) + y*w + z*w*h;
                        mark_line_ptr = darrayGetPr(mark) + y*w + z*w*h;
                        for (x = 0; x < w; x++, neighbors += nb_size) {
-                               if (k==1) {
-                                       num = ((struct neighbors_2d *)neighbors)->num;
-                                       i_index = ((struct neighbors_2d *)neighbors)->index;
-                                       w_index = ((struct neighbors_2d *)neighbors)->weight;
-                               } else {
-                                       num = ((struct neighbors_3d *)neighbors)->num;
-                                       i_index = ((struct neighbors_3d *)neighbors)->index;
-                                       w_index = ((struct neighbors_3d *)neighbors)->weight;
-                               }
+                               num = *((int *)neighbors);
+                               i_index = (int *)(neighbors+index_offset);
+                               w_index = (double *)(neighbors+weight_offset);
                                /* if pixle is marked, no residual */
                                darrayCheckPr(mark, mark_line_ptr + x, 1);
                                if (mark_line_ptr[x] < 0.5)
@@ -1397,7 +1385,7 @@ void draw_flow(darray_t *dst, const darray_t *flow, const darray_t *flow_i)
  * before z)!
  *
  */
-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, int scalexyz)
+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, int scalexyz, double target_residual_change)
 {
 #ifdef RESIDUAL
        double curr_residual, prev_residual = 10000000000000.0;
@@ -1414,7 +1402,8 @@ int solve_mg(int nlevel, int iters, int ncycle, darray_t **values, darray_t **ma
                        for (i = 0; i < iters; i++)
                                smooth(level, values[level], marks[level], init, nb_list[level]);
 #ifdef RESIDUAL
-                       curr_residual += residual(level, values[level], marks[level], init, nb_list[level]);
+                       if (target_residual_change)
+                               curr_residual += residual(level, values[level], marks[level], init, nb_list[level]);
 #endif
                        if (level < scalexyz)
                                rc = restrict(values[level], values[level+1], flows[level]);
@@ -1442,9 +1431,16 @@ int solve_mg(int nlevel, int iters, int ncycle, darray_t **values, darray_t **ma
 
                /* end if residual raises again */
 #ifdef RESIDUAL
-               if (prev_residual < curr_residual)
+//printf("residual %.8f (change=%%%.4f)\n", curr_residual, (prev_residual-curr_residual)/prev_residual*100);
+               if (target_residual_change)
+                       printf(" %.1f%%", (prev_residual-curr_residual)/prev_residual*100); fflush(stdout);
+               if (curr_residual == 0.0) {
+                       printf(" 0"); fflush(stdout);
+                       break;
+               }
+               if (target_residual_change && (prev_residual-curr_residual)/prev_residual < target_residual_change)
                        break;
-               curr_residual = prev_residual;
+               prev_residual = curr_residual;
 #endif
        }