画像の『膨張・収縮処理』とは、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 |














