OpenCV cvcam - eiichiromomma/CVMLAB GitHub Wiki

(OpenCV) cvcam

OpenCVのcvcam.hを使って動画像処理プログラムの作成

以下に使い方は記したが、大きい画面を弄ろうとするとランタイムエラーが発生する。 これを回避するためにDirectShowからフレームをダイレクトに書き込むにはOpenCV DirectShowを参照。

準備

当たり前だがUSBカメラ等を接続しておく。

サンプルソースのビルド

C:\Program Files\OpenCV\otherlibs\cvcam\sampleのcvcamdemoプロジェクトを開きビルド。 実行するとウィンドウに動画像が表示される。

簡単な解説

関数については必要に応じて[[OpenCV/関数リファレンス)関数リファレンス に追加の予定。

    #include "cvcam.h" //カメラを使うのでcvcam.hをインクルードする。
    #include "highgui.h"
    
    /**************************************************************************\
               How to set video resolution programatically
    \**************************************************************************/ 
    //コールバック関数
    //後でここも弄る
    void callback(IplImage* image)
    {
    
    }
    
    #if 1 //0にすると#elseまでのソースが無視され動画ファイル用のソースになる。
    int ShowCamVideo(HWND hwnd, int width, int height)
    {
      //フォーマットの指定
      //typedef struct
      //{
      //    int width;
      //    int height;
      //    double framerate;
      //}VidFormat;
      //で宣言されている。幅、高さ、フレームレート
      VidFormat vidFmt={ width, height, 30.0};
      
      //カメラが何個繋れているか
      //繋れていないと-1を返す
      int ncams = cvcamGetCamerasCount( );
      //カメラ0(1台目の意)を使う。詳しくは関数リファレンスを参照
      //カメラを使う宣言
      cvcamSetProperty(0, CVCAM_PROP_ENABLE, CVCAMTRUE);
      //コールバック関数の指定
      cvcamSetProperty(0, CVCAM_PROP_CALLBACK,callback);
      //ウィンドウの指定
      cvcamSetProperty(0, CVCAM_PROP_WINDOW, &hwnd);   
      //Set Video Format Property
      //ビデオフォーマットの指定
      cvcamSetProperty( 0, CVCAM_PROP_SETFORMAT, &vidFmt);
      //設定した項目の有効化。失敗したら0を返す
      if( !cvcamInit() )
          return 0;
      //カメラの動作開始
      cvcamStart();
      return 1;
    }
    
    int main( int argc, char** argv )
    {
      cvNamedWindow("cvcam window", CV_WINDOW_AUTOSIZE);
      //ウィンドウのハンドル(操縦桿)をShowCamVideo関数に渡す。640x480のビデオサイズに指定
      if( ShowCamVideo((HWND)cvGetWindowHandle("cvcam window"), 640, 480) )
      {
          //キー待ち状態で実行
          cvWaitKey(0);
          //何かキーが押されたらカメラ停止
          cvcamStop();
      }
      //後片付け
      cvcamExit();
    }
      
    #else //動画像ファイルの処理
    /**************************************************************************\
                           How To Play Media file by CvCam
    \**************************************************************************/
    
    void ShowAVIVideo(char* filename, HWND hwnd, int width, int height)
    {
      cvcamAVIFILE f = cvcamAVIOpenFile(filename);
      if( (int)f < 0 )
          return;
      cvcamAVISetWindow (f, hwnd);
      cvcamAVISetCallback(f, callback);
      cvcamAVISetSize(f, width, height);
      cvcamAVIRun(f);
      cvcamAVIWaitCompletion(f);
      cvcamAVIStop(f);
      cvcamAVICloseFile(f);
    }
    
    
    int main( int argc, char** argv )
    {
      if( argc > 1 )
      {
        cvNamedWindow("avi window", CV_WINDOW_AUTOSIZE);
        ShowAVIVideo( argv[1], (HWND)cvGetWindowHandle("avi window"), 320, 240);
      }
    }
    #endif

コールバック関数による処理

描画の度に呼ばれる関数で、IplImageへのポインタを引数としている。 つまり中の処理については静止画を弄る場合と同じになる。

と思って以下のコールバック関数を使ってみる。

void callback(IplImage* image)
{
  int height,width,step,channels;
  uchar *data;
  int i,j,k;
  // get the image data
  height    = image->height;
  width     = image->width;
  step      = image->widthStep;
  channels  = image->nChannels;
  data      = (uchar *)image->imageData;
  //printf("Processing a %dx%d image with %d channels\n",height,width,channels); 
  // invert the image
  for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
  data[i*step+j*channels+k]=255-data[i*step+j*channels+k];
}

リアルタイムで画像をネガにする。

筈だったのだがポケモン真っ青のフリッカー状態に。 対処法を探したが、特になさそうで別ウィンドウを開くのが正解らしい。 カメラにウィンドウハンドル渡しているんだから当たり前と言えば当たり前か。

main関数に"cvcam window"を作成したのと同じように表示用ウィンドウ

cvNamedWindow("feed window", CV_WINDOW_AUTOSIZE);

を入れる。

int main( int argc, char** argv )
{
  cvNamedWindow("cvcam window", CV_WINDOW_AUTOSIZE);
  cvNamedWindow("feed window", CV_WINDOW_AUTOSIZE);
  if( ShowCamVideo((HWND)cvGetWindowHandle("cvcam window"), 640, 480) )
  {
      cvWaitKey(0);
      cvcamStop();
  }
  cvcamExit();
}

コールバック関数は"feed window"へ描画するように変更。 メモリの取扱は微妙だが毎回cvCloneImageしていると、あっと言う間にメモリを食い潰してしまうので、cvReleaseImageしておく。

    IplImage *image1;
    void callback(IplImage* image)
    {
      int height,width,step,channels;
      uchar *data;
      int i,j,k;
       
      image1=cvCloneImage(image);
      // get the image data
      height    = image1->height;
      width     = image1->width;
      step      = image1->widthStep;
      channels  = image1->nChannels;
      data      = (uchar *)image1->imageData;
      //printf("Processing a %dx%d image with %d channels\n",height,width,channels); 
       
      // invert the image
      for(i=0;i<height;i++) for(j=0;j<width;j++) for(k=0;k<channels;k++)
        data[i*step+j*channels+k]=255-data[i*step+j*channels+k];
      cvShowImage("feed window",image1);
      cvReleaseImage(&image1);
    }

ウィンドウが二つ開いて、一方は通常の画像、他方はネガ画像が表示されれば成功。

原画像ウィンドウが邪魔な場合

泥縄的だがキー入力待ちに入る前に消してしまう。

    int main( int argc, char** argv )
    {
      cvNamedWindow("cvcam window", CV_WINDOW_AUTOSIZE);
      cvNamedWindow("feed window", CV_WINDOW_AUTOSIZE);
      if( ShowCamVideo((HWND)cvGetWindowHandle("cvcam window"), 640, 480) )
      {
        cvDestroyWindow("cvcam window");
        cvWaitKey(0);
        cvcamStop();
      }
      cvcamExit();
    }