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モノクロ画像
(デバッグ画面)もとの画像は8bitモノクロ画像ですが、PixelFormatがFormat32bppArgbになっています。
8bitの画像が32bitとして認識してしまうという事は、無駄に画像データが4倍大きくなってしまうので、画像処理的には処理速度的にも不都合が起こります。
そこで、私は基本WindowsFormsを使っているのですが、クラスだけWPFのクラスを使う事で問題を解決します。
WPFのクラスを用いるにはプロジェクトの参照から
下記の2つを追加します。
PresentationCore
WindowsBase
これで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となり、正しいサイズで画像データを取得できるようになります。
←画像処理のためのC#テクニックへ戻る