JWS C Library
C language utility library
edge.c
Go to the documentation of this file.
00001 /*
00002  * This work is licensed under a Creative Commons 
00003  * Attribution-Noncommercial-Share Alike 3.0 United States License.
00004  * 
00005  *    http://creativecommons.org/licenses/by-nc-sa/3.0/us/
00006  * 
00007  * You are free:
00008  * 
00009  *    to Share - to copy, distribute, display, and perform the work
00010  *    to Remix - to make derivative works
00011  * 
00012  * Under the following conditions:
00013  * 
00014  *    Attribution. You must attribute the work in the manner specified by the
00015  *    author or licensor (but not in any way that suggests that they endorse you
00016  *    or your use of the work).
00017  * 
00018  *    Noncommercial. You may not use this work for commercial purposes.
00019  * 
00020  *    Share Alike. If you alter, transform, or build upon this work, you may
00021  *    distribute the resulting work only under the same or similar license to
00022  *    this one.
00023  * 
00024  * For any reuse or distribution, you must make clear to others the license
00025  * terms of this work. The best way to do this is by including this header.
00026  * 
00027  * Any of the above conditions can be waived if you get permission from the
00028  * copyright holder.
00029  * 
00030  * Apart from the remix rights granted under this license, nothing in this
00031  * license impairs or restricts the author's moral rights.
00032  */
00033 
00034 
00050 #include <jwsc/config.h>
00051 
00052 #include <stdlib.h>
00053 #include <stdio.h>
00054 #include <inttypes.h>
00055 #include <assert.h>
00056 #include <math.h>
00057 #include <string.h>
00058 #include <errno.h>
00059 
00060 #include "jwsc/base/error.h"
00061 #include "jwsc/math/constants.h"
00062 #include "jwsc/vector/vector.h"
00063 #include "jwsc/vector/vector.h"
00064 #include "jwsc/matrix/matrix.h"
00065 #include "jwsc/matrix/matrix_fft.h"
00066 #include "jwsc/matrix/matrix_conv.h"
00067 #include "jwsc/matrix/matrix_util.h"
00068 #include "jwsc/filter/2d.h"
00069 #include "jwsc/prob/pmf.h"
00070 #include "jwsc/image/edge.h"
00071 
00072 #ifdef JWSC_HAVE_DMALLOC
00073 #include <dmalloc.h>
00074 #endif
00075 
00076 
00078 typedef struct Edge_list_f
00079 {
00081     Edge_point_f* pt;
00082 
00084     struct Edge_list_f* next;
00085 }
00086 Edge_list_f;
00087 
00088 
00090 static void free_edge_list_f(Edge_list_f* edges)
00091 {
00092     Edge_list_f* next;
00093 
00094     next = edges->next;
00095 
00096     free(edges->pt);
00097     free(edges);
00098 
00099     if (next)
00100     {
00101         free_edge_list_f(next);
00102     }
00103 }
00104 
00105 
00110 static void copy_edge_list_into_set_f(Edge_set_f* set, Edge_list_f* list)
00111 {
00112     uint32_t      num_pts;
00113     uint32_t      e;
00114     Edge_list_f*  iter;
00115     Edge_point_f* pt;
00116     Edge_point_f* pts;
00117 
00118     set->num_edges++;
00119 
00120     assert(set->num_pts = realloc(set->num_pts, 
00121                 set->num_edges * sizeof(uint32_t)));
00122 
00123     num_pts = 0;
00124     iter = list;
00125     while (iter != NULL)
00126     {
00127         num_pts++;
00128         iter = iter->next;
00129     }
00130     set->num_pts[ set->num_edges - 1 ] = num_pts;
00131     set->total_num_pts += num_pts;
00132 
00133     if (set->num_edges == 1)
00134     {
00135         assert(set->pts = malloc(set->num_edges * sizeof(Edge_point_f*)));
00136         assert(*(set->pts) = malloc(set->total_num_pts * sizeof(Edge_point_f)));
00137     }
00138     else
00139     {
00140         assert(set->pts = realloc(set->pts, 
00141                     set->num_edges * sizeof(Edge_point_f*)));
00142         assert(*(set->pts) = realloc(*(set->pts), 
00143                     set->total_num_pts * sizeof(Edge_point_f)));
00144 
00145         pts = *(set->pts);
00146         for (e = 1; e < set->num_edges; e++)
00147         {
00148             pts += set->num_pts[ e-1 ];
00149             set->pts[ e ] = pts;
00150         }
00151     }
00152 
00153     pt   = set->pts[ set->num_edges - 1 ];
00154     iter = list;
00155     while (iter != NULL)
00156     {
00157         *pt = *(iter->pt);
00158 
00159         pt++;
00160         iter = iter->next;
00161     }
00162 }
00163 
00164 
00172 static Edge_list_f* merge_edge_lists_f
00173 (
00174     Edge_list_f* left, 
00175     Edge_list_f* right
00176 )
00177 {
00178     Edge_list_f* iter;
00179     Edge_list_f* next;
00180     Edge_list_f* prev;
00181 
00182     assert(left != NULL || right != NULL);
00183 
00184     if (left == NULL)
00185     {
00186         return right;
00187     }
00188     else if (right == NULL)
00189     {
00190         return left;
00191     }
00192 
00193     prev = right;
00194     iter = left;
00195     while (iter != NULL)
00196     {
00197         next = iter->next;
00198         iter->next = prev;
00199         prev = iter;
00200         iter = next;
00201     }
00202 
00203     return prev;
00204 }
00205 
00206 
00207 
00214 typedef struct
00215 {
00217     float dcol;
00218 
00220     float drow;
00221 
00223     float mag;
00224 
00226     uint8_t marked;
00227 }
00228 Gradient_f;
00229 
00230 
00232 static Error* create_gradient_map_f
00233 (
00234     Gradient_f***   map_out,
00235     const Matrix_f* m,
00236     float           sigma
00237 )
00238 {
00239     uint32_t num_rows, num_cols;
00240     uint32_t row, col;
00241     float    dcol, drow;
00242 
00243     Matrix_f*    gauss  = NULL;
00244     Matrix_f*    m_dcol = NULL;
00245     Matrix_f*    m_drow = NULL;
00246     Gradient_f** map;
00247     Gradient_f*  map_elts;
00248     Error*       e;
00249 
00250     num_rows = m->num_rows;
00251     num_cols = m->num_cols;
00252 
00253     assert(*map_out == NULL);
00254 
00255 #ifdef JWSC_HAVE_FFTW3F
00256     if ((e = create_2d_gaussian_dx_filter_f(&gauss, sigma, sigma,
00257                     num_rows, num_cols)) != NULL)
00258     {
00259         return e;
00260     }
00261     shift_matrix_f(&gauss, gauss);
00262     assert(convolve_matrix_fft_f(&m_dcol, m, gauss) == NULL);
00263 
00264     if ((e = create_2d_gaussian_dy_filter_f(&gauss, sigma, sigma,
00265                     num_rows, num_cols)) != NULL)
00266     {
00267         return e;
00268     }
00269     shift_matrix_f(&gauss, gauss);
00270     assert(convolve_matrix_fft_f(&m_drow, m, gauss) == NULL);
00271 #else
00272     if ((e = create_auto_2d_gaussian_dx_filter_f(&gauss, sigma, sigma)) 
00273             != NULL)
00274     {
00275         return e;
00276     }
00277     assert(convolve_matrix_f(&m_dcol, m, gauss) == NULL);
00278 
00279     if ((e = create_auto_2d_gaussian_dy_filter_f(&gauss, sigma, sigma)) 
00280             != NULL)
00281     {
00282         return e;
00283     }
00284     assert(convolve_matrix_f(&m_drow, m, gauss) == NULL);
00285 #endif
00286 
00287     free_matrix_f(gauss);
00288 
00289     assert(map_elts = malloc(num_rows*num_cols*sizeof(Gradient_f)));
00290     assert(*map_out = malloc(num_rows*sizeof(Gradient_f*)));
00291     map = *map_out;
00292 
00293     for (row = 0; row < num_rows; row++)
00294     {
00295         map[ row ] = &(map_elts[ row*num_cols ]);
00296     }
00297 
00298     for (row = 0; row < num_rows; row++)
00299     {
00300         for (col = 0; col < num_cols; col++)
00301         {
00302             dcol = m_dcol->elts[ row ][ col ];
00303             drow = m_drow->elts[ row ][ col ];
00304 
00305             map[ row ][ col ].dcol   = dcol;
00306             map[ row ][ col ].drow   = drow;
00307             map[ row ][ col ].mag    = sqrt(dcol*dcol + drow*drow);
00308             map[ row ][ col ].marked = 0;
00309 
00310             if (map[ row ][ col ].mag >= 1.0e-8)
00311             {
00312                 map[ row ][ col ].dcol /= map[ row ][ col ].mag;
00313                 map[ row ][ col ].drow /= map[ row ][ col ].mag;
00314             }
00315         }
00316     }
00317 
00318     free_matrix_f(m_dcol);
00319     free_matrix_f(m_drow);
00320 
00321     return NULL;
00322 }
00323 
00324 
00326 static Gradient_f* follow_gradient_f
00327 (
00328     int32_t*     grad_row_in_out, 
00329     int32_t*     grad_col_in_out,
00330     float        dir_x,
00331     float        dir_y,
00332     Gradient_f** map,
00333     uint32_t     num_rows,
00334     uint32_t     num_cols,
00335     uint32_t     padding
00336 )
00337 {
00338     static const int neighbor_positions[ 8 ][ 2 ] = { {  1,  0 }, 
00339                                                 {  1,  1 }, 
00340                                                 {  0,  1 }, 
00341                                                 { -1,  1 }, 
00342                                                 { -1,  0 }, 
00343                                                 { -1, -1 }, 
00344                                                 {  0, -1 }, 
00345                                                 {  1, -1 } };
00346     static const float neighbor_vectors[ 8 ][ 2 ] = { {  1, 0 }, 
00347                                                 {  0.70710678f,  0.70710678f },
00348                                                 {  0,            1 },
00349                                                 { -0.70710678f,  0.70710678f },
00350                                                 { -1,            0 },
00351                                                 { -0.70710678f, -0.70710678f },
00352                                                 {  0,           -1 },
00353                                                 {  0.70710678f, -0.70710678f }};
00354 
00355     uint8_t     i;
00356     uint8_t     max_neighbor;
00357     int32_t     grad_col, grad_row;
00358     float       max_dp;
00359     float       dp;
00360 
00361     Gradient_f* grad;
00362 
00363     grad_col = *grad_col_in_out;
00364     grad_row = *grad_row_in_out;
00365 
00366     max_neighbor = 0;
00367     max_dp       = -1.0f;
00368     grad         = &map[ grad_row ][ grad_col ];
00369 
00370     for (i = 0; i < 8; i++)
00371     {
00372         dp = dir_x * neighbor_vectors[ i ][ 0 ] +
00373              dir_y * neighbor_vectors[ i ][ 1 ];
00374 
00375         /* Should have some stochastic tie-breaker here. */
00376         if (dp >= max_dp)
00377         {
00378             max_neighbor = i;
00379             max_dp       = dp;
00380         }
00381     }
00382 
00383     grad_row += neighbor_positions[ max_neighbor ][ 1 ];
00384     grad_col += neighbor_positions[ max_neighbor ][ 0 ];
00385 
00386     if (grad_row == padding-1) 
00387         grad_row = padding;
00388     else if (grad_row == num_rows-padding) 
00389         grad_row = num_rows-padding-1;
00390    
00391     if (grad_col == padding-1) 
00392         grad_col = padding;
00393     else if (grad_col == num_cols-padding) 
00394         grad_col = num_cols-padding-1;
00395 
00396     *grad_col_in_out = grad_col;
00397     *grad_row_in_out = grad_row;
00398 
00399     return &map[ grad_row ][ grad_col ];
00400 }
00401 
00402 
00404 static Gradient_f* get_maximal_along_gradient_f
00405 (
00406     int32_t*     grad_row_in_out, 
00407     int32_t*     grad_col_in_out, 
00408     Gradient_f** map,
00409     uint32_t     num_rows,
00410     uint32_t     num_cols,
00411     uint32_t     padding
00412 ) 
00413 {
00414     int32_t grad_row, grad_col;
00415     int32_t curr_grad_row, curr_grad_col;
00416     int32_t next_grad_row, next_grad_col;
00417     int32_t prev_grad_row, prev_grad_col;
00418 
00419     Gradient_f* curr_grad;
00420     Gradient_f* next_grad;
00421     Gradient_f* prev_grad;
00422     Gradient_f* max_grad;
00423 
00424     grad_row = *grad_row_in_out;
00425     grad_col = *grad_col_in_out;
00426 
00427     curr_grad_row = grad_row;
00428     curr_grad_col = grad_col;
00429     curr_grad     = &map[ curr_grad_row ][ curr_grad_col ];
00430 
00431     prev_grad_row = curr_grad_row;
00432     prev_grad_col = curr_grad_col;
00433     prev_grad     = follow_gradient_f(&prev_grad_row, &prev_grad_col,
00434                                       -(curr_grad->dcol), -(curr_grad->drow),
00435                                       map, num_rows, num_cols, padding);
00436 
00437     next_grad_row = curr_grad_row;
00438     next_grad_col = curr_grad_col;
00439     next_grad     = follow_gradient_f(&next_grad_row, &next_grad_col,
00440                                       curr_grad->dcol, curr_grad->drow,
00441                                       map, num_rows, num_cols, padding);
00442 
00443     max_grad = NULL;
00444     while (max_grad == NULL)
00445     {
00446         if (curr_grad->mag >= next_grad->mag && 
00447             curr_grad->mag >= prev_grad->mag)
00448         {
00449             max_grad = curr_grad;
00450         }
00451         else if (curr_grad->mag >= prev_grad->mag)
00452         {
00453             curr_grad_row = next_grad_row;
00454             curr_grad_col = next_grad_col;
00455             curr_grad     = next_grad;
00456         }
00457         else
00458         {
00459             curr_grad_row = prev_grad_row;
00460             curr_grad_col = prev_grad_col;
00461             curr_grad     = prev_grad;
00462         }
00463 
00464         prev_grad_row = curr_grad_row;
00465         prev_grad_col = curr_grad_col;
00466         prev_grad     = follow_gradient_f(&prev_grad_row, &prev_grad_col,
00467                 -(curr_grad->dcol), -(curr_grad->drow), map, 
00468                 num_rows, num_cols, padding);
00469 
00470         next_grad_row = curr_grad_row;
00471         next_grad_col = curr_grad_col;
00472         next_grad     = follow_gradient_f(&next_grad_row, &next_grad_col,
00473                                           curr_grad->dcol, curr_grad->drow, 
00474                                           map, num_rows, num_cols, padding);
00475     }
00476 
00477     *grad_row_in_out = curr_grad_row;
00478     *grad_col_in_out = curr_grad_col;
00479 
00480     return max_grad;
00481 }
00482 
00483 
00490 static Edge_list_f* follow_edge_right_f
00491 (
00492     float        dir_x, 
00493     float        dir_y, 
00494     int32_t      grad_row,
00495     int32_t      grad_col, 
00496     Gradient_f** map,
00497     uint32_t     num_rows,
00498     uint32_t     num_cols,
00499     uint32_t     padding,
00500     float        thresh
00501 )
00502 {
00503     Gradient_f*  grad_curr = NULL;
00504     Gradient_f*  grad_next = NULL;
00505     Edge_list_f* node = NULL;
00506 
00507     grad_curr = &(map[ grad_row ][ grad_col ]);
00508     
00509     follow_gradient_f(&grad_row, &grad_col, dir_x, dir_y, map, 
00510             num_rows, num_cols, padding);
00511 
00512     grad_next = get_maximal_along_gradient_f(&grad_row, &grad_col, map, 
00513             num_rows, num_cols, padding);
00514 
00515     if (!grad_next->marked && grad_next->mag >= thresh &&
00516         grad_row >= padding && grad_row < num_rows-padding &&
00517         grad_col >= padding && grad_col < num_cols-padding)
00518     {
00519         grad_next->marked = 1;
00520 
00521         assert(node = malloc(sizeof(Edge_list_f)));
00522 
00523         assert(node->pt = malloc(sizeof(Edge_point_f)));
00524         node->pt->row  = grad_row - padding;
00525         node->pt->col  = grad_col - padding;
00526         node->pt->dcol = grad_next->dcol;
00527         node->pt->drow = grad_next->drow;
00528         node->pt->mag  = grad_next->mag;
00529 
00530         dir_x =  grad_next->drow;
00531         dir_y = -grad_next->dcol;
00532 
00533         node->next = follow_edge_right_f(dir_x, dir_y, grad_row, grad_col, map, 
00534                 num_rows, num_cols, padding, thresh);
00535     }
00536 
00537     return node;
00538 }
00539 
00540 
00547 static Edge_list_f* follow_edge_left_f
00548 (
00549     float        dir_x, 
00550     float        dir_y, 
00551     int32_t      grad_row,
00552     int32_t      grad_col, 
00553     Gradient_f** map,
00554     uint32_t     num_rows,
00555     uint32_t     num_cols,
00556     uint32_t     padding,
00557     float        thresh
00558 )
00559 {
00560     Gradient_f*  grad_curr = NULL;
00561     Gradient_f*  grad_next = NULL;
00562     Edge_list_f* node = NULL;
00563     
00564     grad_curr = &(map[ grad_row ][ grad_col ]);
00565     
00566     follow_gradient_f(&grad_row, &grad_col, dir_x, dir_y, map, 
00567             num_rows, num_cols, padding);
00568 
00569     grad_next = get_maximal_along_gradient_f(&grad_row, &grad_col, map, 
00570             num_rows, num_cols, padding);
00571 
00572     if (!grad_next->marked && grad_next->mag >= thresh &&
00573         grad_row >= padding && grad_row < num_rows-padding &&
00574         grad_col >= padding && grad_col < num_cols-padding)
00575     {
00576         grad_next->marked = 1;
00577 
00578         assert(node = malloc(sizeof(Edge_list_f)));
00579 
00580         assert(node->pt = malloc(sizeof(Edge_point_f)));
00581         node->pt->row  = grad_row - padding;
00582         node->pt->col  = grad_col - padding;
00583         node->pt->dcol = grad_next->dcol;
00584         node->pt->drow = grad_next->drow;
00585         node->pt->mag  = grad_next->mag;
00586 
00587         dir_x = -grad_next->drow;
00588         dir_y =  grad_next->dcol;
00589 
00590         node->next = follow_edge_left_f(dir_x, dir_y, grad_row, grad_col, map, 
00591                 num_rows, num_cols, padding, thresh);
00592     }
00593 
00594     return node;
00595 }
00596 
00597 
00602 static Edge_set_f* get_edge_set_from_gradient_map_f
00603 (
00604     Gradient_f**   map, 
00605     uint32_t       num_rows, 
00606     uint32_t       num_cols,
00607     uint32_t       padding,
00608     float          begin_thresh, 
00609     float          end_thresh
00610 )
00611 {
00612     int32_t  grad_row;
00613     int32_t  grad_col;
00614     uint32_t row, col;
00615     float    dir_x;
00616     float    dir_y;
00617 
00618     Gradient_f*   grad;
00619     Gradient_f*   max_grad;
00620     Edge_list_f*  node;
00621     Edge_list_f*  right;
00622     Edge_list_f*  left;
00623     Edge_list_f*  edge_list;
00624     Edge_set_f*   edge_set;
00625 
00626     assert(edge_set = malloc(sizeof(Edge_set_f)));
00627     edge_set->num_edges = 0;
00628     edge_set->total_num_pts = 0;
00629     edge_set->num_pts = NULL;
00630     edge_set->pts     = NULL;
00631 
00632     for (row = padding; row < num_rows-padding; row++)
00633     {
00634         for (col = padding; col < num_cols-padding; col++)
00635         {
00636             grad = &map[ row ][ col ];
00637 
00638             if (!grad->marked && grad->mag >= begin_thresh)
00639             {
00640                 grad_row = row;
00641                 grad_col = col;
00642 
00643                 max_grad = get_maximal_along_gradient_f(&grad_row, &grad_col, 
00644                         map, num_rows, num_cols, padding);
00645 
00646                 if (!max_grad->marked && 
00647                     grad_row >= padding && grad_row < num_rows-padding &&
00648                     grad_col >= padding && grad_col < num_cols-padding)
00649                 {
00650                     max_grad->marked = 1;
00651 
00652                     assert(node = malloc(sizeof(Edge_list_f)));
00653                     node->next = NULL;
00654 
00655                     assert(node->pt = malloc(sizeof(Edge_point_f)));
00656                     node->pt->row   = grad_row - padding;
00657                     node->pt->col   = grad_col - padding;
00658                     node->pt->dcol  = grad->dcol;
00659                     node->pt->drow  = grad->drow;
00660                     node->pt->mag   = grad->mag;
00661 
00662                     dir_x =  max_grad->drow;
00663                     dir_y = -max_grad->dcol;
00664                     left  = follow_edge_right_f(dir_x, dir_y, grad_row,
00665                             grad_col, map, num_rows, num_cols, padding,
00666                             end_thresh);
00667 
00668                     dir_x = -max_grad->drow;
00669                     dir_y =  max_grad->dcol;
00670                     right = follow_edge_left_f(dir_x, dir_y, grad_row, grad_col,
00671                             map, num_rows, num_cols, padding, end_thresh);
00672 
00673                     edge_list = merge_edge_lists_f(node, right);
00674                     edge_list = merge_edge_lists_f(left, edge_list);
00675                     copy_edge_list_into_set_f(edge_set, edge_list);
00676                     free_edge_list_f(edge_list);
00677                 }
00678             }
00679         }
00680     }
00681 
00682     return edge_set;
00683 }
00684 
00685 
00686 
00687 
00719 Error* detect_image_edge_set_f
00720 (
00721     Edge_set_f**   edges_out,
00722     const Image_f* img,
00723     float          sigma, 
00724     float          begin_thresh, 
00725     float          end_thresh,
00726     uint32_t       padding
00727 )
00728 {
00729     Matrix_f* m = NULL;
00730     Error*    e;
00731 
00732     create_matrix_from_image_f(&m, img, 0.3, 0.59, 0.11);
00733     if ((e = detect_matrix_edge_set_f(edges_out, m, sigma, begin_thresh,
00734                     end_thresh, padding)) != NULL)
00735     {
00736         return e;
00737     }
00738 
00739     free_matrix_f(m);
00740     
00741     return NULL;
00742 }
00743 
00774 Error* DEPRECATED_detect_image_edge_set_f
00775 (
00776     Edge_set_f**   r_edges_out,
00777     Edge_set_f**   g_edges_out,
00778     Edge_set_f**   b_edges_out,
00779     const Image_f* img,
00780     float          sigma, 
00781     float          begin_thresh, 
00782     float          end_thresh,
00783     uint32_t       padding
00784 )
00785 {
00786     Matrix_f* m = NULL;
00787     Error*    e;
00788 
00789     create_matrix_from_image_f(&m, img, 1.0, 0.0, 0.0);
00790     if ((e = detect_matrix_edge_set_f(r_edges_out, m, sigma, begin_thresh,
00791                     end_thresh, padding)) != NULL)
00792     {
00793         return e;
00794     }
00795 
00796     create_matrix_from_image_f(&m, img, 0.0, 0.0, 0.0);
00797     if ((e = detect_matrix_edge_set_f(g_edges_out, m, sigma, begin_thresh,
00798                     end_thresh, padding)) != NULL)
00799     {
00800         return e;
00801     }
00802 
00803     create_matrix_from_image_f(&m, img, 0.0, 0.0, 1.0);
00804     if ((e = detect_matrix_edge_set_f(b_edges_out, m, sigma, begin_thresh,
00805                     end_thresh, padding)) != NULL)
00806     {
00807         return e;
00808     }
00809 
00810     free_matrix_f(m);
00811     
00812     return NULL;
00813 }
00814 
00851 Error* detect_matrix_edge_set_f
00852 (
00853     Edge_set_f**    edges_out,
00854     const Matrix_f* m,
00855     float           sigma, 
00856     float           begin_thresh, 
00857     float           end_thresh,
00858     uint32_t        padding
00859 )
00860 {
00861     Matrix_f*    padded_m = NULL;
00862     Gradient_f** map = NULL;
00863     Error*       e;
00864 
00865     if (*edges_out != NULL)
00866     {
00867         free_edge_set_f(*edges_out);
00868         *edges_out = NULL;
00869     }
00870 
00871     extend_matrix_f(&padded_m, m, padding, padding);
00872 
00873     if ((e = create_gradient_map_f(&map, padded_m, sigma)) != NULL)
00874     {
00875         free_matrix_f(padded_m);
00876         return e;
00877     }
00878 
00879     *edges_out = get_edge_set_from_gradient_map_f(map, padded_m->num_rows,
00880             padded_m->num_cols, padding, begin_thresh, end_thresh);
00881 
00882     (*edges_out)->num_rows = m->num_rows;
00883     (*edges_out)->num_cols = m->num_cols;
00884 
00885     free_matrix_f(padded_m);
00886     free(*map);
00887     free(map);
00888 
00889     return NULL;
00890 }
00891 
00905 void free_edge_set_f(Edge_set_f* edges)
00906 {
00907     if (edges == NULL)
00908         return;
00909 
00910     if (edges->total_num_pts > 0)
00911     {
00912         free(*(edges->pts));
00913     }
00914     free(edges->pts);
00915     free(edges->num_pts);
00916     free(edges);
00917 }
00918 
00936 void remove_short_edges_f(Edge_set_f* edges, uint32_t min_len)
00937 {
00938     uint32_t  i, j, k;
00939     uint32_t  num_pts_to_remove;
00940     uint32_t  num_edges_to_remove;
00941     uint32_t* old_num_pts;
00942 
00943     Edge_point_f*  pt;
00944     Edge_point_f** old_pts;
00945 
00946     num_pts_to_remove = 0;
00947     num_edges_to_remove = 0;
00948 
00949     for (i = 0; i < edges->num_edges; i++)
00950     {
00951         if (edges->num_pts[ i ] < min_len)
00952         {
00953             num_pts_to_remove += edges->num_pts[ i ];
00954             num_edges_to_remove++;
00955         }
00956     }
00957 
00958     if (num_edges_to_remove == 0)
00959     {
00960         assert(num_pts_to_remove == 0);
00961         return;
00962     }
00963 
00964     old_pts = edges->pts;
00965     old_num_pts = edges->num_pts;
00966 
00967     edges->num_edges -= num_edges_to_remove;
00968     edges->total_num_pts -= num_pts_to_remove;
00969 
00970     edges->pts = malloc(edges->num_edges * sizeof(Edge_point_f*));
00971     assert(edges->pts);
00972 
00973     *(edges->pts) = malloc(edges->total_num_pts * sizeof(Edge_point_f));
00974     assert(*(edges->pts));
00975 
00976     edges->num_pts = malloc(edges->num_edges * sizeof(uint32_t));
00977     assert(edges->num_pts);
00978 
00979     i = 0;
00980     pt = *(edges->pts);
00981 
00982     for (j = 0; j < edges->num_edges + num_edges_to_remove; j++)
00983     {
00984         if (old_num_pts[ j ] >= min_len)
00985         {
00986             edges->num_pts[ i ] = old_num_pts[ j ];
00987 
00988             edges->pts[ i ] = pt;
00989 
00990             for (k = 0; k < edges->num_pts[ i ]; k++)
00991             {
00992                 *pt = old_pts[ j ][ k ];
00993                 pt++;
00994             }
00995 
00996             i++;
00997         }
00998     }
00999 
01000     free(*old_pts);
01001     free(old_pts);
01002     free(old_num_pts);
01003 }
01004 
01028 static void recursively_break_edges_at_corners_f
01029 (
01030     Edge_set_f* edges, 
01031     uint32_t    i, 
01032     float       thresh, 
01033     uint32_t    num_avg
01034 )
01035 {
01036     uint32_t j, k;
01037     uint32_t min_j;
01038 
01039     float  dcol_1, drow_1;
01040     float  dcol_2, drow_2;
01041     float  dp;
01042     float  min_dp;
01043 
01044     assert(num_avg > 0);
01045 
01046     if (edges->num_pts[ i ] < 2*num_avg)
01047         return;
01048 
01049     min_dp = thresh;
01050 
01051     for (j = num_avg-1; j < edges->num_pts[ i ] - num_avg; j++)
01052     {
01053         dcol_1 = drow_1 = 0;
01054         dcol_2 = drow_2 = 0;
01055 
01056         for (k = 0; k < num_avg; k++)
01057         {
01058             dcol_1 += edges->pts[ i ][ j-k ].dcol;
01059             drow_1 += edges->pts[ i ][ j-k ].drow;
01060             dcol_2 += edges->pts[ i ][ j+k+1 ].dcol;
01061             drow_2 += edges->pts[ i ][ j+k+1 ].drow;
01062         }
01063 
01064         dcol_1 /= num_avg;
01065         drow_1 /= num_avg;
01066         dcol_2 /= num_avg;
01067         drow_2 /= num_avg;
01068 
01069         dp = fabs(dcol_1*dcol_2 + drow_1*drow_2);
01070         if (dp < min_dp)
01071         {
01072             min_j = j;
01073             min_dp = dp;
01074         }
01075     }
01076 
01077     if (min_dp < thresh)
01078     {
01079         edges->num_edges++;
01080 
01081         edges->num_pts = realloc(edges->num_pts, 
01082                 edges->num_edges * sizeof(uint32_t));
01083         assert(edges->num_pts);
01084 
01085         edges->pts = realloc(edges->pts, 
01086                 edges->num_edges * sizeof(Edge_point_f*));
01087         assert(edges->pts);
01088 
01089         for (j = edges->num_edges-1; j > i; j--)
01090         {
01091             edges->num_pts[ j ] = edges->num_pts[ j-1 ];
01092             edges->pts[ j ]     = edges->pts[ j-1 ];
01093         }
01094 
01095         edges->num_pts[ i ]    = min_j+1;
01096         edges->num_pts[ i+1 ] -= min_j+1;
01097         edges->pts[ i+1 ]     += min_j+1;
01098 
01099         recursively_break_edges_at_corners_f(edges, i+1, thresh, num_avg);
01100         recursively_break_edges_at_corners_f(edges, i, thresh, num_avg);
01101     }
01102 }
01103 
01111 void break_edges_at_corners_f(Edge_set_f* edges, float thresh, uint32_t num_avg)
01112 {
01113     uint32_t i;
01114 
01115     if (num_avg == 0)
01116         return;
01117 
01118     for (i = 0; i < edges->num_edges; i++)
01119     {
01120         recursively_break_edges_at_corners_f(edges, i, thresh, num_avg);
01121     }
01122 }
01123 
01146 void sample_edge_set_f
01147 (
01148     Edge_set_f**      edges_out, 
01149     const Edge_set_f* edges_in, 
01150     float             p
01151 )
01152 {
01153     uint32_t      e, pt;
01154     uint32_t*     num_pts;
01155     Edge_point_f* pts;
01156     Edge_set_f*   edges;
01157 
01158     assert(edges_in->total_num_pts > 0);
01159 
01160     if (*edges_out == NULL || *edges_out == edges_in)
01161     {
01162         assert(edges = malloc(sizeof(Edge_set_f)));
01163 
01164         edges->pts = malloc(edges_in->num_edges * sizeof(Edge_point_f*));
01165         assert(edges->pts);
01166 
01167         *(edges->pts) = malloc(edges_in->total_num_pts * sizeof(Edge_point_f));
01168         assert(*(edges->pts));
01169 
01170         edges->num_pts = malloc(edges_in->num_edges * sizeof(uint32_t));
01171         assert(edges->num_pts);
01172     }
01173     else
01174     {
01175         edges = *edges_out;
01176 
01177         edges->pts = realloc(edges->pts, 
01178                 edges_in->num_edges * sizeof(Edge_point_f*));
01179         if (edges_in->num_edges > 0) assert(edges->pts);
01180 
01181         *(edges->pts) = realloc(*(edges->pts), 
01182                 edges_in->total_num_pts * sizeof(Edge_point_f));
01183         if (edges_in->total_num_pts > 0) assert(*(edges->pts));
01184 
01185         edges->num_pts = realloc(edges->num_pts, 
01186                 edges_in->num_edges * sizeof(uint32_t));
01187         if (edges_in->num_edges > 0) assert(edges->num_pts);
01188     }
01189 
01190     pts = *(edges->pts);
01191     num_pts = edges->num_pts;
01192 
01193     edges->total_num_pts = 0;
01194     edges->num_edges = 0;
01195     edges->num_rows = edges_in->num_rows;
01196     edges->num_cols = edges_in->num_cols;
01197 
01198     for (e = 0; e < edges_in->num_edges; e++)
01199     {
01200         *num_pts = 0;
01201 
01202         for (pt = 0; pt < edges_in->num_pts[ e ]; pt++)
01203         {
01204             if (sample_bernoulli_pmf_d(p))
01205             {
01206                 pts->row  = edges_in->pts[ e ][ pt ].row;
01207                 pts->col  = edges_in->pts[ e ][ pt ].col;
01208                 pts->dcol = edges_in->pts[ e ][ pt ].dcol;
01209                 pts->drow = edges_in->pts[ e ][ pt ].drow;
01210                 pts->mag  = edges_in->pts[ e ][ pt ].mag;
01211 
01212                 (*num_pts)++;
01213                 edges->total_num_pts++;
01214 
01215                 pts++;
01216             }
01217         }
01218 
01219         if (*num_pts != 0)
01220         {
01221             num_pts++;
01222             edges->num_edges++;
01223         }
01224     }
01225 
01226     edges->pts = realloc(edges->pts, edges->num_edges * sizeof(Edge_point_f*));
01227     if (edges->num_edges > 0) assert(edges->pts);
01228 
01229     *(edges->pts) = realloc(*(edges->pts), 
01230             edges->total_num_pts * sizeof(Edge_point_f));
01231     if (edges->total_num_pts > 0) assert(*(edges->pts));
01232 
01233     edges->num_pts = realloc(edges->num_pts, 
01234             edges->num_edges * sizeof(uint32_t));
01235     if (edges->num_edges > 0) assert(edges->num_pts);
01236 
01237 
01238     pts = *(edges->pts);
01239     for (e = 1; e < edges->num_edges; e++)
01240     {
01241         pts += edges->num_pts[ e-1 ];
01242         edges->pts[ e ] = pts;
01243     }
01244 
01245     if (*edges_out == edges_in)
01246     {
01247         free_edge_set_f(*edges_out);
01248     }
01249 
01250     *edges_out = edges;
01251 }
01252 
01277 Error* color_edge_set_f
01278 (
01279     Image_f**         img_out,
01280     const Image_f*    img_in,
01281     const Edge_set_f* edges, 
01282     const Pixel_f*    pxl
01283 )
01284 {
01285     uint32_t e;
01286     Error* err;
01287 
01288     if (*img_out != img_in)
01289     {
01290         copy_image_f(img_out, img_in);
01291     }
01292 
01293     for (e = 0; e < edges->num_edges; e++)
01294     {
01295         if ((err = color_edge_points_f(img_out, *img_out, edges->pts[ e ],
01296                 edges->num_pts[ e ], pxl)))
01297         {
01298             return err;
01299         }
01300     }
01301 
01302     return NULL;
01303 }
01304 
01328 Error* randomly_color_edge_set_f
01329 (
01330     Image_f**         img_out,
01331     const Image_f*    img_in,
01332     const Edge_set_f* edges
01333 )
01334 {
01335     uint32_t e;
01336     Error* err;
01337 
01338     if (*img_out != img_in)
01339     {
01340         copy_image_f(img_out, img_in);
01341     }
01342 
01343     for (e = 0; e < edges->num_edges; e++)
01344     {
01345         if ((err = randomly_color_edge_points_f(img_out, *img_out, 
01346                         edges->pts[ e ], edges->num_pts[ e ])))
01347         {
01348             return err;
01349         }
01350     }
01351 
01352     return NULL;
01353 }
01354 
01380 Error* color_edge_points_f
01381 (
01382     Image_f**           img_out,
01383     const Image_f*      img_in,
01384     const Edge_point_f* pts, 
01385     uint32_t            num_pts,
01386     const Pixel_f*      pxl
01387 )
01388 {
01389     uint32_t pt;
01390     uint32_t row, col;
01391     Image_f* img;
01392 
01393     if (*img_out != img_in)
01394     {
01395         copy_image_f(img_out, img_in);
01396     }
01397     img = *img_out;
01398 
01399     for (pt = 0; pt < num_pts; pt++)
01400     {
01401         row = pts[ pt ].row;
01402         col = pts[ pt ].col;
01403 
01404         if (row >= img_in->num_rows || col >= img_in->num_cols)
01405         {
01406             if (*img_out != img_in)
01407             {
01408                 free_image_f(*img_out);
01409                 *img_out = 0;
01410             }
01411             return JWSC_EARG("Edge points outside image to color in");
01412         }
01413 
01414         img->pxls[ row ][ col ] = *pxl;
01415     }
01416 
01417     return NULL;
01418 }
01419 
01444 Error* randomly_color_edge_points_f
01445 (
01446     Image_f**           img_out,
01447     const Image_f*      img_in,
01448     const Edge_point_f* pts, 
01449     uint32_t            num_pts
01450 )
01451 {
01452     Pixel_f pxl;
01453 
01454     pxl.r = (float)rand() / (float)RAND_MAX;
01455     pxl.g = (float)rand() / (float)RAND_MAX;
01456     pxl.b = (float)rand() / (float)RAND_MAX;
01457 
01458     return color_edge_points_f(img_out, img_in, pts, num_pts, &pxl);
01459 }
01460 
01503 Error* read_edge_set_f
01504 (
01505     Edge_set_f** edges_out,
01506     const char*  fname
01507 )
01508 {
01509     uint32_t i, j;
01510     FILE*    fp = NULL;
01511     Error*   e = NULL;
01512 
01513     Edge_set_f*  edges;
01514     Edge_point_f* pt;
01515 
01516     if (*edges_out != NULL)
01517     {
01518         free_edge_set_f(*edges_out);
01519         *edges_out = NULL;
01520     }
01521 
01522     if ((fp = fopen(fname, "r")) == NULL)
01523     {
01524         e = JWSC_EIO(strerror(errno));
01525         goto error;
01526     }
01527 
01528     assert(*edges_out = malloc(sizeof(Edge_set_f)));
01529     edges = *edges_out;
01530 
01531     if (fscanf(fp, "num_rows=%u\n", &(edges->num_rows)) != 1 ||
01532         fscanf(fp, "num_cols=%u\n", &(edges->num_cols)) != 1 ||
01533         fscanf(fp, "num_edges=%u\n", &(edges->num_edges)) != 1 ||
01534         fscanf(fp, "total_num_pts=%u\n", &(edges->total_num_pts)) != 1)
01535     {
01536         e = JWSC_EARG("File not properly formatted to read edge points");
01537         goto error;
01538     }
01539 
01540     assert(edges->pts = malloc(edges->num_edges * sizeof(Edge_point_f*)));
01541     assert(*(edges->pts) = malloc(edges->total_num_pts * sizeof(Edge_point_f)));
01542     assert(edges->num_pts = malloc(edges->num_edges * sizeof(uint32_t)));
01543 
01544     pt = *(edges->pts);
01545 
01546     for (i = 0; i < edges->num_edges; i++)
01547     {
01548         if (fscanf(fp, "num_pts=%u\n", &(edges->num_pts[ i ])) != 1)
01549         {
01550             e = JWSC_EARG("File not properly formatted to read edge points");
01551             goto error;
01552         }
01553 
01554         edges->pts[ i ] = pt;
01555 
01556         for (j = 0; j < edges->num_pts[ i ]; j++)
01557         {
01558             if (fscanf(fp, "col=%u row=%u dcol=%f drow=%f mag=%f\n", 
01559                         &(pt->col), &(pt->row), &(pt->dcol), &(pt->drow),
01560                         &(pt->mag)) != 5)
01561             {
01562                 e = JWSC_EARG("Edge point file improperly formatted");
01563                 goto error;
01564             }
01565 
01566             pt++;
01567         }
01568     }
01569 
01570     if (fclose(fp) != 0)
01571     {
01572         e = JWSC_EIO(strerror(errno));
01573         goto error;
01574     }
01575 
01576     return NULL;
01577 
01578 error:
01579     if (fp) fclose(fp);
01580     free_edge_set_f(*edges_out); 
01581     *edges_out = NULL;
01582     return e;
01583 }
01584 
01623 Error* write_edge_set_f
01624 (
01625     const Edge_set_f* edges,
01626     const char*       fname
01627 )
01628 {
01629     uint32_t i, j;
01630     FILE*    fp;
01631 
01632     const Edge_point_f* pt;
01633 
01634     if ((fp = fopen(fname, "w")) == NULL)
01635     {
01636         return JWSC_EIO(strerror(errno));
01637     }
01638 
01639     fprintf(fp, "num_rows=%u\n", edges->num_rows);
01640     fprintf(fp, "num_cols=%u\n", edges->num_cols);
01641     fprintf(fp, "num_edges=%u\n", edges->num_edges);
01642     fprintf(fp, "total_num_pts=%u\n", edges->total_num_pts);
01643 
01644     for (i = 0; i < edges->num_edges; i++)
01645     {
01646         fprintf(fp, "num_pts=%u\n", edges->num_pts[ i ]);
01647 
01648         for (j = 0; j < edges->num_pts[ i ]; j++)
01649         {
01650             pt = &(edges->pts[ i ][ j ]);
01651 
01652             fprintf(fp, "col=%u row=%u", pt->col, pt->row);
01653             fprintf(fp, " dcol=%f drow=%f", pt->dcol, pt->drow);
01654             fprintf(fp, " mag=%f\n", pt->mag);
01655         }
01656     }
01657 
01658     if (fclose(fp) != 0)
01659     {
01660         return JWSC_EIO(strerror(errno));
01661     }
01662 
01663     return NULL;
01664 }
01665