【ImageDataクラス】画像の輝度値のCSVファイル保存

画像処理をしていると、画像の輝度値をCSVファイルに保存したいという要望はよくあります。

C#で画像の輝度値にアクセスしやすいようにしたImageDataクラスを作成しました。

(Pythonで画像の輝度値をCSVファイルに保存したい場合はこちらの記事を参照ください。)

 

このImageDataクラスではSave()メソッドに拡張子がCSVのファイルにも対応したので、輝度値をCSVファイルに保存するには

var img = new ImagingSolution.Imaging.ImageData("Mandrill.BMP");
img.Save("Mandrill.csv");

というコード量だけで、CSVファイルに保存できます。

ちなみに、CSVファイルに保存したいだけであれば、こちらで公開しているサンプルプログラムでも輝度値をCSVファイルに保存できるので、お試しください。

 

例えば、マンドリルのこの画像↓をCSVファイルに保存すると、

 

下図のように画像の左上から画像の輝度値がカンマ区切りで保存されます。

 

このCSVファイルをエクセルで表示すると、

 

エクセルにはセルの値に連動してセルの色を変える条件付き書式というのがあるのですが、この機能を使うとセルに画像を表示することができます。(ただし、モノクロ画像のみ)

 

やり方は、条件付き書式→カラースケール→その他のルールと選択します。

 

すると、最小値種類の部分を数値にして

 

同様に、最大値種類の部分を数値にして255に設定します。

 

すると、エクセル上に、こんな感じ↓で画像が表示されます。

 

ImageDataクラスライブラリへ戻る

【ImageDataクラス】Regionプロパティ

画像処理プログラムでは、画像の一部分のみを処理するROIRegion of Interest)という機能がよくあります。

このROIを使うことで、必要な部分のみを処理したり、異なる2つの画像において、同じ領域を処理するために、このROIを指定したりします。

 

ImageDataクラスでは、Regionプロパティを用意し、処理領域を.NET FrameworkのSystem.Drawing.Rectangle構造体を使って領域を指定します。

 

例えば、下記のようなコードで

// ImageDataクラスをファイル名を指定してインスタンスする
var img = new ImagingSolution.Imaging.ImageData("Lenna.bmp");
// Region範囲の指定
img.Region = new Rectangle(50, 20, 150, 180);
// 指定された範囲の画像を保存
img.Save("Lenna_ROI.bmp");

領域を解除するには

img.ResetRegion();

 

のようにResetRegionメソッドを呼び出して下さい。

 

有名どこのレナさんですが、領域を指定すると指定された領域を画像ファイルに切り出すことができます。

 

 

ImageDataクラスライブラリへ戻る

【ImageDataクラス】画像の輝度値(画素値)の取得/設定

BorderTypeプロパティInterpolationModeプロパティのページでも少し紹介していますが、画像の輝度値を取得/設定するには

var img = new ImagingSolution.Imaging.ImageData("image.bmp");
// 輝度値の取得
var bright = img[2, 3];
// 輝度値の設定
img[2, 3] = 234;

のようにImageDataクラスオブジェクトを、あたかも配列として値の取得/設定ができるようになっています。

 

また、画像の輝度値の値は通常8bit(0~255)なので、

 

img[2, 3] = -45;  や  img[4, 5] = 258;

 

のようには設定できないのですが、上記のように設定すると、クラス内部的には

 

img[2, 3] = -45;  →  img[2, 3] = 0;

img[4, 5] = 258;  →  img[4, 5] = 255;

 

として設定されるので、輝度値を設定するときに、if文で0~255の範囲チェックは必要ありません。

また、 img[2, 3] = -45;  と設定した場合ですが、MinusValueModeプロパティを使って

 

img.MinusValueMode = ImagingSolution.Imaging.ImageData.MinusValueModeEnum.Absolute;

 

のように設定すると img[2, 3] = -45; は  img[2, 3] = 45;  として設定されます。

MinusValueModeプロパティは何も設定しないとMinusValueModeEnum.Zeroに設定されています。

 

値の取得/設定にはC#のインデクサという機能を用いているのですが、このインデクサに下記4つのオーバーロードを用意しています。

int this[int row, int column] // 取得/設定
int this[int row, int column, int ch]  // 取得/設定
int this[float row, float column]  // 取得のみ
int this[float row, float column, int ch] // 取得のみ

この引数の部分の並びを[row, column]とするか、[column, row]にするか悩んだのですが、画像データを多次元配列で表したときに同じ並びになる[row, column]の順番なので、ご注意ください。

座標っぽく表示すると[y, x]という順番です。

 

row(行番号)とcolumn(列番号)の位置関係ですが、画像の左上を原点[0, 0]として、モノクロ画像(8bit,1channel)の場合、次のようになります。

 

カラー画像(24bit,3channel)の場合、

 this[int row, int column]

の形式で輝度値を参照すると、下図のようになります。

 

これだと、少し分かりづらいので、chの引数を用いて

 this[int row, int column, int ch]

の形式で参照すると、下図のようになります。

 

 

カラー画像(32bit,4channel)は、下図のようになります。

 

 

ImageDataクラスライブラリへ戻る

 

【ImageDataクラス】InterpolationModeプロパティ

BorderTypeプロパティではインデクサをつかって

var img = new ImagingSolution.Imaging.ImageData("image.bmp");
var bright = img[-1, -1];

のように配列の添え字に相当する部分に負の値を設定すると、画像の外側の輝度値(画素値)を参照できるのを紹介しました。

だったら、添え字相当の部分に少数も指定できるんじゃね?!的な発想で画素間の輝度値を取得できるようにしています。

 

下記のコード例ではX座標が1.3、Y座標が2.7の位置を輝度値を取得しています。

var img = new ImagingSolution.Imaging.ImageData("image.bmp");
var bright = img[2.7f, 1.3f];

 

この画素と画素の間の輝度値を周りの画素の輝度の値から算出する方法を補間というのですが、詳細は下記ページを参照ください。

画素の補間(Nearest neighbor,Bilinear,Bicubic)の計算方法

 

この補間方法に有名どころで、Nearest neighorBilinearBicubicの3があり、この補間方法をInterpolationMonoプロパティにInterpolationModeEnumで指定します。

Bilinearが初期値で設定されています。

 

コード例

var img = new ImagingSolution.Imaging.ImageData("image.bmp");

////////////////////////////////////////////////////
// 下記のいづれかを指定します
// NearestNeighbor
img.InterpolationMode = ImagingSolution.Imaging.ImageData.InterpolationModeEnum.NearestNeighbor;
// Bilinear(初期値)
img.InterpolationMode = ImagingSolution.Imaging.ImageData.InterpolationModeEnum.Bilinear;
// Bicubic
img.InterpolationMode = ImagingSolution.Imaging.ImageData.InterpolationModeEnum.Bicubic;
////////////////////////////////////////////////////
// 取得する輝度値
var bright = img[2.7f, 1.3f];

ただし、Bicubicは処理が重いです...

 

ImageDataクラスライブラリへ戻る

 

【ImageDataクラス】BorderTypeプロパティ

ImageDataクラスでは、C#のインデクサという機能を使って、new したImageDataクラスをオブジェクトをあたかも配列かのように扱うことができます。

 

インデクサの例

var img = new ImagingSolution.Imaging.ImageData("image.bmp");
var bright = img[2, 5];

のようにするだけで画像の輝度値を取得することができます。

 

インデクサを用いると、配列ではできない

var bright = img[-1, -1];

のように配列の添え字に相当する部分にマイナスの値を指定することもできます。

 

このインデクサの機能を使って、画像のフィルタ処理で、画像の外周部分において、画像の外側の輝度値を参照する方法をBorderTypeプロパティにより設定を行います。

 

3×3フィルタにおいて、画像の外側を参照してしまう例

 

設定はBorderTypeEnum列挙型を指定します。

 

BordeTypeEnum.Mirrorの場合(初期値)

画像の輪郭部分を基準に折り返すように輝度値を参照します。

