画像処理ソリューション
これを見れば画像処理の入門から基礎〜応用まで全てがわかるのを目指して!
   
プロフィール

Author:Akira
男性
東京都の町田事業所に勤務
画像処理ソフトの開発を行っています。
リンクフリーです!

ブログ内検索

画像処理製品

画像処理ツール 
プログラムレスで直観的に画像処理ができる!アルゴリズムの構築検討、画像処理の学習には最適。30日間お試し版あり。

画像入力ボード 
CameraLink、デジタル、アナログ、エリアセンサ、ラインセンサカメラ、PCI、PCI-Express各種対応。

動画記録ソフト 
工業用CCDカメラの動画を非圧縮で保存。ラインセンサカメラも対応。RAIDシステムを使うことで、高速大容量の動画も保存可能。動画の記録、解析用途向け。

カテゴリ

最近のコメント

FC2カウンター

オンラインカウンタ

現在の閲覧者数:

カレンダー

10 | 2009/11 | 12
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 - - - - -

趣味のブログ

iPhone萬歳!
iPhoneの情報いろいろ。(まだまだこれから)
俺流クラフト日記
ハンドメイド作品の記録(現在、放置中)

最近の記事
  【DirectShow】SDKサンプルプログラムAmCapのビルド方法(11/21)
  【OpenCV】行列の積(cvMul、cvMatMul)での注意点(11/20)
  Essential OpenCV Programming with Visual C++ 2008(11/07)
  パターンマッチング(正規化相関など)(11/04)
  '09国際画像機器展 展示会情報(10/26)
  DirectShow SDKの入手、ダウンロード(10/22)
  トランジスタ技術の表紙、飾りました!(10/22)
  【OpenCV2.0】C++/CLIによるサンプルプログラム(Ver2.0対応版)(10/15)
  Excel2007で鏡面反射効果を付ける(10/08)
  画像処理用標準画像データ入手、ダウンロード先(10/07)
  OpenCV 2.0 入手、ダウンロード、インストール、環境設定(10/05)
  【OpenCV2.0】cv::Matクラス(10/04)
  OpenCV2.0ReleaseをCMakeを使ってビルドする(10/01)
  OpenCV 2.0 Release版が公開されました。(09/30)
  正規直交基底(09/25)
  【C++/CLI】バージョンの設定方法(09/24)
  新編 画像解析ハンドブック(東京大学出版会)(09/24)
  ラインセンサカメラとエンコーダとの同期撮影方法(09/24)
  疑似カラー(Pseudo-color)(09/23)
  色相、彩度、明度ほか(09/23)
  詳解 OpenCV――コンピュータビジョンライブラリを使った画像処理・認識(09/19)
  OpenCV2.0beta格闘中!メモ(09/12)
  OpenCV 2.0beta版が公開されました(09/11)
【C++/CLI】画像の輝度値を取得、設定する
一般的にGetPixel、SetPixelにより画像の輝度値を取得、設定する方法がよく解説されていますが、モノクロ8Bitの画像データではSetPixelが使えなかったり、処理速度が遅いので、画像データにポインタでアクセスする方法を説明したいと思います。

◆サンプルプログラムのイメージ

 

画像の輝度値の取得、設定 
サンプルプログラムのソースは、以下のリンクを『右ボタンクリック⇒対象をファイルに保存』
  VisualStudio2008Express版
  VisualStudio2005Express版
でダウンロードできます。


◆画像ファイルを開く

private: System::Void button1_Click(System::Object^  sender, System::EventArgs^  e) {
    //ファイルを開く
   
    //ファイルを開くダイアログ
    OpenFileDialog^ OpenDlg = gcnew OpenFileDialog;
    //ファイルフィルタ
    OpenDlg->Filter = "画像ファイル(*.bmp,*.jpg,*.jpeg,*.png,*.tif,*.tiff,*.ico)|*.bmp;*.jpg;*.jpeg;*.png;*.tif;*.tiff;*.ico";
    //ダイアログの表示
    OpenDlg->ShowDialog();
   
    if (OpenDlg->FileName == ""){
     //ファイル名が指定されなかった場合
     return;
    }

    //Bitmapをファイルより作成
    bmp = gcnew Bitmap(OpenDlg->FileName);

    //ピクチャボックスへ画像の表示
    pictureBox1->Image = bmp;
   
   }


