Sobelフィルターは簡単に輪郭を抽出できますが、フィルターの効果が画像の解像度に依存するという欠点があります。その欠点を解消したのが derivative Gaussian フィルターです。Sobelフィルターの代わりに、Gaussian フィルターの一次微分を使います。ガウシアンフィルターのσを調整することで、フィルターが影響する範囲を調整します。
ガウス分布は以下の式で表せます。
σ=5.0の時のグラフです。
この曲線をσを調整しながらフィルターの係数として利用します。
プロットに使ったpythonのソースはここです。
gaussian_plot.py
Pythonで derivative Gaussian フィルター
Pythonで deviation Gaussian フィルターを使うには filters.gaussian_filter の第3引数で1を指定します。また第3引数に(0,1)とx方向に一次微分を指定しても、y方向には普通のガウシアンがかかっています。輪郭を抽出するには、Sobelフィルターと同じく、x方向、y方向にそれぞれ deviation Gaussian フィルターを掛け、各画素について絶対値の大きさを計算します。
__author__ = 'Natsutani' from PIL import Image from numpy import * import scipy from scipy.ndimage import filters im = array(Image.open('twittan.jpg').convert('L')) sigma = 1 # standard deviation imx = zeros(im.shape) imy = zeros(im.shape) filters.gaussian_filter(im, (sigma,sigma), (0,1), imx) filters.gaussian_filter(im, (sigma,sigma), (1,0), imy) magnitude = sqrt(imx**2+imy**2) scipy.misc.imsave('output/twi_derivertive_gaussian_x_python.png', imx) scipy.misc.imsave('output/twi_derivertive_gaussian_y_python.png', imy) scipy.misc.imsave('output/twi_derivertive_gaussian_python.png', magnitude)
Gauche-CVで deviation Gaussian フィルター
OpenCVでは、標準で deviation Gaussian はサポートされていないようなので、自分でフィルターを定義して deviation Gaussian フィルターを使用します。意外に手こずったので、ポイントをまとめました。
- 任意の行列を使用してフィルターをかけるには cv-filter-2d を使う。
- deviation Gaussian をかけた結果は負の値も取ります。make-image で確保した領域(
)は負の値を0に切り上げてしまうため、計算途中は make-cv-mat で確保した領域( )を使用する。 - 輝度の調整には cv-normalize を使用する。
cv-get-image, mat-magniture-2d はこのファイルで定義しています。
cvutil.scm
(use gauche.uvector) (use cv) (load "./cvutil.scm") ; Gaussian カーネルの定義 (define gaussian-kernel (list->f64vector '(0.00013383062461474178 0.004431861620031266 0.053991127420704416 0.24197144565660075 0.3989434693560978 0.24197144565660075 0.053991127420704416 0.004431861620031266 0.00013383062461474178))) ; Derivative Gaussian カーネル(Gaussian の一次微分)の定義 (define derivative-gaussian-kernel (list->f64vector '(-0.0005353224984589671 -0.0132955848600938 -0.10798225484140883 -0.24197144565660075 0.0 0.24197144565660075 0.10798225484140883 0.0132955848600938 0.0005353224984589671))) ; 画像を読み込んでモノクロに変換する。 (define src (cv-load-image "twittan.jpg")) (define src-gray (make-image (ref src 'width) (ref src 'height) IPL_DEPTH_8U 1)) (cv-cvt-color src src-gray CV_BGR2GRAY) ; 作業用領域の確保 (define dst-mat-gx (make-cv-mat (ref src 'height) (ref src 'width) CV_32F)) (define dst-mat-gy (cv-clone dst-mat-gx)) (define dst-mat-derivative-gaussian (cv-clone dst-mat-gx)) ; ガウシアンフィルター行列 (define gaussian-filter-x (make-cv-mat-from-uvector 1 (uvector-length gaussian-kernel) 1 gaussian-kernel)) (define gaussian-filter-y (make-cv-mat-from-uvector (uvector-length gaussian-kernel) 1 1 gaussian-kernel)) ; ガウシアンの一次フィルター行列 (define d-gaussian-filter-x (make-cv-mat-from-uvector 1 (uvector-length derivative-gaussian-kernel) 1 derivative-gaussian-kernel)) (define d-gaussian-filter-y (make-cv-mat-from-uvector (uvector-length derivative-gaussian-kernel) 1 1 derivative-gaussian-kernel)) ; x方向への derivative-gaussian (cv-filter-2d src-gray dst-mat-gx d-gaussian-filter-x) (cv-filter-2d dst-mat-gx dst-mat-gx gaussian-filter-y) ; y方向にはガウシアンフィルターを適用(numpyに準拠) (cv-save-image "output/twi_derivertive_gaussian_x_gauche.png" (cv-get-image dst-mat-gx)) ; y方向への derivative-gaussian (cv-filter-2d src-gray dst-mat-gy gaussian-filter-x) (cv-filter-2d dst-mat-gy dst-mat-gy d-gaussian-filter-y) (cv-save-image "output/twi_derivertive_gaussian_y_gauche.png" (cv-get-image dst-mat-gy)) ; x と y の大きさを計算した後、輝度を調整する。 (mat-magniture-2d dst-mat-gx dst-mat-gy dst-mat-derivative-gaussian) (cv-normalize dst-mat-derivative-gaussian dst-mat-derivative-gaussian 255 0 CV_C) (cv-save-image "output/twi_derivertive_gaussian_gauche.png" (cv-get-image dst-mat-derivative-gaussian))