【C#】画像処理プログラム向け基本プログラム

C#で画像処理を行うための最低限のプログラムを作成しました。

 

 

サンプルプログラムのダウンロードはこちら↓

ImagingBaseSample.zip(Visual Studio 2015 C#)

※Windows7では画像表示が消えてしまうようですので、Windows10でお試し下さい。

 

このプログラムは画像の輝度値へのアクセスを容易にするためのImageDataクラス(自作)と、

ImageDataクラスライブラリ

 

と、Graphicsクラスオブジェクトをコントロールのプロパティで拾えるようにしたGraphicsBoxコントロール(自作)

【.NET】GraphicsBoxコントロール

 

のサンプルとなっています。

 

現状では、むしろ面倒くさいだけのサンプルになっていますが、とりあえずヒストグラムの機能は付けました。

右上の空いたスペースにいろいろ肉付けをしていこうと思います。

 

画像処理のためのC#テクニックへ戻る

【C#】FormにDockしたPictureBoxのリサイズ時のサイズ取得

タイトルが長ったらしくなってしまったのですが、ピクチャボックスをFormにDockしたときにピクチャボックスのリサイズイベントでピクチャボックスの大きさ(幅、高さ)を取得するときのお話です。

 

 

フォームエディタで、上図の様にPictureBoxをFormにDockして、リサイズイベントでピクチャボックスのサイズを取得するには

private void pictureBox1_Resize(object sender, EventArgs e) 
{ 
	System.Diagnostics.Debug.WriteLine( 
		pictureBox1.Width.ToString() + ", " + pictureBox1.Height.ToString() 
	); 
}

とすれば、特に問題なくピクチャボックスの幅と高さを拾う事ができ、出力ウィンドウには

 

631, 460
632, 461
633, 462
634, 463
635, 464
636, 464
637, 465
638, 465
640, 466
640, 467

 

のように表示されます。

 

ここで、リサイズイベント内でピクチャボックスのImageプロパティを変更するプログラム

private void pictureBox1_Resize(object sender, EventArgs e) 
{ 
	System.Diagnostics.Debug.WriteLine( 
		pictureBox1.Width.ToString() + ", " + pictureBox1.Height.ToString() 
	); 
	pictureBox1.Image = null; 
} 

を実行すると、

 

683, 483
302, 260
685, 484
302, 260
686, 484
302, 260
687, 485
302, 260
688, 486
302, 260

 

のように表示され、 pictureBox1.Image = null; のコードが呼ばれた時点でリサイズイベントが再度発生し、取得したサイズが元のサイズに戻ってしまいます。

 

これを回避するのに、ここ↓

 

PictureBox リサイズイベントでのコントロールサイズを取得

https://social.msdn.microsoft.com/Forums/ja-JP/e554eb73-1437-4f63-baec-8f922d190211/picturebox-?forum=csharpgeneralja

 

を参考に sender からPictureBoxを拾うように

private void pictureBox1_Resize(object sender, EventArgs e) 
{ 
	var picBox = sender as PictureBox; 
	System.Diagnostics.Debug.WriteLine( 
		picBox.Width.ToString() + ", " + picBox.Height.ToString() 
	); 
	picBox.Image = null; 
}

としても結果は変わらず。

 

そこで、今回の条件としては、ピクチャボックスをフォームにDockしているので、ピクチャボックスのリサイズイベントが発生するときは、フォームのリサイズイベントも発生するということで、フォームのリサイズイベントで、ピクチャボックスのサイズを拾うように

private void Form1_Resize(object sender, EventArgs e) 
{ 
	System.Diagnostics.Debug.WriteLine( 
		pictureBox1.Width.ToString() + ", " + pictureBox1.Height.ToString() 
	); 
	pictureBox1.Image = null; 
}

としたら、出力ウィンドウにも

 

631, 460
632, 461
633, 462
634, 463
635, 464
636, 464
637, 465
638, 465
640, 466
640, 467

 

のように表示され、正しく動いてくれました。

 

なぜ、このような動きになるのか?不明ですが、結果オーライということで。。

 

C#へ戻る

【C#】画像ファイルを開く

C#で「画像ファイルを開く」というと、画像を表示したり、画像処理をするために、Imageクラス(名前空間:System.Drawing)か、Bitmapクラス(名前空間:System.Drawing)を作成することになります。

 

BitmapクラスはImageクラスを継承しているので、Imageクラスで出来ることはBitmapクラスでも、ほとんど出来るのですが、違いは何か?というと、Bitmapクラスでは画像データ(画像の輝度値)を参照・設定できる点が大きく異なります。

 

そのため画像処理を行う場合は、ほぼBitmapクラスを使うことになります。

 

そこで、画像ファイルからBitmapクラスを生成するメソッドを作成しました。


/// <summary> 
/// ファイルを開くダイアログボックスを表示して画像ファイルを開く 
/// </summary> 
/// <returns>生成したBitmapクラスオブジェクト</returns>
private Bitmap ImageFileOpen()
{
    //ファイルを開くダイアログボックスの作成  
    var ofd = new OpenFileDialog();
    //ファイルフィルタ  
    ofd.Filter = "Image File(*.bmp,*.jpg,*.png,*.tif)|*.bmp;*.jpg;*.png;*.tif|Bitmap(*.bmp)|*.bmp|Jpeg(*.jpg)|*.jpg|PNG(*.png)|*.png";
    //ダイアログの表示 (Cancelボタンがクリックされた場合は何もしない)
    if (ofd.ShowDialog() == DialogResult.Cancel) return null;

    return ImageFileOpen(ofd.FileName);
}

/// <summary>
/// ファイルパスを指定して画像ファイルを開く
/// </summary>
/// <param name="fileName">画像ファイルのファイルパスを指定します。</param>
/// <returns>生成したBitmapクラスオブジェクト</returns>
private Bitmap ImageFileOpen(string fileName)
{
    // 指定したファイルが存在するか?確認
    if (System.IO.File.Exists(fileName) == false) return null;

    // 拡張子の確認
    var ext = System.IO.Path.GetExtension(fileName).ToLower();

    // ファイルの拡張子が対応しているファイルかどうか調べる
    if (
        (ext != ".bmp") &&
        (ext != ".jpg") &&
        (ext != ".png") &&
        (ext != ".tif")
        ) {
        return null;
    }

    Bitmap bmp;

    // ファイルストリームでファイルを開く
    using (var fs = new System.IO.FileStream(
        fileName,
        System.IO.FileMode.Open,
        System.IO.FileAccess.Read))
    {
        bmp = new Bitmap(fs);
    }
    return bmp;
}

このImageFileOpenメソッドの使用例はこんな感じ↓です。

// 画像ファイルを開く
var bmp = ImageFileOpen();
pictureBox1.Image = bmp;

今回はファイルを開くのにFileStreamを使って開いていますが、単に

 

var bmp = new Bitmap(fileName);

 

のようにしてもBitmapクラスオブジェクトが生成されるのですが、画像ファイルを使っている間は、指定したファイルをエクスプローラで削除しようとすると

 

vshost32.exeによってファイルは開かれているため、操作を完了できません。

 

というメッセージが出て、ファイルを削除することができなくなるため、FileStreamを用いました。

 

画像処理のためのC#へ戻る

【C#】n乗根の計算

n乗根の計算で、例えば8の3乗根( \(\sqrt [ 3 ]{ 8 } =2\) )を計算するにはMathクラスのPowメソッドを用いて

 

Math.Pow(8.0, 1.0 / 3.0);

 

と、すれば答え  が求められます。

しかし、負の値のn乗根、例えば \(\sqrt [ 3 ]{ -8 }\)、を求めようと

 

Math.Pow(-8.0, 1.0 / 3.0);

 

とすると、答えは -2 を期待するところですが、C#ではNaNとなり、答えが求まりません。

しかし、負の値であっても、奇数乗根の場合は答えを求めたい。

 

という事で、こんなメソッドを作ってみました↓

private double NthRoot(double x, int n) 
{ 
	if (x >= 0) 
	{ 
		// 通常のn乗根 
		return Math.Pow(x, 1.0 / (double)n); 
	} 
	else 
	{ 
		if ((n % 2) != 0) 
		{ 
			// 奇数乗根の場合 
			return -Math.Pow(-x, 1.0 / (double)n); 
		} 
		else 
		{ 
			// 偶数乗根の場合 
			return double.NaN; 
		} 
	} 
}

(参考)Math.Powメソッド

https://msdn.microsoft.com/ja-jp/library/system.math.pow(v=vs.110).aspx

 

C#へ戻る