JWS C Library
C language utility library
|
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