JavaScript 数组的二维卷积
2D Convolution for JavaScript Arrays
我是 JavaScript 的新手。我正在尝试为 Web 应用程序在 http://www.songho.ca/dsp/convolution/convolution.html 中为 C 在 JavaScript 中实现二维卷积。
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]
任何帮助将不胜感激!
这样看起来对吗?我更改了 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(' ')));
我是 JavaScript 的新手。我正在尝试为 Web 应用程序在 http://www.songho.ca/dsp/convolution/convolution.html 中为 C 在 JavaScript 中实现二维卷积。
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]
任何帮助将不胜感激!
这样看起来对吗?我更改了 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(' ')));