理科系の勉強日記

Linux/Ubuntu/Mac/Emacs/Computer vision/Robotics

IEEE1394 & OpenCV

IEEE1394とは、Appleが主導で開発した高速シリアルバスの名称であり、AppleではFireWireと呼んだりするそうだ(超適当).巷にはUSBで接続する製品が溢れているため、今まで1394でカメラを接続するなんてしたことがなかった。

時代によって変化するが,以下の構成が一般的らしい.

  1. 自作プログラム : C/C++
  2. ライブラリ : libdc1394, libraw1394
  3. ドライバ : libdc1394, libraw1394
  4. カメラ : IEEE1394接続のlibdc1394準拠カメラ

必要なライブラリはlibraw1394, libxv, libsdl, libdc1394あたり.
ドライバはインストール後にロードする必要がある.modprobeでlibdc1394とlibraw2394をロードし,lsmodで確認をする.

次は1394カメラが認識されているかを信頼性の高いアプリケーションで確認する。自作のプログラムが正常に動作しなかった場合、その原因がプログラム側なのかカメラ側なのか判断をつけるのが面倒くさいからである。つまり、つなげば確実に動くアプリケーションで予備実験をしておく。dmesgなどとしてカメラの接続を確認した後,corianderというアプリケーションを用いてカメラの動作をチェック.

$dmesg | grep 1394

...(略)...
[206667.501736] ieee1394: Node added: ID:BUS[]0-00: 1023] GUID[00b09d01008cd782]
... (略)...

みたいなのが出てればOK.

$sudo coriander

基本的に一般ユーザはコンピュータにつながれたデバイスへのアクセス許可がない.
パーミッションを書き換えても良いし,sudoでも良いと思う.

リアルタイムで処理しないのであれば,corianderで連番画像キャプチャして用いるとか,動画がいいならそれらをffmpegで連番画像を動画にできるのでそれでも良い.
リアルタイムで画像処理がしたいというのであれば,やはり自作のプログラムで認識したいということになる.

Googleで[grab_gray_image.c]などと検索すると,今回の設定で使用できるサンプルコードが見つかる.
http://libdc1394-22.sourcearchive.com/documentation/2.0.2-1/grab__gray__image_8c_source.html
実際に書き換える部分は

/*-----------------------------------------------------------------------
     *  have the camera start sending us data
     *-----------------------------------------------------------------------*/
    err=dc1394_video_set_transmission(camera, DC1394_ON);
    DC1394_ERR_CLN_RTN(err,cleanup_and_exit(camera),"Could not start camera iso transmission");

    /*-----------------------------------------------------------------------
     *  capture one frame
     *-----------------------------------------------------------------------*/
    err=dc1394_capture_dequeue(camera, DC1394_CAPTURE_POLICY_WAIT, &frame);
    DC1394_ERR_CLN_RTN(err,cleanup_and_exit(camera),"Could not capture a frame");

    /*-----------------------------------------------------------------------
     *  stop data transmission
     *-----------------------------------------------------------------------*/
    err=dc1394_video_set_transmission(camera,DC1394_OFF);
    DC1394_ERR_CLN_RTN(err,cleanup_and_exit(camera),"Could not stop the camera");

    /*-----------------------------------------------------------------------
     *  save image as 'Image.pgm'
     *-----------------------------------------------------------------------*/
    imagefile=fopen(IMAGE_FILE_NAME, "wb");

    if( imagefile == NULL) {
        perror( "Can't create '" IMAGE_FILE_NAME "'");
        cleanup_and_exit(camera);
    }

    dc1394_get_image_size_from_video_mode(camera, video_mode, &width, &height);
    fprintf(imagefile,"P5\n%u %u 255\n", width, height);
    fwrite(frame->image, 1, height*width, imagefile);
    fclose(imagefile);
    printf("wrote: " IMAGE_FILE_NAME "\n");

になると思われる.

こんな面倒くさいことはしてられない.そこでようやく本題の1394 & OpenCVに入る.
OpenCVがlibdc1394やlibraw1394と関連してインストールされている場合,簡単に1394カメラから画像をキャプチャすることができる.OpenCVをcmakeした後に

...(略)...

--   Video I/O: 
--     DC1394 1.x:                
--     DC1394 2.x:                1
--     FFMPEG:                    1
--       codec:                   1
--       format:                  1
--       util:                    1
--       swscale:                 1
--       gentoo-style:            1
--     GStreamer:                 1
--     UniCap:                    FALSE
--     PvAPI:                     
--     V4L/V4L2:                  Using libv4l
--     Xine:                      FALSE

...(略)...

と表示されていればよいと思う.libdc1394が先にインストールされていればこうなるのか,cmakeのオプションなのかは忘れた.そんなもの見ていないというのであれば,OpenCVを使っているプログラム(実行ファイル)に対してlddでダイナミックリンクを調べる.

ldd ./hoge | grep 1394
libdc1394.so.22 => /usr/lib/libdc1394.so.22 (0xb54a7000)
libraw1394.so.11 => /usr/lib/libraw1394.so.11 (0xb4d71000)

もしこんな感じで表示されればOKである.あとは

CvCapture *videoCapture = 0;
IplImage* image = 0;
videoCapture = cvCreateCameraCapture( CV_CAP_ANY );

while(1) {
    image = cvQueryFrame(videoCapture);

...
}

というようなプログラムを書いてコンパイル,実行すればよい.cvCreateCameraCaptureの引数はintでCV_CAP_ANYを選択しておけば問題ない.
CV_CAP_IEEE1394としてもよい.

// high_gui_c.h
enum
{
	CV_CAP_ANY      =0,     // autodetect

	CV_CAP_MIL      =100,   // MIL proprietary drivers

	CV_CAP_VFW      =200,   // platform native
	CV_CAP_V4L      =200,
	CV_CAP_V4L2     =200,

	CV_CAP_FIREWARE =300,   // IEEE 1394 drivers
	CV_CAP_FIREWIRE =300,
	CV_CAP_IEEE1394 =300,
	CV_CAP_DC1394   =300,
	CV_CAP_CMU1394  =300,

	CV_CAP_STEREO   =400,   // TYZX proprietary drivers
	CV_CAP_TYZX     =400,
	CV_TYZX_LEFT    =400,
	CV_TYZX_RIGHT   =401,
	CV_TYZX_COLOR   =402,
	CV_TYZX_Z       =403,

	CV_CAP_QT       =500,   // QuickTime

	CV_CAP_UNICAP   =600,   // Unicap drivers

	CV_CAP_DSHOW    =700,   // DirectShow (via videoInput)

	CV_CAP_PVAPI    =800   // PvAPI, Prosilica GigE SDK
};