ぱたへね

はてなダイアリーはrustの色分けができないのでこっちに来た

Gauche-CVで derivative Gaussian フィルター

Sobelフィルターは簡単に輪郭を抽出できますが、フィルターの効果が画像の解像度に依存するという欠点があります。その欠点を解消したのが derivative Gaussian フィルターです。Sobelフィルターの代わりに、Gaussian フィルターの一次微分を使います。ガウシアンフィルターのσを調整することで、フィルターが影響する範囲を調整します。

ガウス分布は以下の式で表せます。

f(x)=\frac{1}{^{\sqrt{2\pi \sigma ^{2}}\, }}\exp (-\frac{(x-\mu )^{2}}{2\sigma ^{2}})

μ=0、σ=5.0の時のグラフです。

ガウス分布の一次微分は、以下の式で表せます。

 \frac{\partial }{\partial x}f(x)=\frac{-x}{\sqrt{2\pi }\, \sigma ^{3}}\exp \left(\frac{-x^{2}}{2\sigma ^{2}}\right)

σ=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))

処理結果