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

シェアする

  • このエントリーをはてなブックマークに追加
最近の記事
  • 10/21 【C#】寸法線の描画
  • 10/21 【C#】GraphicsPathの領域取得
  • 10/20 【C#】GraphicsPathの描画
  • 10/18 【C#】GraphicsPath
  • 10/17 【C#】Bitmap画像データの拡大縮小
  • 10/15 【C#】画像の座標系
  • 10/14 【C#】画像の上下左右反転、90,180,270度回転
  • 10/3 【C#】SplitContainerのPanel固定方法
  • 9/7 【Neural Network Console】学習データの出力方法
  • 9/3 Deep Learning向け学習画像撮り込みソフト公開
  • 9/1 【Neural Network Console】新規画像のDataset作成方法
  • 8/28 【Neural Network Console】GUI表示スケールの変更
  • 8/22 【Neural Network Console】CPU/GPU処理の設定切替
  • 8/21 【Neural Network Console】Learning Rate(学習率)の設定
  • 8/20 ソニーの無償AIソフト Neural Network Consoleの入手ダウンロード、インストール
  • 8/20 Deep Learning
  • 8/20
  • 8/19 古いバージョンのVisual Studio Community/Expressの入手ダウンロード
  • 8/19 CUDAの入手、ダウンロード、インストール方法
  • 8/17 【C#.NET】マイクロソフト仕様のアフィン変換
  • 8/5 【C#】ファイルを開くダイアログボックスの表示
  • 8/2 キャノンプリンターのCDトレイはどこ?!
  • 7/6 【参考書籍】画像処理・機械学習プログラミング OpenCV 3対応
  • 6/20 【Python,matplotlib】動くグラフをAnimationGifに保存する方法
  • 6/17 シグモイド関数の微分
  • 6/15 シグモイド関数
  • 6/13 合成関数の微分
  • 6/12 WordPressで数式エディタ風に数式を入力したい
  • 6/11 PythonをVisual Studioでインストールする方法
  • 6/9 【Python】OpenCVをAnacondaでインストール(Windows編)
  • 6/6 【Python】Anacondaで複数バージョンの環境切り替え
  • 6/6 画像センシング展2017に出展します。
  • 6/1 【Office365】Web版Outlookのフォントサイズ変更
  • 6/1 【Anaconda】モジュールのアップデートでエラー発生
  • 6/1 【Anaconda】コマンドリストの表示
  • 5/29 Windows10パソコン購入
  • 5/24 Anacondaのアンインストール
  • 5/24 【Jupyter Notebook】新規プログラムの作成
  • 5/23 【Python】開発環境の構築
  • 5/23 Pythonはじめました
  • 4/6 【Office365】Web版Outlookのスレッド表示を解除する方法
  • 4/5 【Excel】フーリエ解析(FFT)
  • 3/20 Canny edge detection
  • 3/20 【Excel2016】分析ツールの表示
  • 3/5 【Visual Studio】黒い背景色を白に変更する方法
  • 2/8 【Windows10】拡張モニタに表示されたウィンドウを元に戻す
  • 2/7 複素数の計算
  • 1/18 【Excel】棒グラフの横軸の目盛を0始まりにする
  • 1/16 【Excel】フーリエ変換
  • 1/6 【OpenCV】疑似カラー(カラーマップ)

  • 画像処理プログラムの基本は画像の輝度値(画素値)を取得して、様々な処理をすることとなりますが、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
        {
    
            /// <summary>
            /// 表示用ImageDataクラスオブジェクト
            /// </summary>
            ImagingSolution.Imaging.ImageData _img;
    
            public Form1()
            {
                InitializeComponent();
            }
    
            /// <summary>
            /// 画像ファイルを開く
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            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();
            }
    
            /// <summary>
            /// 名前を付けて画像を保存
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            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);
            }
    
            /// <summary>
            /// 終了
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void mnuFileExit_Click(object sender, EventArgs e)
            {
                this.Close();
            }
    
            /// <summary>
            /// 輝度値の表示
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private void picImage_MouseMove(object sender, MouseEventArgs e)
            {
                if (_img == null) return;
    
                // X座標
                int px = e.X;
                // Y座標
                int py = e.Y;
    
                if (_img.Channel == 1)
                {
                    // モノクロの場合
                    lblBright.Text = "(" + px.ToString() + ", " + py.ToString() + ") = "
                        + _img[py, px].ToString();
    
                }
                else if (_img.Channel == 3)
                {
                    // カラーの場合
                    lblBright.Text = "(" + px.ToString() + ", " + py.ToString() + ") = ("
                        + _img[py, px, 2].ToString() + ", " // R
                        + _img[py, px, 1].ToString() + ", " // G
                        + _img[py, px, 0].ToString() + ")"; // B
                }
    
            }
    
            private void mnuFilter_Click(object sender, EventArgs e)
            {
                // フィルタ処理
    
                if (_img == null) return;
    
                var sw = new System.Diagnostics.Stopwatch();
    
                // 時間計測開始
                sw.Start();
    
                // 処理後のImageDataクラス
                ImagingSolution.Imaging.ImageData dst = null;
    
                // クリックされたメニュー
                var mnu = sender as System.Windows.Forms.ToolStripMenuItem;
    
                switch (mnu.Text){
    
                    case "GrayScale":
                        // グレースケール変換
                        ConvertGrayScale(_img, ref dst);
    
                        break;
    
                    case "Gaussian":
                        // ガウシアンフィルタ
                        GaussianBlur(_img, ref dst);
                        break;
    
                    case "Sobel":
                        // ソーベルフィルタ
                        Sobel(_img, ref dst);
                        break;
                }
    
                // 時間計測停止
                sw.Stop();
    
                // 処理時間の表示
                lblTime.Text = sw.ElapsedMilliseconds.ToString() + "mSec";
    
                // 元の画像データを解放
                _img.Dispose();
    
                // 表示用画像データを設定
                _img = dst;
    
                // 画像の表示
                picImage.Image = _img.ToBitmap();
    
            }
    
            /// <summary>
            /// グレースケールへ変換
            /// </summary>
            private void ConvertGrayScale(ImagingSolution.Imaging.ImageData src, ref ImagingSolution.Imaging.ImageData dst)
            {
                int i, j;
                int width = src.Width;
                int height = src.Height;
    
                // dstが無効の場合、モノクロのImageDataクラスをインスタンス
                if (dst == null) dst = new ImagingSolution.Imaging.ImageData(width, height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed);
    
                for (j = 0; j < height; j++)
                {
                    for (i = 0; i < width; i++)
                    {
                        dst[j, i] = (int)(
                            src[j, i, 2] * 0.299   // R 
                          + src[j, i, 1] * 0.587   // G
                          + src[j, i, 0] * 0.114); // B
                    }
                }
            }
    
            /// <summary>
            /// ガウシアンフィルタ
            /// </summary>
            /// <param name="src"></param>
            /// <param name="dst"></param>
            private void GaussianBlur(ImagingSolution.Imaging.ImageData src, ref ImagingSolution.Imaging.ImageData dst)
            {
                int i, j;
                int width = src.Width;
                int height = src.Height;
                int channel = src.Channel;
    
                // dstが無効の場合、ImageDataクラスオブジェクトのクローンを作成
                if (dst == null) dst = src.Clone(false);
    
                for (j = 0; j < height; j++)
                {
                    for (i = 0; i < width * channel; i++)
                    {
                        dst[j, i] = (
                            src[j - 1, i - channel] + src[j - 1, i] * 2 + src[j - 1, i + channel]
                            + src[j, i - channel] * 2 + src[j, i] * 4 + src[j, i + channel] * 2
                            + src[j + 1, i - channel] + src[j + 1, i] * 2 + src[j + 1, i + channel]
                            ) / 16;
                    }
                }
            }
    
            /// <summary>
            /// ソーベルフィルタ
            /// </summary>
            /// <param name="src"></param>
            /// <param name="dst"></param>
            private void Sobel(ImagingSolution.Imaging.ImageData src, ref ImagingSolution.Imaging.ImageData dst)
            {
                int i, j;
                int width = src.Width;
                int height = src.Height;
                int channel = src.Channel;
    
                // 処理後画像データを確保(メモリのコピーはしない)
                var XSobel = src.Clone(false);
                var YSobel = src.Clone(false);
    
                // 負の値は絶対値にする
                XSobel.MinusValueMode = ImagingSolution.Imaging.ImageData.MinusValueModeEnum.Absolute;
                YSobel.MinusValueMode = ImagingSolution.Imaging.ImageData.MinusValueModeEnum.Absolute;
    
                for (j = 0; j < height; j++)
                {
                    for (i = 0; i < width * channel; i++)
                    {
                        XSobel[j, i] = (
                            -src[j - 1, i - channel] + src[j - 1, i + channel]
                            - src[j, i - channel] * 2 + src[j, i + channel] * 2
                            - src[j + 1, i - channel] + src[j + 1, i + channel]
                            );
                        YSobel[j, i] = (
                            -src[j - 1, i - channel] - src[j - 1, i] * 2 - src[j - 1, i + channel]
                            + src[j + 1, i - channel] + src[j + 1, i] * 2 + src[j + 1, i + channel]
                            );
                    }
                }
                // X方向とY方向を足し合わせる
                dst = XSobel + YSobel;
    
                // 解放
                XSobel.Dispose();
                YSobel.Dispose();
            }
        }
    }
    
    
    

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

    コメント

    1. […] 3/17 【C#】ImageDataクラスライブラリ公開 […]