img[-1, -1]の値は130となります。

 

BordeTypeEnum.Clampの場合

画像の輪郭部分の輝度値に固定し参照します。

 

img[-1, -1]の値は71となります。

 

BordeTypeEnum.ToZeroの場合

画像の外側の輝度値を0にします。

img[-1, -1]の値は0となります。

 

ImageDataクラスライブラリへ戻る

【ImageDataクラス】サンプルプログラム

ImageDataクラスライブラリ公開のページにて公開しているサンプルプログラムについて簡単に説明しておきます。

 

このサンプルプログラムの開発環境は

  • Visual Studio 2015 C#
  • .NET Framework 4.5.2

となります。

 

上記環境にて、サンプルプログラムを実行すると、下図のような画面が開きます。

 

 

このFileメニューよりOpenを選択し、画像ファイルを指定します。

 

 

このOpenの処理の中身は、ほぼ.NET FrameworkのBitmapクラスなので、開く事のできるファイルもBitmapクラスに従い、*.bmp、*.jpg、*.png、*.tifとなります。

保存(Save)は上記形式に加え、CSVファイルにも保存できます。

 

画像を開いたら、ウィンドウに等倍で画像が表示されます。

 

 

ステータスバー左側にはマウスポインタが指示している画像の座標と、その位置の輝度値(R, G, B)が表示されます。

また、ステータスバー右側には、フィルタ処理を行った時の処理時間が表示されます。

 

画像のフィルタ処理を実行するにはFileメニューより、GrayScaleGaussianSobelの3つの処理を選ぶことができます。

 

 

GrayScaleの処理結果

 

Gaussianフィルタの処理結果

 

Sobelフィルタの処理結果

 

の3つの処理を実装しています。

フィルタ処理の部分はソースを公開しているので、フィルタ処理プログラム作成の参考にしてみて下さい。

 

今回、この3つの処理を選んだのには

 

GrayScael・・・処理の前後で画像のビット数が変わる例

Gaussian・・・画像の外側の輝度値を参照する例

Sobel・・・計算結果が負になる場合がある例

 

の代表的な例として公開しています。

ソースコードを見て頂くと分かりますが、画像の外側も普通に参照しちゃってるっぽいし、フィルタ処理の計算結果が0~255の範囲を超える場合もありそう・・・なのですが、そこは、このImageDataクラスがなんとかしてくれてます。

 

ImageDataクラスライブラリへ戻る

ImageDataクラスライブラリの使用方法

ImageDataクラスライブラリは、知っている人向けにはライブラリ(サンプルプログラム)のダウンロードページよりファイルをダウンロードし、zipファイルを解凍したImageDataSampleフォルダ内にあるImagingSolution.Imaging.ImageData.dllを参照してください!

 

ということなのですが、このライブラリは画像処理プログラム初心者向けを目指しているので、念のため詳細の使用方法です。

 

まず、Visual Stusio 2015を起動し新しいプロジェクトを選択します。

 

次にテンプレート→Visual C#→Windows→Windowsフォームアプリケーション

 

 

と選択し、プロジェクトの名前および場所を指定し、参照をクリックします。

 

 

次にプロジェクト名(WindowsFormsApplication1、プロジェクトの作成時に付けた名前です)を右クリックし、追加参照と選択します。

 

 

次に表示されたウィンドウの参照をクリックします。

すると、参照するファイルの選択ウィンドウが表示されるので、ダウンロードページより取得したサンプルプログラムのファイルを解凍してできたImageDataSamleフォルダ内にある

 

ImagingSolution.Imaging.ImageData.dll

 

のファイルを選択し、追加をクリックします。

 

 

すると、ImagingSolution.Imaging.ImageData.dllの左側にチェックが入っている状態で、OKをクリックします。

 

 

最後にVisual Studioのソリューションエクスプローラー画面の参照の部分にImagingSolution.Imaging.ImageDataが追加されていれば、このライブラリを使用する準備が完了です。

 

 

ImageDataクラスライブラリへ戻る

【C#】ImageDataクラスライブラリ公開