開くことのできる画像ファイルは、bmpファイル、jpegファイル、pngファイル、tifファイル、icoファイルです。

◆輝度値の取得、設定 

private: System::Void button3_Click(System::Object^  sender, System::EventArgs^  e) {
    //輝度値の取得、設定(二値化)
   
    int i, j;
    int Bright; //モノクロ輝度値
    int B, G, R;//カラー輝度値
    int BitCount;
    int Step;
    Byte Threshold;

    //しきい値の取得
    bool result = Byte::TryParse(textBox1->Text, Threshold);
    if (result == false) return;

    //輝度値を取得、設定する領域
    Rectangle rect = System::Drawing::Rectangle(0, 0, bmp->Width, bmp->Height);

    //Lock
    Imaging::BitmapData^ bmpData = bmp->LockBits(rect, Imaging::ImageLockMode::ReadWrite, bmp->PixelFormat);
   
    //ビットマップデータのメモリのポインタ
    Byte* pBuf = (Byte*)bmpData->Scan0.ToPointer();

    //画像データのビット数
    BitCount = bmp->GetPixelFormatSize(bmp->PixelFormat);

    //輝度値の取得、設定
    switch (bmp->PixelFormat){
       case Imaging::PixelFormat::Format8bppIndexed:
          //8ビットデータの場合

          for (j = 0; j < rect.Height; j++){
             for (i = 0; i < rect.Width; i++){
                //輝度値の取得
                Bright = pBuf[i + j * bmpData->Stride];

                //輝度値の設定(二値化)
                if (Bright >= Threshold)
                   pBuf[i + j * bmpData->Stride] = 255; //白に設定
                else
                   pBuf[i + j * bmpData->Stride] = 0;  //黒に設定
              }
           }

           break;

       case Imaging::PixelFormat::Format24bppRgb:
          //24ビットカラーデータの場合
          //輝度値は
B,G,R,B,G,R・・・の順で格納されています。
       case Imaging::PixelFormat::Format32bppRgb:
          //32ビットカラーデータの場合
          //輝度値は
B,G,R,A,B,G,R,A・・・の順で格納されています。
    
          Step = BitCount / 8;

          for (j = 0; j < rect.Height; j++){
             for (i = 0; i < rect.Width; i++){
                //輝度値の取得
                B = pBuf[i * Step +     j * bmpData->Stride]; //青
                G = pBuf[i * Step + 1 + j * bmpData->Stride]; //緑
                R = pBuf[i * Step + 2 + j * bmpData->Stride]; //赤

                //輝度値の設定(二値化)
                if ((B >= Threshold) || (G >= Threshold) || (R >= Threshold)){
                   pBuf[i * Step +     j * bmpData->Stride] = 255; //青
                   pBuf[i * Step + 1 + j * bmpData->Stride] = 255; //緑
                   pBuf[i * Step + 2 + j * bmpData->Stride] = 255; //赤
                 }else{
                    pBuf[i * Step +     j * bmpData->Stride] = 0; //青
                    pBuf[i * Step + 1 + j * bmpData->Stride] = 0; //緑
                    pBuf[i * Step + 2 + j * bmpData->Stride] = 0; //赤 
                 }
             }
          }

         break;
    
       default:
          MessageBox::Show("未対応ファイルフォーマットです。");
          bmp->UnlockBits(bmpData);
          return;
    }

    //UnLock
    bmp->UnlockBits(bmpData);

    //ピクチャボックスへ画像の表示
    pictureBox1->Image = bmp;

   }


