画像処理ソリューション
これを見れば画像処理の入門から基礎~応用まで全てがわかるのを目指して!
   
翻訳(Translate)

プロフィール

Akira

ニックネーム:Akira
東京都の町田事業所に勤務
画像処理ソフトの開発を行っています。リンクフリーです!
詳細プロフィールは こちら
お問い合わせは、こちら↓

【補助HP】
画像処理ソリューションWeb版 【Newブログ】
イメージングソリューション

スポンサーリンク


カテゴリ

最近のコメント

カレンダー

09 | 2017/10 | 11
S M T W T F S
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31 - - - -

趣味のブログ

iPhone萬歳!
iPhoneの情報いろいろ。
ブログ学習帳
ブログ、SEO、アフィリエイト情報など(まだまだこれから)
俺流クラフト日記
ハンドメイド作品の記録(現在、放置中)

スポンサーリンク 最近の記事
(09/18)  計測測定展に光切断のデモを出展しました
(08/17)  ディジタル画像技術事典200に記事が載りました
(06/09)  光切断を画像センシング展で公開
(05/14)  中国(上海)へ行って来ました
(04/12)  韓国へ行って来ました
(03/10)  私の求める新人像
(01/18)  エレクトロテストジャパンにカラー光切断法のデモを出展しました。
(12/23)  ユニークアクセス200万達成!
(12/10)  【カラー光切断法】YouTube動画まとめ
(11/04)  国際画像機器展2014にカラー光切断法を出展します。
(10/05)  第25回コンピュータビジョン勉強会@関東に参加してきました。
(09/08)  フーリエ変換の記事を追加しました。
(08/09)  【画像処理】ランキング低下中
(07/06)  記事の更新が停滞中...
(06/08)  画像センシング展2014でカラー光切断法のデモを行います。
(05/17)  カラー光切断法の動画を公開しました。
(04/30)  ソニーα NEX-5Rで星空撮影
(04/10)  カラー光切断法の取込結果を追加しました
(03/08)  Korea Vision Show 2014へ行ってきました
(02/05)  フーリエ変換シリーズを始めます。
(01/06)  2014年、あけましておめでとうございます。
(12/04)  カラー光切断法を公開(国際画像機器展2013にて)
(11/13)  国際画像機器展2013に出展します
(10/14)  「画像処理のためのC#」はじめます。
(09/16)  【C#,VB.NET】高速描画コントロールをバージョンアップしました。
(09/04)  拡大鏡に輝度値表示、ルーラー機能を追加した個人ツールを公開
(08/05)  7月の拍手Top5
(07/06)  2013年6月人気記事Top5
(05/12)  SONY α NEX-5Rレビュー
(04/24)  SONY α NEX-5RY購入

【OpenCV】C++/CLIによるサンプルプログラム

 

.NETを使ったOpenCVのサンプルプログラムを探すと、OpenCVDotNetやC#用のSharperCVというようなラッパライブラリを使った解説が多いのですが、ここではそれらを使わず、C++/CLIのみでOpenCVのサンプルプログラムを作成してみました。


OpenCV2.0用のサンプルプログラムは
  【OpenCV2.0】C++/CLIによるサンプルプログラム
のページを参照願います。
以下記事はOpenCV1.0の場合です。


で、作成したプログラムはこんな感じ↓
C++/CLIによるOpenCVのサンプルプログラム

機能としては
 ■二値化
 ■平滑化
 ■ガウシアン
 ■膨張
 ■収縮
 ■輝度値の表示
 ■処理時間の表示


ぐらいの簡単なものです。
処理できる画像は24bitのカラー画像のみです。
モノクロ画像の場合、IplImageからBitmapへ変換している部分と、輝度値を拾ってきている部分が対応できていません。

で、サンプルプログラムは
こちら(右ボタン→対象をファイルに保存)よりダウンロードできます。
Visual C++ 2005 Express Editionで作成しています。 )
ただし、プログラムを実行する前にOpenCVのインストールなど、OpenCVが動作する環境設定が必要です。これらについては下記ページを参照下さい。
◆OpenCVの入手ダウンロード、インストール、環境設定
◆開発環境(VisualStudio)の設定

注!!!
OpenCVのVer.1.1prea1版をインストールすると、ファイルを開くとき、
 -----------------------------------------------------------------
