OpenCVSharp BitMap <-> IplImage 間の変換

 いま携わっているプロジェクトで,BitMap形式の画像を IplImage に変換して OpenCVSharp を使って画像処理をやる必要があったんだけど,うまい変換方法がわからなかったので調べてみました.C# 自体そんなに強くない状態から始めたので,いろいろと勉強になってます.

 まずは,BitMap を表示するところから.

1. Windows Forms Project を生成する.

 「ファイル」->「新規作成」->「新規作成」->「プロジェクト」->「Windows フォームアプリケーション」

f:id:rkoichi2001:20160525234600p:plain

2. OpenCVSharp をプロジェクトに導入し,C# のフォーム上に写真を表示します.

 「ツール」->「NuGet パッケージマネージャ」->「ソリューションの NuGet パッケージの管理」

f:id:rkoichi2001:20160525234844p:plain

3. Form に Picture Box を追加します.

3.1 GUI コンポーネントの編集

 選択している「PictureBox」のドラッグ&ドロップで完了.

f:id:rkoichi2001:20160525234935p:plain

3.2 コード編集

 ソリューションエクスプローラに作成したフォームアイテムが表示されるので,このアイテムをダブルクリックするとテキストベースのコードが現れます.このケースの場合 「Form1.cs」 が該当.

f:id:rkoichi2001:20160526000159p:plain


 このファイルにコードを記述して,外部から取り込んだ写真を表示.追加したコードは下記のとおり.もともと持っていた写真のサイズが少し大きかったので,それを縮小して表示する部分も加えました.詳細は下記のとおり.

1. Picture Box に追加する Bitmap オブジェクトを生成する.
 Form に追加した Picture Box と同じサイズではまる Bitmap を生成します.実際に Picture Box に表示されるのはこの canvas オブジェクトになります.

Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);

2. canvas オブジェクト上の Image を操作するために,Graphics オブジェクトを取得します.

Graphics g = Graphics.FromImage(canvas);

3. canvas 上での Image 操作の際の補完方法を指定します.

g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;

4. 写真から Bitmap オブジェクトを生成します.
 実際に加工されるイメージの元となる Bitmap を生成します.こいつが canvas 上にコピーされて,canvas 上にコピーされたものに対していろいろと操作を加えるという流れになります.

Bitmap pic = new Bitmap(@"C:\\Users\\Koichi\\Documents\\Visual Studio 2013\\Projects\\ConsoleApplication1\\OpenCVSharpSample\\img\\boeing777.jpg");

5. オリジナルの Bitmap を canvas 上にコピーすると同時に拡大・縮小も実施します(されます).

g.DrawImage(pic, 0, 0, 500, 500);

6. 元のイメージ,および Graphics オブジェクトは必要なくなったので,消去!

pic.Dispose();
g.Dispose();

7. 拡大・縮小したイメージを Picture Box に紐づける.

pictureBox1.Image = canvas;
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 WindowsFormsApplicationExample
{
    public partial class Form1 : Form
    {

        private void DisplayBitmap()
        {
            // 1. Image Object Creation.
            Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            // 2. Generate Graphics Object from Image.
            Graphics g = Graphics.FromImage(canvas);
            // 3. Specify Interpolation Mode.
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            // 4. Generate Bitmap Object from picture.
            Bitmap pic = new Bitmap(@"C:\\Users\\Koichi\\Documents\\Visual Studio 2013\\Projects\\ConsoleApplication1\\OpenCVSharpSample\\img\\boeing777.jpg");
            // 5. Reduce Size of Picture and paint it to canvas.
            g.DrawImage(pic, 0, 0, 500, 500);
            // 6. Dispose unnecessary "pic" and graphics.
            pic.Dispose();
            g.Dispose();
            // 7. Display image.         
            pictureBox1.Image = canvas;
            
        }

        public Form1()
        {
            InitializeComponent();
            DisplayBitmap();
        }
    }
}


実行結果は下記のとおり.
f:id:rkoichi2001:20160526003811p:plain

3. System.Drawing.Bitmap -> IplImage 間の変換を実施

 ここからがやっと本題です...2 のステップで,Bitmap をフォーム上に表示するところまでは行きました.今度は,こいつを OpenCVSharp の画像形式に変換して OpenCVSharp の Window でも表示します.

1. 表示したイメージを取得する.

Image img = pictureBox1.Image;

2. 表示したイメージと同じサイズ・フォーマットの IplImage を用意する.

IplImage convertedImg = new IplImage(new CvSize(img.Width, img.Height), BitDepth.U8, 3);

3. Bitmap フォーマットから IplImage にコピーする.

convertedImg.CopyFrom(img as Bitmap);

4. OpenCV 流に表示する.

Cv.ShowImage("CvSharpImage", convertedImg);

 なんか,3 のステップだけを書いたらええやんけ!っていう気もしますが,自分の練習・備忘も含まれてるのでご容赦を!ちなみに,ここで紹介しているのは Bitmap -> IplImage の変換ですが,下記のようにすれば逆の変換もできます.

System.Drawing.Image img = iplImage.ToBitmap();
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;

using OpenCvSharp;
using OpenCvSharp.Extensions;

namespace WindowsFormsApplicationExample
{
    public partial class Form1 : Form
    {

        private void DisplayBitmap()
        {
            // 1. Image Object Creation.
            Bitmap canvas = new Bitmap(pictureBox1.Width, pictureBox1.Height);
            // 2. Generate Graphics Object from Image.
            Graphics g = Graphics.FromImage(canvas);
            // 3. Specify Interpolation Mode.
            g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor;
            // 4. Generate Bitmap Object from picture.
            Bitmap pic = new Bitmap(@"C:\\Users\\Koichi\\Documents\\Visual Studio 2013\\Projects\\ConsoleApplication1\\OpenCVSharpSample\\img\\boeing777.jpg");
            // 5. Reduce Size of Picture and paint it to canvas.
            g.DrawImage(pic, 0, 0, 500, 500);
            // 6. Dispose unnecessary "pic" and graphics.
            pic.Dispose();
            g.Dispose();
            // 7. Display image.                        
            pictureBox1.Image = canvas;
            
        }

        private void DisplayPictureByOpenCVSharp()
        {
      // 1. Get Displayed Image.
            Image img = pictureBox1.Image;

      // 2. Instantiate OpenCV Image Class.
            IplImage convertedImg = new IplImage(new CvSize(img.Width, img.Height), BitDepth.U8, 3);

      // 3. Copy data from Bitmap.            
            convertedImg.CopyFrom(img as Bitmap);

      // 4. Display Image.
            Cv.ShowImage("CvSharpImage", convertedImg);

        }

        public Form1()
        {
            InitializeComponent();
            DisplayBitmap();
            DisplayPictureByOpenCVSharp();
        }
    }
}

実行結果は下記のとおり.
(若干端が黒くなっていてサイズが合ってないですが,,,とりあえず細かいことは置いといてということで...)

f:id:rkoichi2001:20160526010304p:plain