MATLAB、Python、Scilab、Julia比較ページはこちら
https://www.simulationroom999.com/blog/comparison-of-matlab-python-scilab/
はじめに
の、
MATLAB,Python,Scilab,Julia比較 第3章 その53【Hysteresis Threshold④】
非極大値抑制にHysteresis Thresholdを加えた、Canny法を実施して、2値化を行う。
今回はMATLABで実施する。
【再掲】Hysteresis Thresholdを実施するための手順
今回から、Hysteresis Thresholdで2値化をやる。
まずはMATLAB。
最初に手順を再掲しておこう。
トータルの手法としてはCanny法という名称になる。
- Sobelフィルタ等の微分フィルタで以下を推定
- x軸、y軸の濃淡変化量
- 変化強度(ノルム)
- 「x軸、y軸の濃淡変化量」から勾配方向角を推定
- arntan関数を利用
- 勾配方向を垂直(UD)、水平(LR)、斜め右上から右下(RULD)、斜め左上から右下の4パターンに丸め。
- 勾配方向角に応じて極大値評価をして非極大値だったら「変化強度(ノルム)」 を0値埋め
- Hysteresis Threshold
- High以上は白
- Low未満は黒
- High-Lowの間の場合は周辺を探査し、エッジが居れば白、いなければ黒
- 画像出力
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 ) );
%imgTmp = double(img(y-dy:y+dy, x-dx:x+dx));
%out(y, x) = imgTmp(:)'*kernel(:);
end
end
end
non_maximum_suppression.m
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
end
hysteresis_threshold.m
function out = hysteresis_threshold(img, low, high, r)
[h, w] = size(img);
out = img;
for y = (1+r):(h-r-1)
for x = (1+r):(w-r-1)
% 最大閾値より大きければ「エッジ」
if img(y,x) >= high
out(y,x) = 255;
% 最小閾値より小さければ「非エッジ」
elseif img(y,x) < low
out(y,x) = 0;
% 最小閾値と最大閾値の間で、半径rの範囲内に「エッジ」が1つでもあればエッジと判定
else
if max(img(y-r:y+r+1, x-r:x+r+1)) >= high
out(y,x) = 255;
else
out(y,x) = 0;
end
end
end
end
end
canny_test.m
function [] = canny_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 = 0.2990 * r + 0.5870 * g + 0.1140 * 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 = atan2(Gy, Gx) * 180 / pi;
% 極大値以外を除去(Non maximum Suppression)
G_nms = non_maximum_suppression(G, theta);
% Hysteresis Threshold(最小閾値除去、最大閾値以上を残し、且つそこと繋がっている最小閾値以上を残す)
G_canny = hysteresis_threshold(G_nms, 30, 65, 1); % 0 or 255に2値化
imwrite(uint8(G_canny),'dog_canny.jpg');
end
処理結果
処理結果は以下になる。
考察
結果としては見た通りで、ちゃんと2値化ができている。
ソースコードとしてはかなり増えてしまっているが、
ほとんどは前回までの非極大値抑制と同一。
今回新規に追加したのは、hysteresis_thresholdとcanny_testだけになる。
結果論になるが、ステップアップ式にここまで来た感じになる。
まとめ
- 非極大値抑制にHysteresis Thresholdを加えた、Canny法による2値化をMATLABで実施。
- 基本的にはいままでのコードを再利用。
- 追加分はHysteresis Thresholdの部分。
MATLAB、Python、Scilab、Julia比較ページはこちら
コメント