'System.Threading.ThreadStateException' のハンドルされていない例外が System.Windows.Forms.dll で発生しました。

追加情報: OLE が呼び出される前に、現在のスレッドが Single Thread Apartment (STA) モードに設定されていなければなりません。Main 関数に STAThreadAttribute が設定されていることを確認してください。 この例外はデバッガがプロセスにアタッチされている場合にのみ発生します。
 -----------------------------------------------------------------
というメッセージが出て、ファイルを開く事ができません。
その場合は、現状ではVer1.0版のOpenCVをインストールして下さい。


以下、簡単なソースの解説です。

 画像ファイルの読込
ファイルメニューのファイル→開くでファイルを開くダイアログボックスを使って、画像ファイルを選択し、cvLoadImage関数で画像の読込を行っています。

 private: System::Void mnuFileOpen_Click(System::Object^  sender, System::EventArgs^  e) {
     //ファイルメニュー⇒開く

     ///////////////////////////////////
     //  ビットマップファイルの取得
     //  
     //ファイルを開くダイアログの作成

     OpenFileDialog^ dlg = gcnew OpenFileDialog;
     //ファイルフィルタ
     dlg->Filter = "画像ファイル(*.bmp,*.jpg,*.png,*.tif,jp2)|*.bmp;*.jpg;*.png;*.tif;*.jp2";
     //ダイアログの表示
     if (dlg->ShowDialog() == System::Windows::Forms::DialogResult::Cancel) return;
     //System::String^型のファイル名
     System::String^ strFilename = dlg->FileName;

     ///////////////////////////////////
     // src_img の解放
     //
     if (src_img != NULL){
      IplImage *temp_img = src_img;
      cvReleaseImage(&temp_img);
      src_img = NULL;
     }   
    
     ///////////////////////////////////
     //  IplImageの確保
     //
     //System::String^からchar*へ変換
     char* pStr = (char*)System::Runtime::InteropServices::Marshal::StringToHGlobalAnsi(strFilename).ToPointer();
     //アンマネージ関数へchar*を渡す
     src_img = cvLoadImage(pStr, CV_LOAD_IMAGE_ANYDEPTH | CV_LOAD_IMAGE_ANYCOLOR);
     //メモリの解放
     System::Runtime::InteropServices::Marshal::FreeHGlobal(IntPtr(pStr));

     ///////////////////////////////////
     //IplImageをピクチャボックスへ描画
     //
     DrawCvImage(src_img);

    }

ここでのポイントはStringToHGlobalAnsiメソッドを使ってString^からchar*に変換している部分でしょうか。


 IplImageのPictureBoxへの描画

OpenCVの画像データのポインタ(imageData)をBitmapへ渡し、Bitmapを確保して、DrawImageを使ってピクチャボックスへ描画しています。

 private: System::Void DrawCvImage(IplImage *CvImage) {
    //IplImageをピクチャボックスへ描画
   
    ///////////////////////////////////
    //  Graphicsの確保
    //

    if ((pictureBox1->Image == nullptr)
     || (pictureBox1->Width != CvImage->width)
     || (pictureBox1->Height != CvImage->height)){
     //ピクチャボックスをビットマップ画像サイズに合わせる
     pictureBox1->Width = CvImage->width;
     pictureBox1->Height = CvImage->height;
     //PictureBoxと同じ大きさのBitmapクラスを作成する。
     Bitmap^ bmpPicBox = gcnew Bitmap(pictureBox1->Width, pictureBox1->Height);
     //空のBitmapをPictureBoxのImageに指定する。
     pictureBox1->Image = bmpPicBox;
    }

    //Graphicsクラスの作成(空のピクチャボックスからGraphicsを作成する)
    Graphics^g = Graphics::FromImage(pictureBox1->Image);
   
    ///////////////////////////////////
    //  IplImageからBitmapの確保
    //     
    //IplImageの画像データのポインタ(imageData)をBitmapへ渡し、Bitmapを作成

    Bitmap^ bmp = gcnew Bitmap(CvImage->width, CvImage->height, CvImage->widthStep,
     System::Drawing::Imaging::PixelFormat::Format24bppRgb, IntPtr(CvImage->imageData));

   
    ///////////////////////////////////
    //  画像の描画
    //
    //ピクチャボックスのImageへ

    g->DrawImage(bmp, 0, 0, CvImage->width, CvImage->height); 
    pictureBox1->Refresh();
   
    delete g;
   }



 OpenCVの処理

