2016-04-20 3 views
1

В настоящее время я выполняю функцию MATLAB filter2 в R, которая является методом двумерной свертки. Я сделал для работы 2D свертки, но как «действительный» вариант в работе filter2 мне не совсем понятен.Реализация функции MATLAB filter2 в R

Функция 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 (изображение, фильтр) в Matlab, однако, когда добавляется опция «valid», генерируется следующий вывод:

-48 -48 -48 -48                                                 
-48 -48 -48 -48                                                 
-48 -48 -48 -48                                                 
-48 -48 -48 -48 

Не совсем очевидно, как filter2 с параметром «valid» генерирует это. Это просто использование значений центра? Или это делает что-то более сложное?

+0

Незначительное примечание: ваш исходный код использовал 'input' внутри суммы свертки, когда ваше определение функции использовалось' img'. Я переименовал 'input' в' img' в коде, и теперь он работает. – rayryeng

ответ

2

Прежде чем начать, ваш код на самом деле делает 2D корреляция. 2D свертка требует, чтобы вы выполняли поворот на 180 градусов на ядре перед выполнением взвешенной суммы. Корреляция и свертка фактически являются одной и той же операцией , если ядро ​​симметрично (т. Е. Транспонирование ядра равно самому себе). Я просто хотел это сделать, прежде чем начать. Кроме того, в документации для filter2 указано, что выполняется корреляция.


'valid' вариант в MATLAB просто означает, что он должен возвращать только выходы, где ядро ​​полностью перекрывает 2D сигнал при выполнении фильтрации. Поскольку у вас есть ядро ​​3 x 3, это означает, что в местоположении (2,2) в двумерном сигнале, например, ядро ​​не выходит за пределы границ сигнала. Поэтому возвращается то, что отфильтрованный 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 

Я думаю, что очень важно оставить горизонтальные и вертикальные метки такими, как они есть. Y ou может явно видеть, что не весь сигнал возвращается, что и делает код в настоящее время .... это зависит от вас. Я оставлю это вам решать.

+1

Спасибо, что указали, что такое двумерная корреляция и 2D свертка - это было очень полезно. Теперь действительный вариант также имеет гораздо больше смысла! Часто документация по методам немного скрыта в их объяснениях, а ваша гораздо яснее. –

+0

Вы очень желанны :) То, что я упомянул, исходит из опыта, и эта информация - это то, что документация немного замаскирует. Рад, что смог помочь. Удачи! – rayryeng