バックナンバーはこちら。
https://www.simulationroom999.com/blog/compare-matlabpythonscilabjulia3-backnumber/
はじめに
非極大値抑制をプログラムで実現してみる。
今回はScilabで実施。
登場人物
博識フクロウのフクさん
イラスト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
動作確認用処理【再掲】
太郎くん
まずは、非極大値抑制の実験の処理手順を再掲
- Sobelフィルタ等の微分フィルタで以下を推定
- x軸、y軸の濃淡変化量
- 変化強度(ノルム)
- 「x軸、y軸の濃淡変化量」から勾配方向角を推定
- arntan関数を利用
- 勾配方向を垂直(UD)、水平(LR)、斜め右上から右下(RULD)、斜め左上から右下の4パターンに丸め。
- 勾配方向角に応じて極大値評価をして非極大値だったら「変化強度(ノルム)」 を0値埋め
- 画像出力
フクさん
これをScilabで実現する。
Scilabコード
フクさん
Scilabコードは以下になる。
convolution2d.sci
function out = convolution2d(img, Kernel)
[m, n] = size(Kernel); // カーネルサイズ取得
// カーネル中心からみた幅
dy = int32((m-1)/2); // カーネル上下幅
dx = int32((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( double(img(y-dy:y+dy, x-dx:x+dx)).*Kernel );
end
end
endfunction
non_maximum_suppression.sci
function out = non_maximum_suppression(G, theta)
[h, w] = size(G);
out = G;
// 勾配方向を4方向(LR,UD,RULD,LURD)に近似
theta( -22.5 <= theta & theta < 22.5) = 0; // LR ─
theta( 22.5 <= theta & theta < 67.5) = 45; // RULD /
theta( 67.5 <= theta & theta < 112.5) = 90; // UD │
theta( 112.5 <= theta & theta < 157.5) = 135; // LURD \
theta( 157.5 <= theta & theta < 180.0) = 0; // LR ─
theta(-180.0 <= theta & theta < -157.5) = 0; // LR ─
theta(-157.5 <= theta & theta < -112.5) = 45; // RULD /
theta(-112.5 <= theta & theta < -67.5) = 90; // UD │
theta( -67.5 <= theta & theta < -22.5) = 135; // LURD \
// 現画素の勾配方向に接する2つの画素値を比較し、現画素が極大値でなければ0にする。
for y = 2:(h - 1)
for x = 2:(w - 1)
if theta(y,x) == 0 // LR ─
if (G(y,x) < G(y,x+1)) | (G(y,x) < G(y,x-1))
out(y,x) = 0;
end
elseif theta(y,x) == 45 // RULD /
if (G(y,x) < G(y-1,x+1)) | (G(y,x) < G(y+1,x-1))
out(y,x) = 0;
end
elseif theta(y,x) == 90 // UD │
if (G(y,x) < G(y+1,x)) | (G(y,x) < G(y-1,x))
out(y,x) = 0;
end
else // LURD \
if (G(y,x) < G(y+1,x+1)) | (G(y,x) < G(y-1,x-1))
out(y,x) = 0;
end
end
end
end
endfunction
non_maximum_supp_test.sci
function [] = non_maximum_supp_test()
// 入力画像の読み込み
img = imread('dog.jpg');
r = img(:,:,1);
g = img(:,:,2);
b = img(:,:,3);
// ガウシアンフィルタ用のkernel
kernel_gauss = [ 1/16 2/16 1/16;...
2/16 4/16 2/16;...
1/16 2/16 1/16];
// Sobelフィルタ用のKernel
kernel_sx = [-1 0 1;...
-2 0 2;...
-1 0 1];
kernel_sy = kernel_sx';
// SDTVグレースケール
gray_sdtv = uint8([0.2990 * double(r) ...
+ 0.5870 * double(g) + 0.1140 * double(b) ]);
// ガウシアンフィルタ
img_g = convolution2d(gray_sdtv, kernel_gauss);
// Sobelフィルタ
Gx = convolution2d(img_g, kernel_sx);
Gy = convolution2d(img_g, kernel_sy);
// 勾配強度と角度
G = sqrt( Gx.^2 + Gy.^2 );
theta = atan(Gy, Gx) * 180 / %pi;
imwrite(uint8(abs(max(min(G,255),-255))),'dog_nms_G.jpg'); // 255オーバーあり
imwrite(uint8(abs(max(min(theta,255),-255))),'dog_nms_theta.jpg'); // -180~180
// 極大値以外を除去(Non maximum Suppression)
G_nms = non_maximum_suppression(G, theta);
imwrite(uint8(max(min(G_nms,255),0)),'dog_nms.jpg'); // 255オーバーあり
endfunction
処理結果
フクさん
処理結果は以下になる。
考察
太郎くん
結果及びコードはMATLABと一緒か。
フクさん
そうだね。
まぁ、min、maxによるサチュレーションが必要な点が大きな差分かな。
太郎くん
そして、Scilabでは論理インデックスサーチってのを使用してる感じかな?
theta( -22.5 <= theta & theta < 22.5) = 0; // LR ─
フクさん
そうそう。
そして、Scilabも線形インデックスサーチは可能だ。
太郎くん
そこらへんはあとでまとめて解説してもらおう。
まとめ
フクさん
まとめだよ。
- Scilabで非極大値抑制を実施。
- MATLABと同様の結果が得られた。
- コードもほぼ一緒。
- Scilabも線形&論理インデックスサーチが存在する。
バックナンバーはこちら。
コメント