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/matrix/matrix_math.h" 00056 #include "jwsc/matrix/matrix_fft.h" 00057 #include "jwsc/matrix/matrix_conv.h" 00058 00059 00061 #define PI 3.14159265358979323846 00062 00063 00097 Error* convolve_matrix_f 00098 ( 00099 Matrix_f** m_out, 00100 const Matrix_f* m_in, 00101 const Matrix_f* h 00102 ) 00103 { 00104 int64_t num_in_rows, num_in_cols; /* 64-bit since it's signed */ 00105 int64_t num_h_rows, num_h_cols; 00106 int64_t in_row, in_col; 00107 int64_t h_row, h_col; 00108 int64_t h_row_center; 00109 int64_t h_col_center; 00110 int64_t i, j; 00111 00112 float sum; 00113 Matrix_f* m; 00114 00115 num_in_rows = m_in->num_rows; 00116 num_in_cols = m_in->num_cols; 00117 num_h_rows = h->num_rows; 00118 num_h_cols = h->num_cols; 00119 00120 /* Test if the filter is larger than m_in. */ 00121 if (num_in_rows < num_h_rows || num_in_cols < num_h_cols) 00122 { 00123 if (*m_out != m_in) 00124 { 00125 free_matrix_f(*m_out); *m_out = NULL; 00126 } 00127 return JWSC_EARG("Convolution filter larger than input matrix"); 00128 } 00129 00130 m = (*m_out == m_in) ? NULL : *m_out; 00131 create_matrix_f(&m, num_in_rows, num_in_cols); 00132 00133 h_row_center = num_h_rows / 2; 00134 h_col_center = num_h_cols / 2; 00135 00136 for (in_row = 0; in_row < num_in_rows; in_row++) 00137 { 00138 for (in_col = 0; in_col < num_in_cols; in_col++) 00139 { 00140 sum = 0; 00141 for (h_row = 0; h_row < num_h_rows; h_row++) 00142 { 00143 for (h_col = 0; h_col < num_h_cols; h_col++) 00144 { 00145 i = in_row + (h_row - h_row_center); 00146 if (i < 0) 00147 { 00148 i = -i; 00149 } 00150 else if (i >= num_in_rows) 00151 { 00152 i = num_in_rows - (i - (num_in_rows - 1)); 00153 } 00154 00155 j = in_col + (h_col - h_col_center); 00156 if (j < 0) 00157 { 00158 j = -j; 00159 } 00160 else if (j >= num_in_cols) 00161 { 00162 j = num_in_cols - (j - (num_in_cols - 1)); 00163 } 00164 00165 sum += m_in->elts[ i ][ j ] * h->elts[ h_row ][ h_col ]; 00166 } 00167 } 00168 m->elts[ in_row ][ in_col ] = sum; 00169 } 00170 } 00171 00172 if (*m_out == m_in) 00173 { 00174 copy_matrix_f(m_out, m); 00175 free_matrix_f(m); 00176 } 00177 else 00178 { 00179 *m_out = m; 00180 } 00181 00182 return NULL; 00183 } 00184 00185 00212 Error* convolve_matrix_d 00213 ( 00214 Matrix_d** m_out, 00215 const Matrix_d* m_in, 00216 const Matrix_d* h 00217 ) 00218 { 00219 int64_t num_in_rows, num_in_cols; /* 64-bit since it's signed */ 00220 int64_t num_h_rows, num_h_cols; 00221 int64_t in_row, in_col; 00222 int64_t h_row, h_col; 00223 int64_t h_row_center; 00224 int64_t h_col_center; 00225 int64_t i, j; 00226 00227 double sum; 00228 Matrix_d* m; 00229 00230 num_in_rows = m_in->num_rows; 00231 num_in_cols = m_in->num_cols; 00232 num_h_rows = h->num_rows; 00233 num_h_cols = h->num_cols; 00234 00235 /* Test if the filter is larger than m_in. */ 00236 if (num_in_rows < num_h_rows || num_in_cols < num_h_cols) 00237 { 00238 if (*m_out != m_in) 00239 { 00240 free_matrix_d(*m_out); *m_out = NULL; 00241 } 00242 return JWSC_EARG("Convolution filter larger than input matrix"); 00243 } 00244 00245 m = (*m_out == m_in) ? NULL : *m_out; 00246 create_matrix_d(&m, num_in_rows, num_in_cols); 00247 00248 h_row_center = num_h_rows / 2; 00249 h_col_center = num_h_cols / 2; 00250 00251 for (in_row = 0; in_row < num_in_rows; in_row++) 00252 { 00253 for (in_col = 0; in_col < num_in_cols; in_col++) 00254 { 00255 sum = 0; 00256 for (h_row = 0; h_row < num_h_rows; h_row++) 00257 { 00258 for (h_col = 0; h_col < num_h_cols; h_col++) 00259 { 00260 i = in_row + (h_row - h_row_center); 00261 if (i < 0) 00262 { 00263 i = -i; 00264 } 00265 else if (i >= num_in_rows) 00266 { 00267 i = num_in_rows - (i - (num_in_rows - 1)); 00268 } 00269 00270 j = in_col + (h_col - h_col_center); 00271 if (j < 0) 00272 { 00273 j = -j; 00274 } 00275 else if (j >= num_in_cols) 00276 { 00277 j = num_in_cols - (j - (num_in_cols - 1)); 00278 } 00279 00280 sum += m_in->elts[ i ][ j ] * h->elts[ h_row ][ h_col ]; 00281 } 00282 } 00283 m->elts[ in_row ][ in_col ] = sum; 00284 } 00285 } 00286 00287 if (*m_out == m_in) 00288 { 00289 copy_matrix_d(m_out, m); 00290 free_matrix_d(m); 00291 } 00292 else 00293 { 00294 *m_out = m; 00295 } 00296 00297 return NULL; 00298 } 00299 00332 #ifdef JWSC_HAVE_FFTW3F 00333 Error* convolve_matrix_fft_f 00334 ( 00335 Matrix_f** m_out, 00336 const Matrix_f* m_in, 00337 const Matrix_f* h 00338 ) 00339 { 00340 uint32_t num_in_rows, num_in_cols; 00341 uint32_t num_h_rows, num_h_cols; 00342 Matrix_cf* dft_m_in; 00343 Matrix_cf* dft_h; 00344 00345 num_in_rows = m_in->num_rows; 00346 num_in_cols = m_in->num_cols; 00347 num_h_rows = h->num_rows; 00348 num_h_cols = h->num_cols; 00349 00350 /* Test if the filter is the same size as m_in. */ 00351 if (num_in_rows != num_h_rows || num_in_cols != num_h_cols) 00352 { 00353 if (*m_out != m_in) 00354 { 00355 free_matrix_f(*m_out); *m_out = NULL; 00356 } 00357 return JWSC_EARG("Incompatible matrix sizes for FFT convolution"); 00358 } 00359 00360 dft_m_in = NULL; 00361 dft_h = NULL; 00362 00363 real_to_complex_matrix_dft_f(&dft_m_in, m_in); 00364 real_to_complex_matrix_dft_f(&dft_h, h); 00365 assert(multiply_matrices_elt_wise_cf(&dft_m_in, dft_m_in, dft_h) == NULL); 00366 complex_to_real_matrix_dft_f(m_out, dft_m_in, (num_in_cols % 2 == 0)); 00367 scale_matrix_dft_f(m_out, *m_out); 00368 00369 free_matrix_cf(dft_m_in); 00370 free_matrix_cf(dft_h); 00371 00372 return NULL; 00373 } 00374 #endif 00375 00396 #ifdef JWSC_HAVE_FFTW3F 00397 Error* convolve_matrix_fft_d 00398 ( 00399 Matrix_d** m_out, 00400 const Matrix_d* m_in, 00401 const Matrix_d* h 00402 ) 00403 { 00404 uint32_t num_in_rows, num_in_cols; 00405 uint32_t num_h_rows, num_h_cols; 00406 Matrix_cd* dft_m_in; 00407 Matrix_cd* dft_h; 00408 00409 num_in_rows = m_in->num_rows; 00410 num_in_cols = m_in->num_cols; 00411 num_h_rows = h->num_rows; 00412 num_h_cols = h->num_cols; 00413 00414 /* Test if the filter is the same size as m_in. */ 00415 if (num_in_rows != num_h_rows || num_in_cols != num_h_cols) 00416 { 00417 if (*m_out != m_in) 00418 { 00419 free_matrix_d(*m_out); *m_out = NULL; 00420 } 00421 return JWSC_EARG("Incompatible matrix sizes for FFT convolution"); 00422 } 00423 00424 dft_m_in = NULL; 00425 dft_h = NULL; 00426 00427 real_to_complex_matrix_dft_d(&dft_m_in, m_in); 00428 real_to_complex_matrix_dft_d(&dft_h, h); 00429 assert(multiply_matrices_elt_wise_cd(&dft_m_in, dft_m_in, dft_h) == NULL); 00430 complex_to_real_matrix_dft_d(m_out, dft_m_in, (num_in_cols % 2 == 0)); 00431 scale_matrix_dft_d(m_out, *m_out); 00432 00433 free_matrix_cd(dft_m_in); 00434 free_matrix_cd(dft_h); 00435 00436 return NULL; 00437 } 00438 #endif 00439