【问题标题】:Implementing the MATLAB filter2 function in R在 R 中实现 MATLAB filter2 函数
【发布时间】:2016-04-20 15:24:50
【问题描述】:

我目前正在R中实现filter2 MATLAB函数,这是一种二维卷积的方法。我已经完成了 2D 卷积工作,但 filter2 中的“有效”选项的工作原理对我来说不是很清楚。

此处描述了 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  

带有“有效”选项的 filter2 是如何生成这个的并不完全清楚。它只是使用中心值吗?还是在做一些更复杂的事情?

【问题讨论】:

  • 次要注意:当您的函数定义使用img 时,您的原始代码在卷积和内使用input。我在代码中将input 重命名为img,它现在可以工作了。

标签: r matlab filter 2d convolution


【解决方案1】:

在我开始之前,您的代码实际上是在做 2D correlation。 2D 卷积要求您在进行加权和之前对内核执行 180 度旋转。相关和卷积实际上是相同的操作如果内核是对称的(即内核的转置等于自身)。我只是想在开始之前说清楚。此外,filter2 的文档确实声明正在执行关联。


MATLAB 中的'valid' 选项仅仅意味着它应该只返回内核在执行滤波时与二维信号完全重叠的输出。因为您有一个 3 x 3 内核,这意味着例如在 2D 信号中的位置 (2,2) 处,内核不会超出信号边界。因此,返回的是滤波后的 2D 信号的范围,其中内核完全位于原始 2D 信号内。举个例子,如果您将内核放置在位置(1,1),一些内核会超出范围。过滤时处理越界条件可以通过多种方式完成,这可能会影响结果以及对这些结果的解释。因此,当您使用形成最终结果的真实信息时,需要'valid' 选项。您没有对超出 2D 信号边界的数据进行插值或执行任何估计。

简单地说,您返回一个删除了边框元素的简化矩阵。形状奇特的过滤器使这很容易。您只需删除第一个和最后一个floor(M/2) 行以及第一个和最后一个floor(N/2) 列,其中M x N 是内核的大小。因此,因为您的内核是 3 x 3,这意味着我们需要从顶部删除 1 行,从底部删除 1 行,以及从左侧删除 1 列和从右侧删除 1 列。这会导致-48 在 4 x 4 网格内,正如您从 MATLAB 的输出中看到的那样。

因此,如果您想在代码中使用'valid' 选项,只需确保删除结果中的边框元素即可。您可以在最后返回矩阵之前执行此操作:

# 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

我认为将水平和垂直标签保持原样可能很重要,这样您就可以清楚地看到并非所有信号都被返回,这就是代码当前正在做的......不过取决于你。这个由你来决定。

【讨论】:

  • 感谢您指定什么是 2D 相关和 2D 卷积 - 这非常有帮助。现在有效选项也更有意义!通常,方法的文档在其解释中有点隐含,而您的解释要清楚得多。
  • 不客气 :) 我提到的内容来自经验,而这些信息是文档中简要掩盖的内容。很高兴我能帮上忙。祝你好运!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-08-11
  • 1970-01-01
  • 2015-01-29
  • 2013-07-13
  • 2011-01-06
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多