2012年4月15日日曜日

エッジを検出する その1 - OpenCV for Android


いよいよ画像解析っぽくなってきました。

エッジ検出とは、画素の明るさが急激に変化する場所を探し、画像の輪郭を算出する処理を指します。
明るさの変化は、微分演算を利用することで算出し、グラディエント(1次微分)とラプラシアン(2次微分)があります。

1次微分を計算するSobelフィルタを利用するには、Imgproc.Sobel()メソッドを利用します。

imgproc.Imgproc.Sobel(Mat src, Mat dst, int ddepth,
int dx, int dy, int ksize, double scale, double delta, int borderType))

Mat src     処理したい元画像のMat
Mat dst     変換後Mat
int ddepth    変換後のビット深度
int dx       dx
int dy       dy
int ksize     カーネルサイズ
double scale  計算されたデリバティブの値の任意のスケールファクタ
double delta  オプションのデルタ値
int borderType ピクセル外挿手法

dx、dyについては、ksizeが1の場合を除き、必ずksize未満である必要があります。
ksizeが1の場合は、3 x 1もしくは1 x 3のカーネルが利用されますので、dx、dyの最大値は2です。

ksizeについては、ksizeが1の場合を除き、導関数を計算するためにksize × ksizeのカーネルが利用されます。
ksizeは奇数かつ31以下である必要があります。

ksizeが特殊な値「Imgproc.CV_SCHARR」の場合、3×3のSobelフィルタより精度が高い、3×3のScharrフィルタに対応します。
Scharrフィルタを利用する場合、dxかdyのどちらかが1、どちらかが0である必要があります。


それでは、実際にやってみましょう。

グレースケールに変換してから処理します。

まずは元画像。


Imgproc.Sobel(mat, dstMat, mat.type(), 1, 0, 1);


dxを変更してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 2, 0, 1);


ドキュメントには、このメソッドはほとんどの場合(dx = 1, dy = 0, ksize = 3)もしくは(dx = 0, dy = 1, ksize = 3) の引数で呼び出されるとあるので、それぞれ試してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 0, 3);


Imgproc.Sobel(mat, dstMat, mat.type(), 0, 1, 3);


ksizeを変更してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 1, 7);


Imgproc.Sobel(mat, dstMat, mat.type(), 1, 1, 21);


Scharrフィルタを利用してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 0,
  Imgproc.CV_SCHARR);


Imgproc.Sobel(mat, dstMat, mat.type(), 0, 1,
  Imgproc.CV_SCHARR);


scaleを変更してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 1, 3, 50.0);


deltaを変更してみます。
Imgproc.Sobel(mat, dstMat, mat.type(), 1, 1, 3, 1.0,
  100.0);


ところで微分って何?おいしいの?

0 コメント:

コメントを投稿