JWS C Library
C language utility library
surface.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 
00051 #include <jwsc/config.h>
00052 
00053 #include <stdlib.h>
00054 #include <stdio.h>
00055 #include <inttypes.h>
00056 #include <assert.h>
00057 #include <math.h>
00058 #include <string.h>
00059 #include <errno.h>
00060 
00061 #include "jwsc/base/error.h"
00062 #include "jwsc/vector/vector.h"
00063 #include "jwsc/vector/vector_math.h"
00064 #include "jwsc/matblock/matblock.h"
00065 #include "jwsc/matblock/matblock_fft.h"
00066 #include "jwsc/matblock/matblock_conv.h"
00067 #include "jwsc/filter/3d.h"
00068 #include "jwsc/prob/pmf.h"
00069 #include "jwsc/imgblock/surface.h"
00070 
00071 #ifdef JWSC_HAVE_DMALLOC
00072 #include <dmalloc.h>
00073 #endif
00074 
00075 
00077 #define INV_SQRT_2 0.70710678
00078 
00079 
00081 #define INV_SQRT_3 0.57735027
00082 
00083 
00090 typedef struct
00091 {
00093     float dcol;
00094 
00096     float drow;
00097 
00099     float dmat;
00100 
00102     float mag;
00103 
00105     uint8_t marked;
00106 }
00107 Gradient_f;
00108 
00109 
00111 static Error* create_gradient_map_f
00112 (
00113     Gradient_f****    map_out, 
00114     const Matblock_f* m, 
00115     float             sigma,
00116     float             grad_mat_weight,
00117     float             grad_row_weight,
00118     float             grad_col_weight
00119 )
00120 {
00121     uint32_t num_mats, num_rows, num_cols;
00122     uint32_t mat, row, col;
00123     float    dmat, dcol, drow;
00124 
00125     Matblock_f*   gauss  = NULL;
00126     Matblock_f*   m_dmat = NULL;
00127     Matblock_f*   m_drow = NULL;
00128     Matblock_f*   m_dcol = NULL;
00129     Gradient_f*** map;
00130     Gradient_f**  map_rows;
00131     Gradient_f*   map_elts;
00132     Error*        e;
00133 
00134     num_mats = m->num_mats;
00135     num_rows = m->num_rows;
00136     num_cols = m->num_cols;
00137 
00138     assert(*map_out == NULL);
00139 
00140 #ifdef JWSC_HAVE_FFTW3F
00141     if ((e = create_3d_gaussian_dx_filter_f(&gauss, sigma, sigma, sigma,
00142                     num_mats, num_rows, num_cols)) != NULL)
00143     {
00144         return e;
00145     }
00146     shift_matblock_f(&gauss, gauss);
00147     assert(convolve_matblock_fft_f(&m_dcol, m, gauss) == NULL);
00148 
00149     if ((e = create_3d_gaussian_dy_filter_f(&gauss, sigma, sigma, sigma,
00150                     num_mats, num_rows, num_cols)) != NULL)
00151     {
00152         return e;
00153     }
00154     shift_matblock_f(&gauss, gauss);
00155     assert(convolve_matblock_fft_f(&m_drow, m, gauss) == NULL);
00156 
00157     if ((e = create_3d_gaussian_dz_filter_f(&gauss, sigma, sigma, sigma,
00158                     num_mats, num_rows, num_cols)) != NULL)
00159     {
00160         return e;
00161     }
00162     shift_matblock_f(&gauss, gauss);
00163     assert(convolve_matblock_fft_f(&m_dmat, m, gauss) == NULL);
00164 #else
00165     if ((e = create_auto_3d_gaussian_dx_filter_f(&gauss, sigma, sigma, 
00166                     sigma)) != NULL)
00167     {
00168         return e;
00169     }
00170     assert(convolve_matblock_f(&m_dcol, m, gauss) == NULL);
00171 
00172     if ((e = create_auto_3d_gaussian_dy_filter_f(&gauss, sigma, sigma, 
00173                     sigma)) != NULL)
00174     {
00175         return e;
00176     }
00177     assert(convolve_matblock_f(&m_drow, m, gauss) == NULL);
00178 
00179     if ((e = create_auto_3d_gaussian_dz_filter_f(&gauss, sigma, sigma, 
00180                     sigma)) != NULL)
00181     {
00182         return e;
00183     }
00184     assert(convolve_matblock_f(&m_dmat, m, gauss) == NULL);
00185 #endif
00186 
00187     free_matblock_f(gauss);
00188 
00189     assert(map_elts = malloc(num_mats*num_rows*num_cols * sizeof(Gradient_f)));
00190     assert(map_rows = malloc(num_mats*num_rows*sizeof(Gradient_f*)));
00191     assert(*map_out = malloc(num_mats*sizeof(Gradient_f**)));
00192     map = *map_out;
00193 
00194     for (mat = 0; mat < num_mats; mat++)
00195     {
00196         map[ mat ] = &(map_rows[ mat*num_rows ]);
00197 
00198         for (row = 0; row < num_rows; row++)
00199         {
00200             map[ mat ][ row ] = &(map_elts[ (row+mat*num_rows)*num_cols ]);
00201         }
00202     }
00203 
00204     for (mat = 0; mat < num_mats; mat++)
00205     {
00206         for (row = 0; row < num_rows; row++)
00207         {
00208             for (col = 0; col < num_cols; col++)
00209             {
00210                 dcol = m_dcol->elts[ mat ][ row ][ col ];
00211                 drow = m_drow->elts[ mat ][ row ][ col ];
00212                 dmat = m_dmat->elts[ mat ][ row ][ col ];
00213 
00214                 map[ mat ][ row ][ col ].dcol = dcol;
00215                 map[ mat ][ row ][ col ].drow = drow;
00216                 map[ mat ][ row ][ col ].dmat = dmat;
00217                 map[ mat ][ row ][ col ].mag  = sqrt(grad_col_weight*dcol*dcol +
00218                                                      grad_row_weight*drow*drow +
00219                                                      grad_mat_weight*dmat*dmat);
00220                 map[ mat ][ row ][ col ].marked = 0;
00221 
00222                 if (map[ mat ][ row ][ col ].mag >= 1.0e-8)
00223                 {
00224                     map[ mat ][ row ][ col ].dcol /= 
00225                         map[ mat ][ row ][ col ].mag;
00226                     map[ mat ][ row ][ col ].drow /= 
00227                         map[ mat ][ row ][ col ].mag;
00228                     map[ mat ][ row ][ col ].dmat /= 
00229                         map[ mat ][ row ][ col ].mag;
00230                 }
00231             }
00232         }
00233     }
00234 
00235     free_matblock_f(m_dcol);
00236     free_matblock_f(m_drow);
00237     free_matblock_f(m_dmat);
00238 
00239     return NULL;
00240 }
00241 
00242 
00244 static Gradient_f* follow_gradient_f
00245 (
00246     int32_t*      grad_mat_in_out, 
00247     int32_t*      grad_row_in_out, 
00248     int32_t*      grad_col_in_out,
00249     float         dir_x,
00250     float         dir_y,
00251     float         dir_z,
00252     Gradient_f*** map,
00253     uint32_t      num_mats,
00254     uint32_t      num_rows,
00255     uint32_t      num_cols
00256 )
00257 {
00258     static const int neighbor_positions[ 26 ][ 3 ] = {
00259         {1,0,1},{1,1,1},{0,1,1},{-1,1,1},{-1,0,1},{-1,-1,1},{0,-1,1},{1,-1,1},
00260         {0,0,1},{1,0,0},{1,1,0},{0,1,0},{-1,1,0},{-1,0,0},{-1,-1,0},{0,-1,0},
00261         {1,-1,0},{1,0,-1},{1,1,-1},{0,1,-1},{-1,1,-1},{-1,0,-1},{-1,-1,-1},
00262         {0,-1,-1},{1,-1,-1},{0,0,-1} };
00263     static const float neighbor_vectors[ 26 ][ 3 ] = {
00264         {INV_SQRT_2,0,INV_SQRT_2}, {INV_SQRT_3,INV_SQRT_3,INV_SQRT_3}, 
00265         {0,INV_SQRT_2,INV_SQRT_2}, {-INV_SQRT_3,INV_SQRT_3,INV_SQRT_3},
00266         {-INV_SQRT_2,0,INV_SQRT_2}, {-INV_SQRT_3,-INV_SQRT_3,INV_SQRT_3},
00267         {0,-INV_SQRT_2,INV_SQRT_2}, {INV_SQRT_3,-INV_SQRT_3,INV_SQRT_3},
00268         {0,0,1}, {1,0,0}, {INV_SQRT_2,INV_SQRT_2,0}, {0,1,0},
00269         {-INV_SQRT_2,INV_SQRT_2,0}, {-1,0,0}, {-INV_SQRT_2,-INV_SQRT_2,0},
00270         {0,-1,0}, {INV_SQRT_2,-INV_SQRT_2,0}, {INV_SQRT_2,0,-INV_SQRT_2},
00271         {INV_SQRT_3,INV_SQRT_3,-INV_SQRT_3}, {0,INV_SQRT_2,-INV_SQRT_2},
00272         {-INV_SQRT_3,INV_SQRT_3,-INV_SQRT_3}, {-INV_SQRT_2,0,-INV_SQRT_2}, 
00273         {-INV_SQRT_3,-INV_SQRT_3,-INV_SQRT_3}, {0,-INV_SQRT_2,-INV_SQRT_2},
00274         {INV_SQRT_3,-INV_SQRT_3,-INV_SQRT_3},{0,0,-1} };
00275 
00276     uint16_t i;
00277     uint16_t max_neighbor;
00278     int32_t  grad_col, grad_row, grad_mat;
00279     float    max_dp;
00280     float    dp;
00281 
00282     Gradient_f* grad;
00283 
00284     grad_col = *grad_col_in_out;
00285     grad_row = *grad_row_in_out;
00286     grad_mat = *grad_mat_in_out;
00287     
00288     grad         = &(map[ grad_mat ][ grad_row ][ grad_col ]);
00289     max_neighbor = 0;
00290     max_dp       = dir_x * neighbor_vectors[ 0 ][ 0 ] +
00291                    dir_y * neighbor_vectors[ 0 ][ 1 ] +
00292                    dir_z * neighbor_vectors[ 0 ][ 2 ];
00293 
00294     for (i = 1; i < 26; i++)
00295     {
00296         dp = dir_x * neighbor_vectors[ i ][ 0 ] +
00297              dir_y * neighbor_vectors[ i ][ 1 ] +
00298              dir_z * neighbor_vectors[ i ][ 2 ];
00299 
00300         /* Should have some stochastic tie-breaker here. */
00301         if (dp >= max_dp)
00302         {
00303             max_dp = dp;
00304             max_neighbor = i;
00305         }
00306     }
00307 
00308     grad_mat += neighbor_positions[ max_neighbor ][ 2 ];
00309     grad_row += neighbor_positions[ max_neighbor ][ 1 ];
00310     grad_col += neighbor_positions[ max_neighbor ][ 0 ];
00311 
00312     if (grad_mat == -1) 
00313         grad_mat = 0;
00314     else if (grad_mat == num_mats) 
00315         grad_mat = num_mats-1;
00316    
00317     if (grad_row == -1) 
00318         grad_row = 0;
00319     else if (grad_row == num_rows) 
00320         grad_row = num_rows-1;
00321    
00322     if (grad_col == -1) 
00323         grad_col = 0;
00324     else if (grad_col == num_cols) 
00325         grad_col = num_cols-1;
00326 
00327     *grad_col_in_out = grad_col;
00328     *grad_row_in_out = grad_row;
00329     *grad_mat_in_out = grad_mat;
00330 
00331     return &map[ grad_mat ][ grad_row ][ grad_col ];
00332 }
00333 
00334 
00336 static Gradient_f* get_maximal_along_gradient_f
00337 (
00338     int32_t*      grad_mat_in_out, 
00339     int32_t*      grad_row_in_out, 
00340     int32_t*      grad_col_in_out, 
00341     Gradient_f*** map,
00342     uint32_t      num_mats,
00343     uint32_t      num_rows,
00344     uint32_t      num_cols
00345 ) 
00346 {
00347     int32_t grad_mat, grad_row, grad_col;
00348     int32_t curr_grad_mat, curr_grad_row, curr_grad_col;
00349     int32_t next_grad_mat, next_grad_row, next_grad_col;
00350     int32_t prev_grad_mat, prev_grad_row, prev_grad_col;
00351 
00352     Gradient_f* curr_grad;
00353     Gradient_f* next_grad;
00354     Gradient_f* prev_grad;
00355     Gradient_f* max_grad;
00356 
00357     grad_mat = *grad_mat_in_out;
00358     grad_row = *grad_row_in_out;
00359     grad_col = *grad_col_in_out;
00360 
00361     curr_grad_mat = grad_mat;
00362     curr_grad_row = grad_row;
00363     curr_grad_col = grad_col;
00364     curr_grad     = &map[ curr_grad_mat ][ curr_grad_row ][ curr_grad_col ];
00365 
00366     prev_grad_mat = curr_grad_mat;
00367     prev_grad_row = curr_grad_row;
00368     prev_grad_col = curr_grad_col;
00369     prev_grad     = follow_gradient_f(&prev_grad_mat, &prev_grad_row, 
00370                                       &prev_grad_col, -(curr_grad->dcol), 
00371                                       -(curr_grad->drow), -(curr_grad->dmat), 
00372                                       map, num_mats, num_rows, num_cols);
00373 
00374     next_grad_mat = curr_grad_mat;
00375     next_grad_row = curr_grad_row;
00376     next_grad_col = curr_grad_col;
00377     next_grad     = follow_gradient_f(&next_grad_mat, &next_grad_row, 
00378                                       &next_grad_col, curr_grad->dcol, 
00379                                       curr_grad->drow, curr_grad->dmat, map, 
00380                                       num_mats, num_rows, num_cols);
00381 
00382     max_grad = NULL;
00383     while (max_grad == NULL)
00384     {
00385         if (curr_grad->mag >= next_grad->mag &&
00386             curr_grad->mag >= prev_grad->mag)
00387         {
00388             max_grad = curr_grad;
00389         }
00390         else if (curr_grad->mag >= prev_grad->mag)
00391         {
00392             curr_grad_mat = next_grad_mat;
00393             curr_grad_row = next_grad_row;
00394             curr_grad_col = next_grad_col;
00395             curr_grad     = next_grad;
00396         }
00397         else
00398         {
00399             curr_grad_mat = prev_grad_mat;
00400             curr_grad_row = prev_grad_row;
00401             curr_grad_col = prev_grad_col;
00402             curr_grad     = prev_grad;
00403         }
00404 
00405         prev_grad_mat = curr_grad_mat;
00406         prev_grad_row = curr_grad_row;
00407         prev_grad_col = curr_grad_col;
00408         prev_grad     = follow_gradient_f(&prev_grad_mat, &prev_grad_row, 
00409                                           &prev_grad_col, -(curr_grad->dcol), 
00410                                           -(curr_grad->drow), 
00411                                           -(curr_grad->dmat), map, 
00412                                           num_mats, num_rows, num_cols);
00413 
00414         next_grad_mat = curr_grad_mat;
00415         next_grad_row = curr_grad_row;
00416         next_grad_col = curr_grad_col;
00417         next_grad     = follow_gradient_f(&next_grad_mat, &next_grad_row, 
00418                                           &next_grad_col, curr_grad->dcol, 
00419                                           curr_grad->drow, curr_grad->dmat, 
00420                                           map, num_mats, num_rows, num_cols);
00421     }
00422 
00423     *grad_mat_in_out = curr_grad_mat;
00424     *grad_row_in_out = curr_grad_row;
00425     *grad_col_in_out = curr_grad_col;
00426 
00427     return max_grad;
00428 }
00429 
00430 
00437 static void follow_surface_f
00438 (
00439     Gradient_f*   grad,
00440     int32_t       grad_mat,
00441     int32_t       grad_row,
00442     int32_t       grad_col, 
00443     Gradient_f*** map,
00444     uint32_t      num_mats,
00445     uint32_t      num_rows,
00446     uint32_t      num_cols,
00447     float         end_thresh
00448 )
00449 {
00450     /* Vectors orthogonal to the z-axis. */
00451     static const float orthogonal_vectors[ 8 ][ 3 ] = {
00452         {1,0,0}, {INV_SQRT_2,INV_SQRT_2,0},{0,1,0}, {-INV_SQRT_2,INV_SQRT_2,0},
00453         {-1,0,0}, {-INV_SQRT_2,-INV_SQRT_2,0}, {0,-1,0},
00454         {INV_SQRT_2,-INV_SQRT_2,0} };
00455 
00456     uint8_t i;
00457     float   x, y, z;
00458     float   ortho_x, ortho_y, ortho_z;
00459     float   sin_psi, cos_psi;
00460     float   sin_theta, cos_theta;
00461     float   mag_xy;
00462 
00463     Gradient_f* grad_to_follow = NULL;
00464 
00465     /* psi used to rotate around z-axis to put vector on the yz-plane. */
00466     mag_xy = sqrt(grad->dcol*grad->dcol +
00467                   grad->drow*grad->drow);
00468     if (mag_xy > 1.0e-8)
00469     {
00470         cos_psi = grad->drow / mag_xy;
00471         sin_psi = grad->dcol / mag_xy;
00472     }
00473     else
00474     {
00475         cos_psi = 0.0;
00476         sin_psi = 1.0;
00477     }
00478 
00479     /* theta used to rotate around x-axis to put vector onto the z-axis. */
00480     cos_theta = grad->dmat;
00481     sin_theta = mag_xy;
00482 
00483     /* Rotate each orthogonal vector and follow the gradient in that 
00484      * direction. */
00485     for (i = 0; i < 8; i++)
00486     {
00487         ortho_x = orthogonal_vectors[ i ][ 0 ];
00488         ortho_y = orthogonal_vectors[ i ][ 1 ];
00489         ortho_z = orthogonal_vectors[ i ][ 2 ];
00490 
00491         /* Rotate the orthagonals. */
00492         x = cos_psi*ortho_x + cos_theta*sin_psi*ortho_y + 
00493             sin_theta*sin_psi*ortho_z;
00494         y = -sin_psi*ortho_x + cos_theta*cos_psi*ortho_y + 
00495             cos_psi*sin_theta*ortho_z;
00496         z = -sin_theta*ortho_y + cos_theta*ortho_z;
00497     
00498         follow_gradient_f(&grad_mat, &grad_row, &grad_col, x, y, z, map, 
00499                 num_mats, num_rows, num_cols);
00500 
00501         grad_to_follow = get_maximal_along_gradient_f(&grad_mat, &grad_row, 
00502                 &grad_col, map, num_mats, num_rows, num_cols);
00503 
00504         if (!grad_to_follow->marked && grad_to_follow->mag >= end_thresh &&
00505                 grad_mat > 0 && grad_mat < num_mats-1 &&
00506                 grad_row > 0 && grad_row < num_rows-1 &&
00507                 grad_col > 0 && grad_col < num_cols-1)
00508         {
00509             grad_to_follow->marked = 1;
00510 
00511             follow_surface_f(grad_to_follow, grad_mat, grad_row, grad_col, 
00512                     map, num_mats, num_rows, num_cols, end_thresh);
00513         }
00514     }
00515 }
00516 
00517 
00524 static void get_surface_points_from_gradient_map_f
00525 (
00526     Surface_point_f** pts_out,
00527     uint32_t*         num_pts_out,
00528     const Matblock_f* m,
00529     Gradient_f***     map, 
00530     uint32_t          num_mats,
00531     uint32_t          num_rows, 
00532     uint32_t          num_cols,
00533     float             begin_thresh, 
00534     float             end_thresh
00535 )
00536 {
00537     int32_t  grad_mat;
00538     int32_t  grad_row;
00539     int32_t  grad_col;
00540     uint32_t mat, row, col;
00541     uint32_t num_pts;
00542 
00543     Gradient_f*      grad;
00544     Gradient_f*      max_grad;
00545     Surface_point_f* pts;
00546 
00547     for (mat = 0; mat < num_mats; mat++)
00548     {
00549         for (row = 0; row < num_rows; row++)
00550         {
00551             for (col = 0; col < num_cols; col++)
00552             {
00553                 grad = &map[ mat ][ row ][ col ];
00554 
00555                 if (!grad->marked && grad->mag >= begin_thresh)
00556                 {
00557                     grad_mat = mat;
00558                     grad_row = row;
00559                     grad_col = col;
00560 
00561                     max_grad = get_maximal_along_gradient_f(&grad_mat, 
00562                             &grad_row, &grad_col, map, num_mats, num_rows, 
00563                             num_cols);
00564 
00565                     if (!max_grad->marked &&
00566                             grad_mat > 0 && grad_mat < num_mats-1 &&
00567                             grad_row > 0 && grad_row < num_rows-1 &&
00568                             grad_col > 0 && grad_col < num_cols-1)
00569                     {
00570                         max_grad->marked = 1;
00571 
00572                         follow_surface_f(max_grad, grad_mat, grad_row, 
00573                                 grad_col, map, num_mats, num_rows, num_cols, 
00574                                 end_thresh);
00575                     }
00576                 }
00577             }
00578         }
00579     }
00580 
00581     num_pts = 0;
00582     for (mat = 0; mat < num_mats; mat++)
00583     {
00584         for (row = 0; row < num_rows; row++)
00585         {
00586             for (col = 0; col < num_cols; col++)
00587             {
00588                 if (map[ mat ][ row ][ col ].marked)
00589                 {
00590                     num_pts++;
00591                 }
00592             }
00593         }
00594     }
00595 
00596     *num_pts_out = num_pts;
00597     *pts_out = realloc(*pts_out, num_pts*sizeof(Surface_point_f));
00598     if (num_pts > 0) assert(*pts_out);
00599     pts = *pts_out;
00600 
00601     for (mat = 0; mat < num_mats; mat++)
00602     {
00603         for (row = 0; row < num_rows; row++)
00604         {
00605             for (col = 0; col < num_cols; col++)
00606             {
00607                 grad = &map[ mat ][ row ][ col ];
00608                 if (grad->marked)
00609                 {
00610                     pts->mat       = mat;
00611                     pts->row       = row;
00612                     pts->col       = col;
00613                     pts->dcol      = grad->dcol * grad->mag;
00614                     pts->drow      = grad->drow * grad->mag;
00615                     pts->dmat      = grad->dmat * grad->mag;
00616                     pts->intensity = m->elts[ mat ][ row ][ col ];
00617                     pts++;
00618                 }
00619             }
00620         }
00621     }
00622 }
00623 
00624 
00625 
00626 
00672 Error* detect_imgblock_surface_points_f
00673 (
00674     Surface_point_f** r_pts_out,
00675     uint32_t*         num_r_pts_out,
00676     Surface_point_f** g_pts_out,
00677     uint32_t*         num_g_pts_out,
00678     Surface_point_f** b_pts_out,
00679     uint32_t*         num_b_pts_out,
00680     const Imgblock_f* img,
00681     float             sigma, 
00682     float             grad_img_weight,
00683     float             grad_row_weight,
00684     float             grad_col_weight,
00685     float             begin_thresh, 
00686     float             end_thresh
00687 )
00688 {
00689     Matblock_f* m = NULL;
00690     Error*      e;
00691 
00692     create_matblock_from_imgblock_f(&m, img, 1.0, 0.0, 0.0);
00693     if ((e = detect_matblock_surface_points_f(r_pts_out, num_r_pts_out, m, 
00694                     sigma, grad_img_weight, grad_row_weight, grad_col_weight,
00695                     begin_thresh, end_thresh)) != NULL)
00696     {
00697         return e;
00698     }
00699 
00700     create_matblock_from_imgblock_f(&m, img, 0.0, 1.0, 0.0);
00701     if ((e = detect_matblock_surface_points_f(g_pts_out, num_g_pts_out, m, 
00702                     sigma, grad_img_weight, grad_row_weight, grad_col_weight,
00703                     begin_thresh, end_thresh)) != NULL)
00704     {
00705         return e;
00706     }
00707 
00708     create_matblock_from_imgblock_f(&m, img, 0.0, 0.0, 1.0);
00709     if ((e = detect_matblock_surface_points_f(b_pts_out, num_b_pts_out, m, 
00710                     sigma, grad_img_weight, grad_row_weight, grad_col_weight,
00711                     begin_thresh, end_thresh)) != NULL)
00712     {
00713         return e;
00714     }
00715 
00716     free_matblock_f(m);
00717     
00718     return NULL;
00719 }
00720 
00760 Error* detect_matblock_surface_points_f
00761 (
00762     Surface_point_f** pts_out,
00763     uint32_t*         num_pts_out,
00764     const Matblock_f* m,
00765     float             sigma, 
00766     float             grad_mat_weight,
00767     float             grad_row_weight,
00768     float             grad_col_weight,
00769     float             begin_thresh, 
00770     float             end_thresh
00771 )
00772 {
00773     Gradient_f*** map = NULL;
00774     Error*        e;
00775 
00776     if ((e = create_gradient_map_f(&map, m, sigma, grad_mat_weight, 
00777                     grad_row_weight, grad_col_weight)) != NULL)
00778     {
00779         free(*pts_out); *pts_out = NULL;
00780         return e;
00781     }
00782 
00783     get_surface_points_from_gradient_map_f(pts_out, num_pts_out, m, map, 
00784             m->num_mats, m->num_rows, m->num_cols, begin_thresh, end_thresh);
00785 
00786     free(**map);
00787     free(*map);
00788     free(map);
00789 
00790     return NULL;
00791 }
00792 
00817 void sample_surface_points_f
00818 (
00819     Surface_point_f**      pts_out, 
00820     uint32_t*              num_pts_out,
00821     const Surface_point_f* pts_in, 
00822     uint32_t               num_pts_in,
00823     float                  p
00824 )
00825 {
00826     uint32_t         num_pts;
00827     uint32_t         pt;
00828     Surface_point_f* pts;
00829 
00830     *pts_out = realloc(*pts_out, num_pts_in*sizeof(Surface_point_f));
00831     if (num_pts_in < 0) assert(*pts_out);
00832 
00833     pts     = *pts_out;
00834     num_pts = 0;
00835 
00836     for (pt = 0; pt < num_pts_in; pt++)
00837     {
00838         if (sample_bernoulli_pmf_d(p))
00839         {
00840             pts->mat       = pts_in[ pt ].mat;
00841             pts->row       = pts_in[ pt ].row;
00842             pts->col       = pts_in[ pt ].col;
00843             pts->dcol      = pts_in[ pt ].dcol;
00844             pts->drow      = pts_in[ pt ].drow;
00845             pts->dmat      = pts_in[ pt ].dmat;
00846             pts->intensity = pts_in[ pt ].intensity;
00847             pts++;
00848             num_pts++;
00849         }
00850     }
00851 
00852     *pts_out = realloc(*pts_out, num_pts*sizeof(Surface_point_f));
00853     if (num_pts > 0) assert(*pts_out);
00854 
00855     *num_pts_out = num_pts;
00856 }
00857 
00878 void color_surface_points_f
00879 (
00880     Imgblock_f**           img_out,
00881     const Imgblock_f*      img_in,
00882     const Surface_point_f* pts, 
00883     uint32_t               num_pts,
00884     const Pixel_f*         pxl
00885 )
00886 {
00887     uint32_t    pt;
00888     Imgblock_f* img;
00889 
00890     copy_imgblock_f(img_out, img_in);
00891     img = *img_out;
00892 
00893     for (pt = 0; pt < num_pts; pt++)
00894     {
00895         img->pxls[ pts[ pt ].mat ][ pts[ pt ].row ][ pts[ pt ].col ] = *pxl;
00896     }
00897 }
00898 
00936 Error* read_surface_points_f
00937 (
00938     Surface_point_f** pts_out,
00939     uint32_t*         num_pts_out,
00940     const char*       fname
00941 )
00942 {
00943     uint32_t num_pts;
00944     uint32_t p;
00945     FILE*    fp;
00946 
00947     Surface_point_f* pts;
00948     Surface_point_f* pt;
00949 
00950     if ((fp = fopen(fname, "r")) == NULL)
00951     {
00952         free(*pts_out); *pts_out = NULL;
00953         return JWSC_EIO(strerror(errno));
00954     }
00955 
00956     if (fscanf(fp, "num_pts=%u\n", &num_pts) != 1)
00957     {
00958         free(*pts_out); *pts_out = NULL;
00959         return JWSC_EARG("File not properly formatted to read surface points");
00960     }
00961 
00962     *num_pts_out = num_pts;
00963     *pts_out = realloc(*pts_out, num_pts*sizeof(Surface_point_f));
00964     if (num_pts > 0) assert(*pts_out);
00965     pts = *pts_out;
00966 
00967     for (p = 0; p < num_pts; p++)
00968     {
00969         pt = &((*pts_out)[ p ]);
00970 
00971         if (fscanf(fp, "col=%u row=%u mat=%u dcol=%f drow=%f dmat=%f intensity=%f\n", 
00972                     &(pt->col), &(pt->row), &(pt->mat),
00973                     &(pt->dcol), &(pt->drow), &(pt->dmat), 
00974                     &(pt->intensity)) != 7)
00975         {
00976             free(*pts_out); *pts_out = NULL;
00977             return JWSC_EARG("Surface points file not properly formatted");
00978         }
00979     }
00980 
00981     if (fclose(fp) != 0)
00982     {
00983         free(*pts_out); *pts_out = NULL;
00984         return JWSC_EIO(strerror(errno));
00985     }
00986 
00987     return NULL;
00988 }
00989 
01022 Error* write_surface_points_f
01023 (
01024     const Surface_point_f* pts,
01025     uint32_t               num_pts,
01026     const char*            fname
01027 )
01028 {
01029     uint32_t p;
01030     FILE*    fp;
01031 
01032     const Surface_point_f* pt;
01033 
01034     if ((fp = fopen(fname, "w")) == NULL)
01035     {
01036         return JWSC_EIO(strerror(errno));
01037     }
01038 
01039     fprintf(fp, "num_pts=%u\n", num_pts);
01040 
01041     for (p = 0; p < num_pts; p++)
01042     {
01043         pt = &(pts[ p ]);
01044 
01045         fprintf(fp, "col=%u row=%u mat=%u", pt->col, pt->row, pt->mat);
01046         fprintf(fp, " dcol=%f drow=%f dmat=%f", pt->dcol, pt->drow, pt->dmat);
01047         fprintf(fp, " intensity=%f\n", pt->intensity);
01048     }
01049 
01050     if (fclose(fp) != 0)
01051     {
01052         return JWSC_EIO(strerror(errno));
01053     }
01054 
01055     return NULL;
01056 }
01057 
01080 void create_surface_patch_f
01081 (
01082     Surface_patch_f**      patch_out,
01083     const Surface_point_f* point,
01084     float                  size,
01085     float                  x_scale,
01086     float                  y_scale,
01087     float                  z_scale
01088 )
01089 {
01090     double mag_xy;
01091     double cos_psi, sin_psi;
01092     double cos_theta, sin_theta;
01093     double pt_x, pt_y, pt_z;
01094     double rot_pt_x, rot_pt_y, rot_pt_z;
01095 
01096     uint32_t i;
01097 
01098     Surface_patch_f* patch;
01099 
01100     if (*patch_out == NULL)
01101     {
01102         assert(*patch_out = malloc(sizeof(Surface_patch_f)));
01103         for (i = 0; i < 4; i++)
01104         {
01105             (*patch_out)->pts[i] = NULL;
01106             create_vector_f(&((*patch_out)->pts[i]), 3);
01107         }
01108         (*patch_out)->normal = NULL;
01109         (*patch_out)->center = NULL;
01110         create_vector_f(&((*patch_out)->normal), 3);
01111         create_vector_f(&((*patch_out)->center), 3);
01112     }
01113     patch = *patch_out;
01114 
01115     patch->albedo = point->intensity;
01116 
01117     patch->center->elts[0] = point->col;
01118     patch->center->elts[1] = point->row;
01119     patch->center->elts[2] = point->mat;
01120 
01121     patch->normal->elts[0] = point->dcol;
01122     patch->normal->elts[1] = point->drow;
01123     patch->normal->elts[2] = point->dmat;
01124     normalize_vector_mag_f(&(patch->normal), patch->normal);
01125 
01126     /* Patch's starting orientation is centered at the origin on the x,y
01127      * plane. */
01128     patch->pts[0]->elts[0] = size; 
01129     patch->pts[0]->elts[1] = size; 
01130     patch->pts[0]->elts[2] = 0;
01131 
01132     patch->pts[1]->elts[0] = size; 
01133     patch->pts[1]->elts[1] =-size; 
01134     patch->pts[1]->elts[2] = 0;
01135 
01136     patch->pts[2]->elts[0] =-size; 
01137     patch->pts[2]->elts[1] =-size; 
01138     patch->pts[2]->elts[2] = 0;
01139 
01140     patch->pts[3]->elts[0] =-size; 
01141     patch->pts[3]->elts[1] = size; 
01142     patch->pts[3]->elts[2] = 0;
01143 
01144     /* Transorm the patch points according to the center and normal. */
01145 
01146     /* 1. The points on the patch need to be rotated by the normal vector.
01147      * psi used to rotate around z-axis to put points on the yz-plane. */
01148     mag_xy = sqrt(patch->normal->elts[0]*patch->normal->elts[0] +
01149                   patch->normal->elts[1]*patch->normal->elts[1]);
01150     if (mag_xy > 1.0e-8)
01151     {
01152         cos_psi = patch->normal->elts[1] / mag_xy;
01153         sin_psi = patch->normal->elts[0] / mag_xy;
01154     }
01155     else
01156     {
01157         cos_psi = 0.0;
01158         sin_psi = 1.0;
01159     }
01160 
01161     /* 2. Theta used to rotate around x-axis to put points onto the z-axis. */
01162     cos_theta = patch->normal->elts[2];
01163     sin_theta = mag_xy;
01164 
01165     /* Transform the patch points. */
01166     for (i = 0; i < 4; i++)
01167     {
01168         /* Rotate. */
01169         pt_x = patch->pts[ i ]->elts[0];
01170         pt_y = patch->pts[ i ]->elts[1];
01171         pt_z = patch->pts[ i ]->elts[2];
01172 
01173         rot_pt_x = cos_psi*pt_x + cos_theta*sin_psi*pt_y + 
01174                    sin_theta*sin_psi*pt_z;
01175         rot_pt_y = -sin_psi*pt_x + cos_theta*cos_psi*pt_y + 
01176                    cos_psi*sin_theta*pt_z;
01177         rot_pt_z = -sin_theta*pt_y + cos_theta*pt_z;
01178 
01179         patch->pts[ i ]->elts[0] = rot_pt_x;
01180         patch->pts[ i ]->elts[1] = rot_pt_y;
01181         patch->pts[ i ]->elts[2] = rot_pt_z;
01182 
01183         /* Translate. */
01184         add_vectors_f(&(patch->pts[ i ]), patch->pts[ i ], patch->center);
01185 
01186         /* Scale. */
01187         patch->pts[ i ]->elts[0] *= x_scale;
01188         patch->pts[ i ]->elts[1] *= y_scale;
01189         patch->pts[ i ]->elts[2] *= z_scale;
01190     }
01191 
01192     /* Finally, scale the position of the center point. */
01193     patch->center->elts[0] *= x_scale;
01194     patch->center->elts[1] *= y_scale;
01195     patch->center->elts[2] *= z_scale;
01196 }
01197 
01211 void free_surface_patch_f(Surface_patch_f* patch)
01212 {
01213     free_vector_f(patch->pts[0]);
01214     free_vector_f(patch->pts[1]);
01215     free_vector_f(patch->pts[2]);
01216     free_vector_f(patch->pts[3]);
01217     free_vector_f(patch->normal);
01218     free_vector_f(patch->center);
01219     free(patch);
01220 }
01221