在 R 中实现 MATLAB filter2 函数
Implementing the MATLAB filter2 function in R
我目前正在 R 中实现 filter2
MATLAB 函数,这是一种二维卷积的方法。我已经为 2D 卷积工作做了,但是我不太清楚 filter2 中的 'valid' 选项是如何工作的。
MATLAB函数说明如下:
http://se.mathworks.com/help/matlab/ref/filter2.html
我的实现:
filter2D <- function(img, window) {
# Algoritm for 2D Convolution
filter_center_index_y <- median(1:dim(window)[1])
filter_max_index_y <- dim(window)[1]
filter_center_index_x <- median(1:dim(window)[2])
filter_max_index_x <- dim(window)[2]
# For each position in the picture, 2D convolution is done by
# calculating a score for all overlapping values within the two matrices
x_min <- 1
x_max <- dim(img)[2]
y_min <- 1
y_max <- dim(img)[1]
df <- NULL
for (x_val in c(x_min:x_max)){
for (y_val in c(y_min:y_max)){
# Distanced from cell
img_dist_left <- x_val-1
img_dist_right <- x_max-x_val
img_dist_up <- y_val-1
img_dist_down <- y_max-y_val
# Overlapping filter cells
filter_x_start <- filter_center_index_x-img_dist_left
if (filter_x_start < 1) {
filter_x_start <- 1
}
filter_x_end <- filter_center_index_x+img_dist_right
if (filter_x_end > filter_max_index_x) {
filter_x_end <- filter_max_index_x
}
filter_y_start <- filter_center_index_y-img_dist_up
if (filter_y_start < 1) {
filter_y_start <- 1
}
filter_y_end <- filter_center_index_y+img_dist_down
if (filter_y_end > filter_max_index_y) {
filter_y_end <- filter_max_index_y
}
# Part of filter that overlaps
filter_overlap_matrix <- filter[filter_y_start:filter_y_end, filter_x_start:filter_x_end]
# Overlapped image cells
image_x_start <- x_val-filter_center_index_x+1
if (image_x_start < 1) {
image_x_start <- 1
}
image_x_end <- x_val+filter_max_index_x-filter_center_index_x
if (image_x_end > x_max) {
image_x_end <- x_max
}
image_y_start <- y_val-filter_center_index_y+1
if (image_y_start < 1) {
image_y_start <- 1
}
image_y_end <- y_val+filter_max_index_y-filter_center_index_y
if (image_y_end > y_max) {
image_y_end <- y_max
}
# Part of image that is overlapped
image_overlap_matrix <- img[image_y_start:image_y_end, image_x_start:image_x_end]
# Calculating the cell value
cell_value <- sum(filter_overlap_matrix*image_overlap_matrix)
df = rbind(df,data.frame(x_val,y_val, cell_value))
}
}
# Axis labels
x_axis <- c(x_min:x_max)
y_axis <- c(y_min:y_max)
# Populating matrix
filter_matrix <- matrix(df[,3], nrow = x_max, ncol = y_max, dimnames = list(x_axis, y_axis))
return(filter_matrix)
}
运行方法:
> image
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
[6,] 31 32 33 34 35 36
> filter
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 0 0 0
[3,] -1 -2 -1
> filter2D(image, filter)
1 2 3 4 5 6
1 -22 -32 -36 -40 -44 -35
2 -36 -48 -48 -48 -48 -36
3 -36 -48 -48 -48 -48 -36
4 -36 -48 -48 -48 -48 -36
5 -36 -48 -48 -48 -48 -36
6 76 104 108 112 116 89
这与 filter2(image, filter) 在 matlab 中产生的输出相同,但是,当添加选项 'valid' 时,会生成以下输出:
-48 -48 -48 -48
-48 -48 -48 -48
-48 -48 -48 -48
-48 -48 -48 -48
带有 'valid' 选项的 filter2 是如何生成这个的并不完全清楚。它只是使用中心值吗?还是它在做更复杂的事情?
在我开始之前,您的代码实际上是在进行 2D 相关。 2D 卷积要求在进行加权求和之前对内核执行 180 度旋转。如果内核是对称的(即内核的 t运行spose 等于其自身),则相关和卷积实际上是相同的操作 。我只是想在开始之前说清楚。此外,filter2
的文档确实说明正在执行关联。
MATLAB 中的 'valid'
选项只是意味着它应该 return 只有在执行滤波时内核与 2D 信号完全重叠的输出。因为您有一个 3 x 3 内核,这意味着例如在 2D 信号中的 (2,2)
位置,内核不会超出信号边界。因此,returned 是经过滤波的 2D 信号的范围,其中内核完全位于原始 2D 信号内。举个例子,如果你把内核放在位置(1,1)
,一些内核会越界。可以通过多种方式处理过滤时的越界条件,这可能会影响结果和对这些结果的解释。因此,当您使用构成最终结果的真实信息时,需要 'valid'
选项。您不会对超出 2D 信号边界的数据进行插值或执行任何估计。
简而言之,您 return 一个减少了边界元素的矩阵。形状奇特的过滤器使这很容易。您只需删除第一行和最后 floor(M/2)
行以及第一行和最后 floor(N/2)
列,其中 M x N
是内核的大小。因此,因为您的内核是 3 x 3,这意味着我们需要从顶部移除 1 行,从底部移除 1 行,以及从左侧移除 1 列,从右侧移除 1 列。正如您从 MATLAB 的输出中看到的那样,这会导致 4 x 4 网格中的 -48
。
因此,如果您想在代码中使用 'valid
' 选项,只需确保删除结果中的边框元素即可。您可以在 return 矩阵之前的最后执行此操作:
# Place your code here...
# ...
# ...
# Now we're at the end of your code
# Populating matrix
filter_matrix <- matrix(df[,3], nrow = x_max, ncol = y_max, dimnames = list(x_axis, y_axis))
# New - Determine rows and columns of matrix as well as the filter kernel
nrow_window <- nrow(window)
ncol_window <- ncol(window)
nrows <- nrow(filter_matrix)
ncols <- ncol(filter_matrix)
# New - Figure out where to cut off
row_cutoff <- floor(nrow_window/2)
col_cutoff <- floor(ncol_window/2)
# New - Remove out borders
filter_matrix <- filter_matrix[((1+row_cutoff):(nrows-row_cutoff)), ((1+col_cutoff):(ncols-col_cutoff))]
# Finally return matrix
return(filter_matrix)
示例运行
使用您的数据:
> image <- t(matrix(c(1:36), nrow=6, ncol=6))
> image
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
[6,] 31 32 33 34 35 36
> filter <- matrix(c(1,0,-1,2,0,-2,1,0,-1), nrow=3, ncol=3)
> filter
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 0 0 0
[3,] -1 -2 -1
我运行这个函数,现在我得到:
> filter2D(image,filter)
2 3 4 5
2 -48 -48 -48 -48
3 -48 -48 -48 -48
4 -48 -48 -48 -48
5 -48 -48 -48 -48
我认为让水平和垂直标签保持原样可能很重要,这样您就可以清楚地看到并非所有信号都被 returned,代码就是这样目前正在做......不过这取决于你。我会留给你决定。
我目前正在 R 中实现 filter2
MATLAB 函数,这是一种二维卷积的方法。我已经为 2D 卷积工作做了,但是我不太清楚 filter2 中的 'valid' 选项是如何工作的。
MATLAB函数说明如下: http://se.mathworks.com/help/matlab/ref/filter2.html
我的实现:
filter2D <- function(img, window) {
# Algoritm for 2D Convolution
filter_center_index_y <- median(1:dim(window)[1])
filter_max_index_y <- dim(window)[1]
filter_center_index_x <- median(1:dim(window)[2])
filter_max_index_x <- dim(window)[2]
# For each position in the picture, 2D convolution is done by
# calculating a score for all overlapping values within the two matrices
x_min <- 1
x_max <- dim(img)[2]
y_min <- 1
y_max <- dim(img)[1]
df <- NULL
for (x_val in c(x_min:x_max)){
for (y_val in c(y_min:y_max)){
# Distanced from cell
img_dist_left <- x_val-1
img_dist_right <- x_max-x_val
img_dist_up <- y_val-1
img_dist_down <- y_max-y_val
# Overlapping filter cells
filter_x_start <- filter_center_index_x-img_dist_left
if (filter_x_start < 1) {
filter_x_start <- 1
}
filter_x_end <- filter_center_index_x+img_dist_right
if (filter_x_end > filter_max_index_x) {
filter_x_end <- filter_max_index_x
}
filter_y_start <- filter_center_index_y-img_dist_up
if (filter_y_start < 1) {
filter_y_start <- 1
}
filter_y_end <- filter_center_index_y+img_dist_down
if (filter_y_end > filter_max_index_y) {
filter_y_end <- filter_max_index_y
}
# Part of filter that overlaps
filter_overlap_matrix <- filter[filter_y_start:filter_y_end, filter_x_start:filter_x_end]
# Overlapped image cells
image_x_start <- x_val-filter_center_index_x+1
if (image_x_start < 1) {
image_x_start <- 1
}
image_x_end <- x_val+filter_max_index_x-filter_center_index_x
if (image_x_end > x_max) {
image_x_end <- x_max
}
image_y_start <- y_val-filter_center_index_y+1
if (image_y_start < 1) {
image_y_start <- 1
}
image_y_end <- y_val+filter_max_index_y-filter_center_index_y
if (image_y_end > y_max) {
image_y_end <- y_max
}
# Part of image that is overlapped
image_overlap_matrix <- img[image_y_start:image_y_end, image_x_start:image_x_end]
# Calculating the cell value
cell_value <- sum(filter_overlap_matrix*image_overlap_matrix)
df = rbind(df,data.frame(x_val,y_val, cell_value))
}
}
# Axis labels
x_axis <- c(x_min:x_max)
y_axis <- c(y_min:y_max)
# Populating matrix
filter_matrix <- matrix(df[,3], nrow = x_max, ncol = y_max, dimnames = list(x_axis, y_axis))
return(filter_matrix)
}
运行方法:
> image
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
[6,] 31 32 33 34 35 36
> filter
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 0 0 0
[3,] -1 -2 -1
> filter2D(image, filter)
1 2 3 4 5 6
1 -22 -32 -36 -40 -44 -35
2 -36 -48 -48 -48 -48 -36
3 -36 -48 -48 -48 -48 -36
4 -36 -48 -48 -48 -48 -36
5 -36 -48 -48 -48 -48 -36
6 76 104 108 112 116 89
这与 filter2(image, filter) 在 matlab 中产生的输出相同,但是,当添加选项 'valid' 时,会生成以下输出:
-48 -48 -48 -48
-48 -48 -48 -48
-48 -48 -48 -48
-48 -48 -48 -48
带有 'valid' 选项的 filter2 是如何生成这个的并不完全清楚。它只是使用中心值吗?还是它在做更复杂的事情?
在我开始之前,您的代码实际上是在进行 2D 相关。 2D 卷积要求在进行加权求和之前对内核执行 180 度旋转。如果内核是对称的(即内核的 t运行spose 等于其自身),则相关和卷积实际上是相同的操作 。我只是想在开始之前说清楚。此外,filter2
的文档确实说明正在执行关联。
MATLAB 中的 'valid'
选项只是意味着它应该 return 只有在执行滤波时内核与 2D 信号完全重叠的输出。因为您有一个 3 x 3 内核,这意味着例如在 2D 信号中的 (2,2)
位置,内核不会超出信号边界。因此,returned 是经过滤波的 2D 信号的范围,其中内核完全位于原始 2D 信号内。举个例子,如果你把内核放在位置(1,1)
,一些内核会越界。可以通过多种方式处理过滤时的越界条件,这可能会影响结果和对这些结果的解释。因此,当您使用构成最终结果的真实信息时,需要 'valid'
选项。您不会对超出 2D 信号边界的数据进行插值或执行任何估计。
简而言之,您 return 一个减少了边界元素的矩阵。形状奇特的过滤器使这很容易。您只需删除第一行和最后 floor(M/2)
行以及第一行和最后 floor(N/2)
列,其中 M x N
是内核的大小。因此,因为您的内核是 3 x 3,这意味着我们需要从顶部移除 1 行,从底部移除 1 行,以及从左侧移除 1 列,从右侧移除 1 列。正如您从 MATLAB 的输出中看到的那样,这会导致 4 x 4 网格中的 -48
。
因此,如果您想在代码中使用 'valid
' 选项,只需确保删除结果中的边框元素即可。您可以在 return 矩阵之前的最后执行此操作:
# Place your code here...
# ...
# ...
# Now we're at the end of your code
# Populating matrix
filter_matrix <- matrix(df[,3], nrow = x_max, ncol = y_max, dimnames = list(x_axis, y_axis))
# New - Determine rows and columns of matrix as well as the filter kernel
nrow_window <- nrow(window)
ncol_window <- ncol(window)
nrows <- nrow(filter_matrix)
ncols <- ncol(filter_matrix)
# New - Figure out where to cut off
row_cutoff <- floor(nrow_window/2)
col_cutoff <- floor(ncol_window/2)
# New - Remove out borders
filter_matrix <- filter_matrix[((1+row_cutoff):(nrows-row_cutoff)), ((1+col_cutoff):(ncols-col_cutoff))]
# Finally return matrix
return(filter_matrix)
示例运行
使用您的数据:
> image <- t(matrix(c(1:36), nrow=6, ncol=6))
> image
[,1] [,2] [,3] [,4] [,5] [,6]
[1,] 1 2 3 4 5 6
[2,] 7 8 9 10 11 12
[3,] 13 14 15 16 17 18
[4,] 19 20 21 22 23 24
[5,] 25 26 27 28 29 30
[6,] 31 32 33 34 35 36
> filter <- matrix(c(1,0,-1,2,0,-2,1,0,-1), nrow=3, ncol=3)
> filter
[,1] [,2] [,3]
[1,] 1 2 1
[2,] 0 0 0
[3,] -1 -2 -1
我运行这个函数,现在我得到:
> filter2D(image,filter)
2 3 4 5
2 -48 -48 -48 -48
3 -48 -48 -48 -48
4 -48 -48 -48 -48
5 -48 -48 -48 -48
我认为让水平和垂直标签保持原样可能很重要,这样您就可以清楚地看到并非所有信号都被 returned,代码就是这样目前正在做......不过这取决于你。我会留给你决定。