画像の『膨張・収縮処理』とは、Webをググルと 一般に2値化された画像に対し行われ、ターゲットとなるピクセルの周辺に1ピクセルでも 白があれば白に置き換える膨張処理(Dilation)と、逆に1ピクセルでも 黒があれば黒に置き換える収縮処理(Erosion)からなり、ノイズを消す処理に用いるとのこと。
ただし OpenCvでは 『マルチチャンネルの場合、各チャンネルが個別に処理される』となっています。(OpenCv-CookBook参照)つまりは 2値化された画像のみならず グレースケールさらにはカラー画像もそれなりの処理がされることになります。Andoroid版の実験では カメラで撮影した画像を2値化してテストデータとしましたが、今回は同じデータをグレースケール化したものを透視変換だけ行いそのままテストデータにします。
注)画像の『膨張・収縮処理』については 以下のサイトに詳しく記述されています。
http://imagingsolution.blog107.fc2.com/blog-entry-101.html
http://d.hatena.ne.jp/shokai/20090203/1233608481
フォームには 次のボタンを準備しました。
- 透視変換 読み込んだ画像の正規化を行う
- 膨張一回 膨張処理を一回行う
- 膨張三回 膨張処理を三回行う
- 収縮一回 収縮処理を一回行う
- 収縮三回 収縮処理を三回行う
なお 膨張は Cv.Dilate(src, dst, element, n) 収縮はCv.Erode(src, dst, element, n) となります。
ここで 構造要素を示すelementをnullにすると ターゲットとなるピクセルは 3×3の矩形の中心で この3x3のピクセルの値をもとに 膨張・収縮処理を行います。またnは処理回数を示します。
構造要素を示すelementはIplConvKernel クラスで
IplConvKernel(int cols, int rows, int anchor_x, int anchor_y, ElementShape shape)
で定義します。
int cols,int rows: 構造要素のcols,rows
int anchor_x, int anchor_y: アンカー(ターゲット)となるピクセル位置
0 ≦ anchor_x < (cols -1) , 0 ≦ anchor_y < (rows -1)
ElementShape shape:列挙型 Rect,Ellispe,Crossから選択します。ただし Customの使い方はわかりませんでした。
コーディング |
using System; using System.Collections.Generic; using System.ComponentModel; using System.Data; using System.Drawing; using System.Text; using System.Windows.Forms; using OpenCvSharp; namespace OpenCvShp { public partial class Form1 : Form { private IplImage img; public Form1() { InitializeComponent(); } //初期処理(画像データ読み込み・表示) private void timer1_Tick(object sender, EventArgs e) { img = new IplImage(@”C:¥OpenCvTest¥Data¥a320_240.jpg”, LoadMode.GrayScale); timer1.Enabled = false; pictureBox1.Invalidate(); } //透視変換(正規化) private void btnPerspective_Click(object sender, EventArgs e) { CvPoint2D32f[] src_pf = new CvPoint2D32f[] { new CvPoint2D32f( 26, 19), new CvPoint2D32f( 9, 148), new CvPoint2D32f(237, 146), new CvPoint2D32f(223, 29) }; CvPoint2D32f[] dst_pf = new CvPoint2D32f[] { new CvPoint2D32f( 9, 19), new CvPoint2D32f( 9, 148), new CvPoint2D32f(237, 148), new CvPoint2D32f(237, 19) }; CvMat perspective_matrix = Cv.GetPerspectiveTransform(src_pf, dst_pf); Cv.WarpPerspective(img, img, perspective_matrix, Interpolation.Linear, new CvScalar(0, 0, 0)); pictureBox1.Invalidate(); } //膨張1回 private void btnDilate1_Click(object sender, EventArgs e) { Cv.Dilate(img, img, null, 1); pictureBox1.Invalidate(); } //膨張3回 private void btnDilate3_Click(object sender, EventArgs e) { Cv.Dilate(img, img, null, 3); pictureBox1.Invalidate(); } //収縮1回 private void btnErode1_Click(object sender, EventArgs e) { Cv.Erode(img, img, null, 1); pictureBox1.Invalidate(); } //収縮3回 private void btnErode3_Click(object sender, EventArgs e) { Cv.Erode(img, img, null, 3); pictureBox1.Invalidate(); } //描画処理 private void pictureBox1_Paint(object sender, PaintEventArgs e) { if (!timer1.Enabled) { Bitmap bmp = new Bitmap(img.Width, img.Height); bmp = img.ToBitmap(); e.Graphics.DrawImage(bmp, 0, 0, bmp.Width, bmp.Height); bmp.Dispose(); } } } }
処理結果 |
1) 元の画像 | 2) 透視変換して画像を正規化した状態 この画像をテストデータとします。 |
3) 2)から『膨張一回』をクリックした状態 | 4) 2)から『膨張三回』をクリックした状態 |
5) 2)から『収縮一回』をクリックした状態 | 6) 2)から『収縮三回』をクリックした状態 |
このDilateメソッド Erodeメソッドは単独で使うことは まれで 膨張・収縮を繰り返し処理を行う場合が多くあります。 とくに、同じ回数分だけ膨張して収縮する処理をクロージング(Closing)、 同じ回数分だけ収縮して膨張する処理をオープニング(Opening)とよびます。実際に2)のデータをもとに実験してみます。
1) 膨張1回 → 収縮1回 | 2) 収縮1回 → 膨張1回 |
3) 膨張3回 → 収縮3回 | 4) 収縮3回 → 収縮3回 |
カラー画像を直接処理すると |
初めにOpenCvでは カラー画像もそれなりに膨張・収縮しょりができるはず と書きました。今度はその実験をします。次の2つの処理手順の結果を比較します。
- 元の画像 ⇒ 膨張3回 ⇒ グレースケール化
- 元の画像 ⇒ グレースケール化 ⇒ 膨張3回
元の画像 | |
カラー画像を直接膨張3回した結果 |
⇒ グレースケール化した画像 |
元画像をグレースケール化した画像 |
⇒ 3回膨張 |
2つの手順とも同じ結果が得られました。
Windows7 Vs2008 OpenCv2.4 And OpenCvSharp |