画像処理プログラムの基本は画像の輝度値(画素値)を取得して、様々な処理をすることとなりますが、C#では輝度値を取得するメソッドにSetPixel/GetPixelのメソッドが用意されていますが、これは処理が遅いことで有名。

 

そこで、OpenCVのIplImage構造体やMatクラスのエッセンスを取り入れつつ、.NETのBitmapクラスっぽく、さらに画像データを簡単に扱えるようにすることを目指したImageDataクラスなるライブラリを作成してみました。

 

基本コンセプトは

●画像の輝度値の取得/設定が簡単

●SetPixel/GetPixelよりは高速

●シンプルなプログラムが書けること

 

といったところです。

 

画像処理をこれから学ぼうとする人、とりあえず簡単にアルゴリズムの評価プログラムを作って見たい人向けを想定しています。パフォーマンス重視の方はポインタ(Scan0)を参照してください。

 

というスタンスです。

今のところフリーですので、ご興味があれば使ってみてください。

ただし、本ライブラリを使用した事による不具合等の責任を負えませんので、ご了承願います。

 

ファイル:ImagingSolution.Imaging.ImageData.dll

.NET Frameworkバージョン:4.5.2

Visual Studio 2015 C#を使用

 

ダウンロード

公開日 バージョン サンプルプログラム
2016.3.19 Ver.0.1.1 ImageDataSample011.zip Bitmapファイル読込部分のバグ修正

Reaginプロパティに影響

2016.3.17 Ver.0.1.0 ImageDataSample010.zip 初版

バグなどが含まれる可能性があります。

今後、仕様が変更される可能性もあります。

 

コンストラクター

名前 説明
ImageData(int, int, int, int) 画像の幅、高さ、画像のビット数、メモリのビット数を指定して、ImageDataクラスの新しいインスタンスを初期化します。
ImageData(int, int, int, System.Drawing.Imaging.PixelFormat, System.IntPtr) 画像の幅、高さ、メモリの幅のバイト数、ピクセルフォーマット、外部メモリのポインタを指定して、ImageDataクラスの新しいインスタンスを初期化します。
ImageData(int, int, System.Drawing.Imaging.PixelFormat) 画像の幅、高さ、ピクセルフォーマットを指定して、ImageDataクラスの新しいインスタンスを初期化します。
ImageData(string) 画像ファイル名を指定して、ImageDataクラスの新しいインスタンスを初期化します。

 

プロパティ

名前 説明
BiCubicVal biCubiによる補間の計算時に用いる変数を取得/設定します。

初期値:-0.75

BorderType 画像の外側の輝度値の参照方法をBorderTypeEnumにより取得/設定します。

初期値:BorderTypeEnum.Mirror

BufferBit 画像を格納するメモリのビット数を取得します。

8、16、24、32のいづれを指定します。

ByteAlignment 画像を格納するメモリのアライメントのバイト数を取得します。
Channel 画像のチャンネル数(色数)を取得します。

1, 3, 4のいづれか

Height 画像の高さ(画素数)を取得します。
ImageBit 画像のビット数を取得します。

8~16、24、30、32のいづれを指定します。

InterpolationMode 画素間の輝度値の取得時の補間モードをInterpolationModeEnumにより取得/設定します。

初期値:InterpolationModeEnum.Bilinear

MinusValueMode 輝度値(画素値)に負の値を設定時の処理方法をMinusValueModeEnumにより取得/設定します。

初期値:MinusValueModeEnum.Zero

PixelFormat 画像のピクセルフォーマットをSystem.Drawing.Imaging.PixelFormatにより取得します。
Region 画像処理処理範囲(参照範囲)をSystem.Drawing.Rectangleにより取得/設定します。
Sacn0 画像データを格納するメモリのポインタをSystem.IntPtrにより取得します。
Stride 画像データを格納するメモリの幅をバイト数で取得します。
Width 画像の幅(画素数)を取得します。

 

インデクサ

