前言
二維卷積的使用非常廣泛,不論是出現(xiàn)處理還是深度學(xué)習(xí)都有涉及。但是目前網(wǎng)上大多羅列公式,把其實(shí)簡單的二維卷積操作搞的很復(fù)雜。本文用在不使用任何的公式情況下,明白二維卷積的使用方法,并能夠用Matlab編程實(shí)現(xiàn)。
二維卷積實(shí)現(xiàn)
二維卷積實(shí)現(xiàn)可以分為兩大步。一是預(yù)處理:將卷積核翻轉(zhuǎn)180°,將原始數(shù)據(jù)擴(kuò)邊;二是滑動卷積計(jì)算。下面按這兩個(gè)步驟分別說明:
預(yù)處理
如圖1所示即看的很明白。對卷積核翻轉(zhuǎn)180°就是"上下翻轉(zhuǎn)+左右翻轉(zhuǎn)";對原始數(shù)據(jù)的擴(kuò)邊其實(shí)就是為了"補(bǔ)0"好算,擴(kuò)邊括多大呢?就看原始數(shù)據(jù)"左上角"那個(gè)點(diǎn),卷積核是3x3,那么左頂點(diǎn)一周也就要擴(kuò)成3x3(卷積核中心和左頂點(diǎn)對齊后可以做"點(diǎn)乘"),也就是上、下各括邊"fix(3/2) = 1"。

圖1:二維卷積操作預(yù)處理
滑動卷積計(jì)算
滑動卷積計(jì)算,其實(shí)就是對應(yīng)的"兩個(gè)小矩陣"的"點(diǎn)乘并求和"。"滑動"是指:卷積核沿著"擴(kuò)邊后的原始數(shù)據(jù)"從左到右,從上到下進(jìn)行。如圖2所示:

圖2:滑動卷積計(jì)算
完成上面兩步,二維卷積就做完了!是不是很簡單?根本不需要看復(fù)雜的公式~
既然清楚了理論基礎(chǔ),那就用Matlab實(shí)踐一下。
clc; clear;
x = [-1 -2 -1;0 0 0;1 2 1]; % 卷積核——必須是方陣且為奇數(shù)行/列
data = [1 2 3 4 5;6 7 8 9 10;11 12 13 14 15;16 17 18 19 20;21 22 23 24 25]; % 原始數(shù)據(jù)
zidai = conv2(data,x,'same'); % matlab自帶的二維卷積函數(shù)
x = rot90(rot90(x)); % 新的卷積核
% 核的尺寸
size_x = size(x);
row_x = size_x(1); % 核的行數(shù)
col_x = size_x(2); % 核的列數(shù)
% 數(shù)據(jù)的尺寸
size_data = size(data);
row_data = size_data(1); % 數(shù)據(jù)的行數(shù)
col_data = size_data(2); % 數(shù)據(jù)的列數(shù)
% 核的中心元素:
centerx_row = round(row_x/2);
centerx_col = round(col_x/2);
centerx = x(centerx_row,centerx_col);
% 對原始數(shù)據(jù)擴(kuò)邊:
data_tmp = zeros(row_data+row_x-1,col_data+row_x-1);
data_tmp(centerx_row:centerx_row+row_data-1,centerx_row:centerx_row+col_data-1) = data;
data_k = data_tmp;
% 擴(kuò)邊后新數(shù)據(jù)矩陣尺寸:
size_data_k = size(data_k);
row_data_k = size_data_k(1);
col_data_k = size_data_k(2);
% m = centerx_row:row_data+row_x-2
% 開始卷積計(jì)算: m n 是新數(shù)據(jù)矩陣的正常索引
result = zeros(row_data_k,col_data_k);
% m n一般卷積步長都是1
for m = centerx_row:centerx_row+row_data-1
for n = centerx_row:centerx_row+col_data-1
% tt是臨時(shí)與卷積核大小相同的數(shù)據(jù)中的部分矩陣:
tt = data_k(m-(centerx_row-1):m+(centerx_row-1),n-(centerx_row-1):n+(centerx_row-1));
% juan是中間每一次卷積計(jì)算求和的中間量:
juan = sum(x.*tt);
result(m,n) = sum(juan(:));
end
end
% 求掉之前擴(kuò)邊的0:
result = result(centerx_row:centerx_row+row_data-1,centerx_row:centerx_row+col_data-1)
說明:手動實(shí)現(xiàn)的matlab程序其實(shí)很簡單很好理解,可直接運(yùn)行。