MATLAB,Python,Scilab,Julia比較 第3章 その21【ガウシアンフィルタ⑦】

MATLAB,Python,Scilab,Julia比較 第3章 その21【ガウシアンフィルタ⑦】 数値計算
MATLAB,Python,Scilab,Julia比較 第3章 その21【ガウシアンフィルタ⑦】

バックナンバーはこちら。
https://www.simulationroom999.com/blog/compare-matlabpythonscilabjulia3-backnumber/

はじめに

畳み込み演算のガウシアンフィルタの話。
今回はMATLABで実施してみる。

登場人物

博識フクロウのフクさん

指差しフクロウ

イラストACにて公開の「kino_k」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=iKciwKA9&area=1

エンジニア歴8年の太郎くん

技術者太郎

イラストACにて公開の「しのみ」さんのイラストを使用しています。
https://www.ac-illust.com/main/profile.php?id=uCKphAW2&area=1

使用する畳み込みカーネルと画像

太郎くん
太郎くん

今回からは、実際にガウシアンカーネルを試していくんだよね。
まずはMATLABか。

フクさん
フクさん

そうだね。
使用する畳み込みカーネルと画像を再掲しよう。

畳み込みカーネル

\(
\displaystyle K_{3\times3}=\frac{1}{16}
\begin{bmatrix}
1 & 2 & 1 \\
2 & 4 & 2 \\
1 & 2 & 1 \\
\end{bmatrix}
\)

画像

犬と自転車

MATLABコード

フクさん
フクさん

MATLABコードは以下になる。

convolution2d.m

function out = convolution2d(img, kernel)
    [m, n] = size(kernel);  % カーネルサイズ取得
    
    % カーネル中心からみた幅
    dy = int64(fix((m-1)/2));  % カーネル上下幅
    dx = int64(fix((n-1)/2));  % カーネル左右幅
    
    [h, w] = size(img);         % イメージサイズ
    out = zeros(h, w);          % 出力用イメージ
    
    % 畳み込み
    for y = dy+1:(h - dy)
        for x = dx+1:(w-dx)
            out(y, x) = sum( sum( double(img(y-dy:y+dy, x-dx:x+dx)).*kernel ) );
        end
    end
end

gaussian_test.m

function gaussian_test()
    img = imread('dog.jpg');
    
    [h, w, c] = size(img);
    
    % ガウシアンフィルタ用のkernel
    kernel_gauss = [ 1/16  2/16  1/16; ...
                     2/16  4/16  2/16; ...
                     1/16  2/16  1/16];
    img_gauss = zeros(h, w, c, 'uint8');
    
    % ガウシアンフィルタ
    tic
    img_gauss(:,:,1) = convolution2d(img(:,:,1), kernel_gauss);
    img_gauss(:,:,2) = convolution2d(img(:,:,2), kernel_gauss);
    img_gauss(:,:,3) = convolution2d(img(:,:,3), kernel_gauss);
    toc
    imwrite(img_gauss,'dog_gaussian.jpg');
end

処理結果

フクさん
フクさん

そして処理結果。

犬と自転車、ガウシアンフィルタ、MATLAB

考察

太郎くん
太郎くん

画像は・・・変わった・・・か????

フクさん
フクさん

並べてみるとわかるけど、一応平滑化された感じはある。

太郎くん
太郎くん

まぁ、元々がそれほどノイズを持ってるか像じゃないから人間の目で見た際の変化が少ないんだな。

太郎くん
太郎くん

畳み込み演算用の関数はconvolution2dになるのかな?

フクさん
フクさん

そうだね。
out(y, x) = sum( sum( double(img(y-dy:y+dy, x-dx:x+dx)).*kernel ) );
の部分が一回の畳み込み演算だ。
MATLABのsumは列方向、行方向のそれぞれの総和が取れるが、一括で全体の総和が取れないため、2回実施している。
MATLAB R2018b以降であれば、sum(A,’all’)のような指定の仕方がで行列全体の総和が取れるみたいだな。
ここでは、どのversionでも動くように2回のsumをする方式を採用している。

太郎くん
太郎くん

sumの挙動が想定とちょっと違うのか・・・。

フクさん
フクさん

あとは、行列をベクトルに変換して、内積として処理させることもできるが、
行列の形状は変えず、アダマール積と総和の組み合わせで実現している。

太郎くん
太郎くん

アダマール積は演算子が「.*」になるんだったね。
この点は気を付ける必要がありそう。

フクさん
フクさん

あとはRGB 3chをそれぞれ抽出して、ガウス分布カーネルと一緒に畳み込み演算関数に渡してる。

太郎くん
太郎くん

あー、それで同じような処理が3回実施されているのか。

まとめ

フクさん
フクさん

まとめだよ。

  • MATLABでガウシアンフィルタを実施。
  • 畳み込み演算は関数化。
    • MATLABのsumは行と列のそれぞれの総和しか計算できない。(version依存)
  • RGB 3chに対して同じ処理を実施している。

バックナンバーはこちら。

コメント

タイトルとURLをコピーしました