简体   繁体   中英

2D Convolution for JavaScript Arrays

I am fairly new to JavaScript. I am trying to implement the 2D convolution described at http://www.songho.ca/dsp/convolution/convolution.html for C in JavaScript for a web app.

function conv_2d(kernel, array){
    var result = uniform_array(array.length, uniform_array(array[0].length, 0));
    var kRows = kernel.length;
    var kCols = kernel[0].length;
    var rows = array.length;
    var cols = array[0].length;
    // find center position of kernel (half of kernel size)
    var kCenterX = Math.floor(kCols/2);
    var kCenterY = Math.floor(kRows/2);
    var i, j, m, n, mm, nn;

    for(i=0; i < rows; ++i){          // for all rows
        for(j=0; j < cols; ++j){          // for all columns
            for(m=0; m < kRows; ++m){         // for all kernel rows
                for(n=0; n < kCols; ++n){        // for all kernel columns
                    // index of input signal, used for checking boundary
                    var ii = i + (m - kCenterY);
                    var jj = j + (n - kCenterX);
                    // ignore input samples which are out of bound
                    if(ii >= 0 && ii < rows && jj >= 0 && jj < cols){
                        result[i][j] += array[ii][jj] * kernel[m][n];
                    };
                };
            };
        };
    };
    return result;
};

function uniform_array(len, value) {
    let arr = new Array(len); for (let i=0; i<len; ++i) arr[i] = value;
    return arr;
}

Now, I have tried to look at what I am doing wrong, but I can't find the error. What I know is, applying the 2D convolution for the same pair of matrices, the result in javascript gives me the sum of all the rows for each row in the output matrix. I have found that comparing to the output in C++:

JavaScript output:

0: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
1: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
2: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
3: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
4: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
5: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
6: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
7: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]
8: (9) [75, 150, 225, 300, 375, 450, 525, 600, 425]

C++ Output (correct):

     6    12    18    24    30    36    42    48    34
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     9    18    27    36    45    54    63    72    51
     6    12    18    24    30    36    42    48    34

This result comes from the convolution of a uniform 3x3 kernel and a matrix which is:

0: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
1: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
2: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
3: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
4: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
5: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
6: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
7: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]
8: (9) [1, 2, 3, 4, 5, 6, 7, 8, 9]

Any help will be really appreciated!

Does this look right? I changed uniform_array to make it create new arrays rather than pointing to the same one for every row.

 const array = [ [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], [1, 2, 3, 4, 5, 6, 7, 8, 9], ]; const kernel = [ [1,1,1], [1,1,1], [1,1,1], ]; function uniform_array(len, value) { let arr = new Array(len); for (let i=0; i<len; ++i) arr[i] = Array.isArray(value) ? [...value] : value; return arr; } function conv_2d(kernel, array){ var result = uniform_array(array.length, uniform_array(array[0].length, 0)); var kRows = kernel.length; var kCols = kernel[0].length; var rows = array.length; var cols = array[0].length; // find center position of kernel (half of kernel size) var kCenterX = Math.floor(kCols/2); var kCenterY = Math.floor(kRows/2); var i, j, m, n, ii, jj; for(i=0; i < rows; ++i){ // for all rows for(j=0; j < cols; ++j){ // for all columns for(m=0; m < kRows; ++m){ // for all kernel rows for(n=0; n < kCols; ++n){ // for all kernel columns // index of input signal, used for checking boundary ii = i + (m - kCenterY); jj = j + (n - kCenterX); // ignore input samples which are out of bound if(ii >= 0 && ii < rows && jj >= 0 && jj < cols){ result[i][j] += array[ii][jj] * kernel[m][n]; }; }; }; }; }; return result; }; conv_2d(kernel, array).forEach(row => console.log(row.join(' ')));

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM