C#プログラム画像処理画像処理プログラミング

【C#】画像の輝度値の取得

C#で画像ファイルの輝度値を取得するにはLockBits~UnlockBitsでポインタを取得して配列へコピーするなどするのが、C#では定番となっています。

例えば、下記のようなサンプルコード

var bmp = new Bitmap("01.png"); 

// Bitmapをロック 
var bmpData = bmp.LockBits( 
	new Rectangle(0, 0, bmp.Width, bmp.Height), 
	System.Drawing.Imaging.ImageLockMode.ReadWrite, 
	bmp.PixelFormat 
	); 

// メモリの幅のバイト数を取得 
var stride = Math.Abs(bmpData.Stride); 

// 画像データ格納用配列 
var data = new byte[stride * bmpData.Height]; 

// Bitmapデータを配列へコピー 
System.Runtime.InteropServices.Marshal.Copy( 
	bmpData.Scan0, 
	data, 
	0, 
	stride * bmpData.Height 
	);

// アンロック 
bmp.UnlockBits(bmpData);

このプログラムで、ほとんどの場合、問題ない事が多いのですが、モノクロ8Bitのpng画像ファイルを開くと、なぜか?32bitカラーの画像として認識してしまいます。

(評価に用いた画像) Deep Learningでは定番のMNISTの手書き文字に似せて作成した8bitモノクロ画像
csharp_get_bright

(デバッグ画面)もとの画像は8bitモノクロ画像ですが、PixelFormatがFormat32bppArgbになっています。

csharp_get_bright

 

8bitの画像が32bitとして認識してしまうという事は、無駄に画像データが4倍大きくなってしまうので、画像処理的には処理速度的にも不都合が起こります。

 

そこで、私は基本WindowsFormsを使っているのですが、クラスだけWPFのクラスを使う事で問題を解決します。

 

WPFのクラスを用いるにはプロジェクトの参照から
csharp_get_bright

下記の2つを追加します。

PresentationCore
WindowsBase

csharp_get_bright

 

これでWPFのクラスが使えるようになります。
そこで、最初に書いたBitmapクラスを用いたプログラムと同等のことをWPFのクラスを用いて作成すると

byte[] data; 

using (var fs = new System.IO.FileStream("01.png", System.IO.FileMode.Open, System.IO.FileAccess.Read)) 
{ 
	var bitmapFrame = System.Windows.Media.Imaging.BitmapFrame.Create( 
		fs, 
		System.Windows.Media.Imaging.BitmapCreateOptions.PreservePixelFormat, 
		System.Windows.Media.Imaging.BitmapCacheOption.Default 
		); 

	int stride = ((bitmapFrame.PixelWidth * bitmapFrame.Format.BitsPerPixel + 31) / 32) * 4; 

	// 画像データ格納用配列 
	data = new byte[stride * bitmapFrame.PixelHeight]; 
	
	// 輝度データを配列へコピー 
	bitmapFrame.CopyPixels(data, stride, 0); 
}

となります。

これでFormatもGray8となり、正しいサイズで画像データを取得できるようになります。

csharp_get_bright

 

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

関連記事

【C#】画像の輝度値の取得設定速度の比較
C#で画像の輝度値を取得/設定を行う場合は、GetPixel、SetPixelメソッドを使うと遅いのでLockBits~UnlockBitsでポインタをむき出して輝度値の取得/設定を行うのが定番となっていますが、自分自身でGetPixel、...

コメント

タイトルとURLをコピーしました