JWS C Library
C language utility library
image_util.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 
00046 #include <jwsc/config.h>
00047 
00048 #include <stdlib.h>
00049 #include <inttypes.h>
00050 #include <math.h>
00051 #include <assert.h>
00052 
00053 #include "jwsc/base/error.h"
00054 #include "jwsc/matrix/matrix.h"
00055 #include "jwsc/filter/2d.h"
00056 #include "jwsc/image/image.h"
00057 #include "jwsc/image/image_util.h"
00058 
00059 
00086 Error* down_sample_image_f
00087 (
00088     Image_f**      img_out, 
00089     const Image_f* img_in, 
00090     float          row_factor,
00091     float          col_factor
00092 )
00093 {
00094     int64_t num_in_rows, num_in_cols;
00095     int64_t num_out_rows, num_out_cols;
00096     int64_t num_h_rows, num_h_cols;
00097     int64_t in_row, in_col;
00098     int64_t out_row, out_col;
00099     int64_t h_row, h_col;
00100     int64_t h_row_center;
00101     int64_t h_col_center;
00102     int64_t i, j;
00103 
00104     float col_delta_sum, row_delta_sum;
00105     float r_sum, g_sum, b_sum;
00106     float row_delta;
00107     float col_delta;
00108     float row_sigma;
00109     float col_sigma;
00110     float weight;
00111     float weight_sum;
00112 
00113     Image_f*   img = NULL;
00114     Matrix_f*  h   = NULL;
00115 
00116     /* Test if the factors are in (0, 1]. */
00117     if (0 >= row_factor || row_factor > 1.0 ||
00118         0 >= col_factor || col_factor > 1.0)
00119     {
00120         if (*img_out != img_in)
00121         {
00122             free_image_f(*img_out);
00123             *img_out = NULL;
00124         }
00125         return JWSC_EARG("Down sampling factors must be in (0, 1]");
00126     }
00127 
00128     num_in_rows = img_in->num_rows;
00129     num_in_cols = img_in->num_cols;
00130 
00131     num_out_rows = ceil(row_factor*num_in_rows);
00132     num_out_cols = ceil(col_factor*num_in_cols);
00133 
00134     if (num_in_rows == num_out_rows && num_in_cols == num_out_cols &&
00135             *img_out != img_in)
00136     {
00137         copy_image_f(img_out, img_in);
00138         return  NULL;
00139     }
00140 
00141     row_delta = 1.0 / row_factor;
00142     col_delta = 1.0 / col_factor;
00143 
00144     row_sigma = 0.35 * row_delta;
00145     col_sigma = 0.35 * col_delta;
00146 
00147     assert(create_auto_2d_gaussian_filter_f(&h, row_sigma, col_sigma) == NULL);
00148     num_h_rows = h->num_rows;
00149     num_h_cols = h->num_cols;
00150 
00151     img = (*img_out == img_in) ? NULL : *img_out;
00152     create_image_f(&img, num_out_rows, num_out_cols);
00153 
00154     h_row_center = num_h_rows / 2;
00155     h_col_center = num_h_cols / 2;
00156 
00157     row_delta_sum = 0.5*row_delta;
00158     in_row = ceil(row_delta_sum) - 1;
00159     for (out_row = 0; out_row < num_out_rows; out_row++)
00160     {
00161         col_delta_sum = 0.5*col_delta;
00162         in_col = ceil(col_delta_sum) - 1;
00163         for (out_col = 0; out_col < num_out_cols; out_col++)
00164         {
00165             r_sum = 0;
00166             g_sum = 0;
00167             b_sum = 0;
00168             weight_sum = 0;
00169 
00170             i = -1;
00171             j = -1;
00172 
00173             for (h_row = 0; h_row < num_h_rows; h_row++)
00174             {
00175                 for (h_col = 0; h_col < num_h_cols; h_col++)
00176                 {
00177                     i = in_row + (h_row - h_row_center);
00178                     if (i < 0)
00179                     {
00180                         i = 0;
00181                     }
00182                     else if (i >= num_in_rows)
00183                     {
00184                         i = num_in_rows - 1;
00185                     }
00186 
00187                     j = in_col + (h_col - h_col_center);
00188                     if (j < 0)
00189                     {
00190                         j = 0;
00191                     }
00192                     else if (j >= num_in_cols)
00193                     {
00194                         j = num_in_cols - 1;
00195                     }
00196 
00197                     weight = h->elts[ h_row ][ h_col ];
00198 
00199                     r_sum += img_in->pxls[ i ][ j ].r * weight;
00200                     g_sum += img_in->pxls[ i ][ j ].g * weight;
00201                     b_sum += img_in->pxls[ i ][ j ].b * weight;
00202 
00203                     weight_sum += weight;
00204                 }
00205             }
00206 
00207             if (weight_sum > 0)
00208             {
00209                 r_sum /= weight_sum;
00210                 g_sum /= weight_sum;
00211                 b_sum /= weight_sum;
00212 
00213                 img->pxls[ out_row ][ out_col ].r = r_sum;
00214                 img->pxls[ out_row ][ out_col ].g = g_sum;
00215                 img->pxls[ out_row ][ out_col ].b = b_sum;
00216             }
00217             else
00218             {
00219                 img->pxls[ out_row ][ out_col ].r = img_in->pxls[ i ][ j ].r;
00220                 img->pxls[ out_row ][ out_col ].g = img_in->pxls[ i ][ j ].g;
00221                 img->pxls[ out_row ][ out_col ].b = img_in->pxls[ i ][ j ].b;
00222             }
00223 
00224             col_delta_sum += col_delta;
00225             in_col = floor(col_delta_sum);
00226             if (in_col >= num_in_cols) 
00227                 in_col = num_in_cols - 1;
00228         }
00229 
00230         row_delta_sum += row_delta;
00231         in_row = floor(row_delta_sum);
00232         if (in_row >= num_in_rows) 
00233             in_row = num_in_rows - 1;
00234     }
00235 
00236     if (*img_out == img_in)
00237     {
00238         copy_image_f(img_out, img);
00239         free_image_f(img);
00240     }
00241     else
00242     {
00243         *img_out = img;
00244     }
00245 
00246     free_matrix_f(h);
00247 
00248     return NULL;
00249 }
00250 
00272 void extend_image_f
00273 (
00274     Image_f**      img_out, 
00275     const Image_f* img_in, 
00276     uint32_t       row_padding,
00277     uint32_t       col_padding
00278 )
00279 {
00280     uint32_t num_rows, num_cols;
00281     uint32_t num_prows, num_pcols;
00282     uint32_t prow, pcol;
00283 
00284     Image_f* img;
00285 
00286     num_rows = img_in->num_rows;
00287     num_cols = img_in->num_cols;
00288 
00289     num_prows = num_rows + 2*row_padding;
00290     num_pcols = num_cols + 2*col_padding;
00291 
00292     img = (*img_out == img_in) ? NULL : *img_out;
00293     create_image_f(&img, num_prows, num_pcols);
00294 
00295     for (prow = 0; prow < (num_prows - row_padding); prow++)
00296     {
00297         if (prow < row_padding)
00298         {
00299             for (pcol = 0; pcol < col_padding; pcol++)
00300             {
00301                 img->pxls[ prow ][ pcol ] 
00302                     = img_in->pxls[ 0 ][ 0 ];
00303 
00304                 img->pxls[ prow ][ num_pcols-pcol-1 ] 
00305                     = img_in->pxls[ 0 ][ num_cols-1 ];
00306 
00307                 img->pxls[ num_prows-prow-1 ][ pcol ] 
00308                     = img_in->pxls[ num_rows-1 ][ 0 ];
00309 
00310                 img->pxls[ num_prows-prow-1 ][ num_pcols-pcol-1 ] 
00311                     = img_in->pxls[ num_rows-1 ][ num_cols-1 ];
00312             }
00313             for (pcol = col_padding; pcol < (num_pcols-col_padding); pcol++)
00314             {
00315                 img->pxls[ prow ][ pcol ] 
00316                     = img_in->pxls[ 0 ][ pcol-col_padding ];
00317                 img->pxls[ num_prows-prow-1 ][ pcol ] 
00318                     = img_in->pxls[ num_rows-1 ][ pcol-col_padding ];
00319             }
00320         }
00321         else
00322         {
00323             for (pcol = 0; pcol < col_padding; pcol++)
00324             {
00325                 img->pxls[ prow ][ pcol ] 
00326                     = img_in->pxls[ prow-row_padding ][ 0 ];
00327                 img->pxls[ prow ][ num_pcols-pcol-1 ] 
00328                     = img_in->pxls[ prow-row_padding ][ num_cols-1 ];
00329             }
00330             for (pcol = col_padding; pcol < (num_pcols-col_padding); pcol++)
00331             {
00332                 img->pxls[ prow ][ pcol ] 
00333                     = img_in->pxls[ prow-row_padding][ pcol-col_padding ];
00334             }
00335         }
00336     }
00337 
00338     *img_out = img;
00339 }
00340 
00360 Error* crop_image_f
00361 (
00362     Image_f**      img_out, 
00363     const Image_f* img_in, 
00364     uint32_t       row,
00365     uint32_t       col,
00366     uint32_t       num_rows,
00367     uint32_t       num_cols
00368 )
00369 {
00370     uint32_t num_in_rows;
00371     uint32_t num_in_cols;
00372     uint32_t rrow, ccol;
00373     uint32_t r, c;
00374 
00375     Image_f* img = NULL;
00376 
00377     num_in_rows = img_in->num_rows;
00378     num_in_cols = img_in->num_cols;
00379 
00380     if (row == num_in_rows || col == num_in_cols ||
00381         row+num_rows > num_in_rows || col+num_cols > num_in_cols)
00382     {
00383         free_image_f(*img_out);
00384         *img_out = NULL;
00385         return JWSC_EARG("Invalid image region to crop");
00386     }
00387 
00388     img = (*img_out == img_in) ? NULL : *img_out;
00389     create_image_f(&img, num_rows, num_cols);
00390 
00391     r = 0;
00392 
00393     for (rrow = row; rrow < row+num_rows; rrow++)
00394     {
00395         c = 0;
00396 
00397         for (ccol = col; ccol < col+num_cols; ccol++)
00398         {
00399             img->pxls[ r ][ c++ ] = img_in->pxls[ rrow ][ ccol ];
00400         }
00401 
00402         r++;
00403     }
00404 
00405     if (*img_out == img_in)
00406     {
00407         copy_image_f(img_out, img);
00408     }
00409     else
00410     {
00411         *img_out = img;
00412     }
00413 
00414     return NULL;
00415 }
00416 
00437 void threshold_image_f
00438 (
00439     Matrix_f**     mat_out, 
00440     const Image_f* img_in,
00441     float          t
00442 )
00443 {
00444     create_matrix_from_image_f(mat_out, img_in, 0.3, 0.59, 0.11);
00445     threshold_matrix_f(mat_out, *mat_out, t);
00446 }
00447 
00468 void threshold_matrix_f
00469 (
00470     Matrix_f**      mat_out, 
00471     const Matrix_f* mat_in,
00472     float           t
00473 )
00474 {
00475     uint32_t row, num_rows;
00476     uint32_t col, num_cols;
00477 
00478     num_rows = mat_in->num_rows;
00479     num_cols = mat_in->num_cols;
00480 
00481     create_matrix_f(mat_out, num_rows, num_cols);
00482 
00483     for (row = 0; row < num_rows; row++)
00484     {
00485         for (col = 0; col < num_cols; col++)
00486         {
00487             if (mat_in->elts[ row ][ col ] >= t)
00488             {
00489                 (*mat_out)->elts[ row ][ col ] = 1.0f;
00490             }
00491             else
00492             {
00493                 (*mat_out)->elts[ row ][ col ] = 0.0f;
00494             }
00495         }
00496     }
00497 }
00498 
00522 void dynamically_threshold_image_f
00523 (
00524     Matrix_f**     mat_out, 
00525     const Image_f* img_in
00526 )
00527 {
00528     create_matrix_from_image_f(mat_out, img_in, 0.3, 0.59, 0.11);
00529     dynamically_threshold_matrix_f(mat_out, *mat_out);
00530 }
00531 
00555 void dynamically_threshold_matrix_f
00556 (
00557     Matrix_f**      mat_out, 
00558     const Matrix_f* mat_in
00559 )
00560 {
00561     static const float epsilon = 1.0e-12;
00562 
00563     uint32_t row, num_rows;
00564     uint32_t col, num_cols;
00565     uint32_t num_fg;
00566     uint32_t num_bg;
00567     float min, max;
00568     float x;
00569     float t;
00570     float t_prev;
00571     float mean_fg;
00572     float mean_bg;
00573 
00574     num_rows = mat_in->num_rows;
00575     num_cols = mat_in->num_cols;
00576 
00577     max = min = mat_in->elts[0][0];
00578 
00579     for (row = 0; row < num_rows; row++)
00580     {
00581         for (col = 0; col < num_cols; col++)
00582         {
00583             if (mat_in->elts[ row ][ col ] > max)
00584             {
00585                 max = mat_in->elts[ row ][ col ];
00586             }
00587             else if (mat_in->elts[ row ][ col ] < min)
00588             {
00589                 min = mat_in->elts[ row ][ col ];
00590             }
00591         }
00592     }
00593     assert((max - min) >= 0.0);
00594 
00595     t = 0.5f*(max - min) + min;
00596     t_prev = t - min;
00597 
00598     while (fabs(t - t_prev) > epsilon)
00599     {
00600         t_prev = t;
00601 
00602         num_fg = num_bg = 0;
00603         mean_fg = mean_bg = 0.0;
00604 
00605         for (row = 0; row < num_rows; row++)
00606         {
00607             for (col = 0; col < num_cols; col++)
00608             {
00609                 x = mat_in->elts[ row ][ col ];
00610 
00611                 if (x < t)
00612                 {
00613                     num_bg++;
00614                     mean_bg += x;
00615                 }
00616                 else
00617                 {
00618                     num_fg++;
00619                     mean_fg += x;
00620                 }
00621             }
00622         }
00623 
00624         if (num_bg)
00625         {
00626             mean_bg *= 1.0f / (float)num_bg;
00627         }
00628         if (num_fg)
00629         {
00630             mean_fg *= 1.0f / (float)num_fg;
00631         }
00632 
00633         t = 0.5f * (mean_fg + mean_bg);
00634     }
00635 
00636     threshold_matrix_f(mat_out, mat_in, t);
00637 }
00638