サンプルプログラムのメニューのOpenCV以下のフィルタ処理のイベント処理は、それぞれのイベントごとに処理を書くのが面倒だったので、全て同じイベント処理を通すようにしてみました。

private: System::Void mnuOpenCV_Click(System::Object^  sender, System::EventArgs^  e) {
    //OpenCVメニュー

    //処理後の画像データ
    IplImage* dst_img;
    //描画時間計測用
    Diagnostics::Stopwatch^ sw = gcnew Diagnostics::Stopwatch;  
    //メニューアイテム(どのメニューがクリックされたのか?)
    ToolStripMenuItem^ mnu = (ToolStripMenuItem^)sender;

    //画像データが無い場合
    if (src_img == NULL) return;

    //処理時間計測開始
    sw->Start();

    //src_imgと同じサイズのIplImageの確保
    dst_img = cvCreateImage(cvSize(src_img->width, src_img->height),
         src_img->depth, src_img->nChannels);

    //クリックされたメニューごとにOpenCVの処理
    if (mnu->Name == "mnuThreshold"){
     //二値化(しきい値127)
     cvThreshold(src_img, dst_img, 127, 255, CV_THRESH_BINARY);

    }else if (mnu->Name == "mnuSmooth3_3"){
     //平滑化(3×3)
     cvSmooth(src_img, dst_img, CV_BLUR, 3, 3);

    }else if (mnu->Name == "mnuGaussian21_21"){
     //ガウシアン(21×21)
     cvSmooth(src_img, dst_img, CV_GAUSSIAN , 21, 21);

    }else if (mnu->Name == "mnuDilate"){
     //膨張
     cvDilate(src_img, dst_img, NULL , 1);

    }else if (mnu->Name == "mnuErode"){
     //収縮
     cvErode(src_img, dst_img, NULL , 1);

    }else{
     return;
    }

    //処理後の画像を元の画像データにコピーする。
    cvCopy(dst_img, src_img);

    //解放
    cvReleaseImage(&dst_img);

    //処理時間計測停止
    sw->Stop();

    //処理時間の表示
    toolStripStatusLabel2->Text =
     mnu->Text + "処理時間 = " + sw->ElapsedMilliseconds.ToString() + "msec";

    //画像の描画
    DrawCvImage(src_img);

   }


 輝度値の取得

画像の輝度値はピクチャボックスのMouseMoveイベントでマウスポインタの位置の輝度値をステータスバーに表示するようにしました。
OpenCVにおける輝度値はIplImageのimageDataのポインタを参照することで拾うことができるのですが、imageDataのポインタはなぜか符号付char型になっているので、符合なしのucharで受けています。
って、
opencv.jpの内容をそのままマネしただけですけど...

private: System::Void pictureBox1_MouseMove(System::Object^  sender, System::Windows::Forms::MouseEventArgs^  e) {
   
//画像の輝度値の表示

    //画像データが無い場合
    if (src_img == NULL) return;

    //輝度値の取得
    uchar p[3];
    p[0] = src_img->imageData[src_img->widthStep * e->Y + e->X * 3];        // B
    p[1] = src_img->imageData[src_img->widthStep * e->Y + e->X * 3 + 1];    // G
    p[2] = src_img->imageData[src_img->widthStep * e->Y + e->X * 3 + 2];    // R

    //輝度値表示
    //輝度値(X座標, Y座標) = (R, G, B)
    toolStripStatusLabel1->Text =
     "輝度値(" + e->X.ToString() + "," + e->Y.ToString() + ") = (" +
     p[2].ToString() + "," + p[1].ToString() + "," + p[0].ToString() + ")" ;
   }



Loading...
スポンサーリンク

この記事に対するコメント

とても魅力的な記事でした!!
また遊びに来ます!!
ありがとうございます。。
【2012/02/01 15:20】 URL | 履歴書のサンプル #- [ 編集]


この記事に対するコメントの投稿














管理者にだけ表示を許可する


この記事に対するトラックバック
トラックバックURL
→http://imagingsolution.blog107.fc2.com/tb.php/91-c8ad5dcd
この記事にトラックバックする(FC2ブログユーザー)

現在の閲覧者数: / 合計