二維卷積的原理與手動編程實(shí)現(xiàn)

前言

二維卷積的使用非常廣泛,不論是出現(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)行。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容