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 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