【问题标题】:2D Convolution for JavaScript ArraysJavaScript 数组的二维卷积
【发布时间】:2020-11-03 19:41:32
【问题描述】:

我对 JavaScript 相当陌生。我正在尝试为 Web 应用程序的 JavaScript 中的 C 实现 http://www.songho.ca/dsp/convolution/convolution.html 中描述的 2D 卷积。

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

现在,我试图查看我做错了什么,但我找不到错误。我所知道的是,对同一对矩阵应用 2D 卷积,javascript 中的结果为我提供了输出矩阵中每一行的所有行的总和。我发现与 C++ 中的输出相比:

JavaScript 输出:

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++ 输出(正确):

     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

这个结果来自一个统一的 3x3 内核和一个矩阵的卷积:

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]

任何帮助将不胜感激!

【问题讨论】:

  • conv_2d() 的输入是什么样的? mm和nn去哪儿了?
  • 输入是这两个数组: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]] 和内核= [[1,1,1],[1,1,1],[1,1,1]]。我删除了 mm 和 nn,因为我的计划是将它与均匀和高斯内核一起使用,它们是对称的,不需要翻转。

标签: javascript convolution


【解决方案1】:

这看起来对吗?我更改了 uniform_array 以使其创建新数组,而不是为每一行指向同一个数组。

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(' ')));

【讨论】:

  • 是的!那很完美!谢谢 :) 我没想到错误来自该功能。 mm 和 nn 只会对不对称的内核产生影响。再次感谢您!
猜你喜欢
  • 2013-10-16
  • 1970-01-01
  • 1970-01-01
  • 2021-11-12
  • 2017-02-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-09-07
相关资源
最近更新 更多