最初に輝度値を取得する画像の範囲を指定します。

   
Rectangle rect = System::Drawing::Rectangle(0, 0, bmp->Width, bmp->Height);

座標は画像の左上が原点(0,0)となり、画像の右下が(Width - 1、Height - 1)となります。
この例では画像全体の領域を指定していますが、例えば

  
Rectangle rect = System::Drawing::Rectangle(50, 50, 150, 150);

のように画像の一部分を指定することも可能です。

【処理例】

画像のRegion Of Interest(ROI)処理

この処理は画像処理でいうところのRegion of interest(ROI)処理ですが、簡単にできちゃいます。
この時、画像データのポインタが画像の左上からRectangleで指定した領域の左上の位置へ移動するだけですので、ご注意下さい。(Strideの値に変わりはありません。)


輝度値の参照、設定にはBitmapDataプロパティのScan0プロパティを使って、画像データにポインタで参照します。

  
Byte* pBuf = (Byte*)bmpData->Scan0.ToPointer();

こうして得られた画像データのポインタ(pBuf)を使うことで画像データを参照、設定することができるようになります。
このポインタであらわされるメモリには画像の左から右、上から下へ向かって輝度値データが格納されています。通常のBitmapファイルのバイナリデータの向きとは上下が逆になるのでご注意下さい。

また、メモリの幅は従来どおり、4の倍数バイトとなるように調整されています。
この幅(バイト数)は

  bmpData->Stride

で取得できます。

このポインタ(pBuf)へは通常のC言語のポインタと同様に参照することができ、mallocなどで確保したメモリを、memcpy関数を使って画像データにコピーすることもできます。
ただし、ポインタへの書き込みはLockBitsのときの第二引数(ImageLockMode flags)が

  Imaging::ImageLockMode::ReadWrite

になっている必要があります。
この処理が可能なのは、LockBits〜UnlockBitsまでの間です。

◆画像のファイル保存 

Private: System::Void button2_Click(System::Object^  sender, System::EventArgs^  e) {
    //名前を付けて保存
   
    //ファイルを保存ダイアログ
    SaveFileDialog^ SaveDlg = gcnew SaveFileDialog;
    //ファイルフィルタ
    SaveDlg->Filter = "ビットマップファイル(*.bmp)|*.bmp|jpegファイル(*.jpg)|*.jpg|pngファイル(*.png)|*.png|tifファイル(*.tif)|*.tif";

    //ダイアログの表示
    SaveDlg->ShowDialog();
   
    if (SaveDlg->FileName == ""){
       //ファイル名が指定されなかった場合
       return;
    }else{
       //画像を名前を付けて保存

       //ファイル名の拡張子を取得し、小文字へ変換
       String^ ext = System::IO::Path::GetExtension(SaveDlg->FileName)->ToLower();

       //拡張子ごとに保存フォーマットを指定
       if (ext == ".bmp")
          //ビットマップ
          bmp->Save(SaveDlg->FileName, Imaging::ImageFormat::Bmp);
       else if (ext == ".jpg")
          //Jpeg
          bmp->Save(SaveDlg->FileName, Imaging::ImageFormat::Jpeg);
       else if (ext == ".png")
          //Ping
          bmp->Save(SaveDlg->FileName, Imaging::ImageFormat::Png);
       else if (ext == ".tif")
          //Tiff
          bmp->Save(SaveDlg->FileName, Imaging::ImageFormat::Tiff);
    }     
   }

画像のファイルへの保存は、ファイル名とファイルフォーマットを指定するだけで可能です。
Saveメソッドの第二引数(ImageFormat)は省略することも可能ですが、省略した場合、PNGファイルとして保存される場合があります。保存されたファイルのプロパティを見ただけでは、PNGファイルで保存されているかどうか分かりづらいので、できるだけ、フォーマットは指定しておいた方が無難です。



テーマ:画像処理 - ジャンル:趣味・実用

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

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














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


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