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