名前 説明
this[float, float, int] 画像の行位置(Y座標)、列位置(X座標)、チャンネル番号(B[0]、G[1]、R[2])を指定して輝度値を取得します。
this[float, float] 画像データの行位置(Y座標)、列位置(X座標)を指定して輝度値を取得します。
this[int, int, int] 画像の行位置(Y座標)、列位置(X座標)、チャンネル番号(B[0]、G[1]、R[2])を指定して輝度値を取得/設定します。
this[int, int] 画像データの行位置(Y座標)、列位置(X座標)を指定して輝度値を取得/設定します。

 

列挙型

名前 説明
BorderTypeEnum BorderTypeプロパティを指定するのに用います。

Clamp:最外周の輝度値を用いる

Mirror:(初期値)画像の外側から折り返した輝度値を用いる

ToZero:画像の外側は輝度値0にする

InterpolationModeEnum InterpolationModeプロパティで画素間の輝度値を取得する際の補間方法を指定するのに用います。

Bicubic:バイキュービック

Bilinear:(初期値)バイリニア

NearestNeighbor:ニアレストネイバー

MinusValueModeEnum インデクサで負の値を指定した時の処理方法を指定します。

Absolute:負の場合は絶対値をとります。

Zero:(初期値)負の場合は0にします。

 

メソッド

名前 説明
Clone() ImageDataクラスオブジェクトのクローンを作成します。画像データもコピーされます。
Clone(bool) 画像データをコピーする(true)/しない(false)を指定してImageDataクラスオブジェクトのクローンを作成します。
CopyMemory(System.IntPtr, System.IntPtr, int) コピー先のポインタ、コピー元のポインタ、コピーサイズを指定して画像データをコピーします。
CopyTo(ImagingSolution.Imaging.ImageData) 画像データを指定したImageDataクラスオブジェクトへコピーします。
Dispose() ImageDataクラスで使用されているリソースを解放します。
ImageData.IsEqualImageSize(

ImagingSolution.Imaging.ImageData, ImagingSolution.Imaging.ImageData)

2つのImageDataクラスの画像サイズが等しい(true)か等しくない(false)かを確認します。
ResetRegion()  指定した領域(Regionプロパティ)を解除します。
Save(string) ImageDataクラスの画像データをファイルに保存します。
ToBitmap() ImageDataクラスオブジェクトをSystem.Drawing.Bitmapクラスへ変換します。
ZeroMemory(System.IntPtr, int) ポインタで示されているメモリから指定バイト数分、0に設定します。

 

サンプルプログラム

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace ImageDataSample
{
    public partial class Form1 : Form
    {

        /// 
        ImagingSolution.Imaging.ImageData _img;

        public Form1()
        {
            InitializeComponent();
        }

        /// 
        /// 
        private void mnuFileOpen_Click(object sender, EventArgs e)
        {
            //ファイルを開くダイアログボックスの作成  
            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;

            if (_img != null) _img.Dispose();

            _img = new ImagingSolution.Imaging.ImageData(ofd.FileName);

            picImage.Image = _img.ToBitmap();
        }

        /// 
        /// 
        private void mnuFileSave_Click(object sender, EventArgs e)
        {
            // 画像データが設定されていない場合は何もしない
            if (_img == null) return;

            //名前を付けて保存ダイアログボックスの作成  
            var sfd = new SaveFileDialog();
            //ファイルフィルタ  
            sfd.Filter = "Bitmap(*.bmp)|*.bmp|Jpeg(*.jpg)|*.jpg|PNG(*.png)|*.png|CSV(*.csv)|*.csv";
            //ダイアログの表示 (Cancelボタンがクリックされた場合は何もしない)
            if (sfd.ShowDialog() == DialogResult.Cancel) return;

            // 名前を付けて画像データを保存
            _img.Save(sfd.FileName);
        }

        /// 
        /// 
        /// /param>
        private void mnuFileExit_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        /// 

 

ImageDataクラスライブラリへ戻る

ImageDataクラスライブラリ

画像データの取得/設定をできるだけ簡単にできることを目指したImageDataクラスライブラリに関する情報です。

 

 

 

 

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