« 代替プラン | トップページ | もしもの時の為に »

2011年12月14日 (水)OpenCVと某カメラを使う

おはようございます。 本日の当番プログラマなT.Yです。

最近はプログラマにも関わらず、
プライベートではほとんどプログラマらしい事をしていなかったので、
ちょっとプログラマらしいメモ日記でいこうかと思います。

発売して以来、いろいろなプログラマやクリエイターの
遊び道具になっている、某カメラのインターフェイス。

世間では、OpenNIとOpenCV使って使ってる人が多いのですが、
敢えて、販売元から公式に公開されているプレビュー版で触ってみました。

商用利用は出来ないので商売は無理といった制限があるのですが、
簡単なインストーラーでドライバの組み込みまで自動でやってくれる便利さが
個人で軽く嗜む程度には便利かと。

これでカメラユニットから得られる映像のストリームをOpenCVに突っ込んで
遊んでみようと思います。


ここからは、とりあえずベースとして
Windowが表示出来てDirect3Dテクスチャが扱える物がある前提で。。

ということで、以下軽く嗜む為のサンプル


#include "MSR_NuiApi.h"
#include "opencv/cv.h"
#include "opencv/highgui.h"


HANDLE   m_hNextSkeletonEvent
HANDLE   m_hNextVideoFrameEvent
HANDLE   m_pVideoStreamHandle
HANDLE   m_hNextDepthFrameEvent
HANDLE   m_pDepthStreamHandle
NUI_SKELETON_FRAME   m_SkeletonFrame;

CvHaarClassifierCascade*   cascade = 0;
CvMemStorage*           storage = 0;

IplImage* g_pInputImage;
IplImage* g_pOutputImage;
IplImage* g_pGrayImage;


void main()
{
   // 他システム部分の初期化

   // 某カメラの初期化

   {
      HRESULT result;

      result = NuiInitialize(
         NUI_INITIALIZE_FLAG_USES_DEPTH_AND_PLAYER_INDEX | NUI_INITIALIZE_FLAG_USES_SKELETON | NUI_INITIALIZE_FLAG_USES_COLOR);
      if( FAILED( result ) )
      {
         return;
      }


      result = NuiSkeletonTrackingEnable( m_hNextSkeletonEvent, 0 );
      if( FAILED( result ) )
      {
         //エラー処理
      }

      result = NuiImageStreamOpen(
         NUI_IMAGE_TYPE_COLOR,
         NUI_IMAGE_RESOLUTION_640x480,
         0,
         2,
         m_hNextVideoFrameEvent,
         &m_pVideoStreamHandle );
      if( FAILED( result ) )
      {
         //エラー処理
      }

      result = NuiImageStreamOpen(
         NUI_IMAGE_TYPE_DEPTH_AND_PLAYER_INDEX,
         NUI_IMAGE_RESOLUTION_320x240,
         0,
         2,
         m_hNextDepthFrameEvent,
         &m_pDepthStreamHandle );
      if( FAILED( result ) )
      {
         //エラー処理
      }
   }

   // OpenCV
   {
      // openCV用イメージ作成
      g_pInputImage = cvCreateImage( cvSize( 640, 480 ), IPL_DEPTH_8U, 3 );
      g_pGrayImage = cvCreateImage( cvSize( 640, 480 ), IPL_DEPTH_8U, 1 );
      g_pOutputImage = cvCreateImage( cvSize( 640, 480 ), IPL_DEPTH_8U, 1 );


      // 顔認識用データ
      {
         cascade = (CvHaarClassifierCascade *) cvLoad (cascade_name, 0, 0, 0);
         storage = cvCreateMemStorage (0);
         cvClearMemStorage (storage);

      }

   }

   // ウインドウ作成
   cvNamedWindow ("GrayImage", CV_WINDOW_AUTOSIZE);


   // メインループ
   while(1)
   {
      // 省略
      // ここまで他処理


      HRESULT result;
      const NUI_IMAGE_FRAME * pImageFrame = NULL;
      const NUI_IMAGE_FRAME * pDepthFrame = NULL;

      // カラーイメージを取得
      result = NuiImageStreamGetNextFrame(
         m_pVideoStreamHandle,
         0,
         &pImageFrame );

      // 深度イメージを取得
      result = NuiImageStreamGetNextFrame(
         m_pDepthStreamHandle,
         0,
         &pDepthFrame );

      // 骨格情報を取得
      result = NuiSkeletonGetNextFrame( 0, &m_SkeletonFrame );
      NuiTransformSmooth(&m_SkeletonFrame, NULL);


      if( pImageFrame )
      {
         KINECT_LOCKED_RECT srcLockedRect;
         pImageFrame->pFrameTexture->LockRect( 0, &srcLockedRect, NULL, NULL );
         for( int y=0; y<480; y++ )
         {
            unsigned char* pSrcLine = reinterpret_cast

(srcLockedRect.pBits);
            pSrcLine = (pSrcLine + (srcLockedRect.Pitch * y));

            for( int x=0; x<640; x++ )
            {
               g_pInputImage->imageData[((y * 640 + x) * 3)+0] = pSrcLine[(x * 4)+0];
               g_pInputImage->imageData[((y * 640 + x) * 3)+1] = pSrcLine[(x * 4)+1];
               g_pInputImage->imageData[((y * 640 + x) * 3)+2] = pSrcLine[(x * 4)+2];
            }
         }

         pImageFrame->pFrameTexture->UnlockRect( 0 );
         NuiImageStreamReleaseFrame( m_pVideoStreamHandle, pImageFrame );


         // グレイスケール化
         cvCvtColor( g_pInputImage, g_pGrayImage, CV_BGR2GRAY );

         // 顔認識用のデータを使って検出器にかける
         {
            CvSeq *faces;
            faces = cvHaarDetectObjects (g_pGrayImage, cascade, storage, 1.11, 4, 0, cvSize (40, 40));
            CvScalar col = {255,255,255};
            // 検出された全ての顔位置に,円を描画する
            for (int i = 0; i < (faces ? faces->total : 0); i++)
            {
               CvRect *r = (CvRect *) cvGetSeqElem (faces, i);
               CvPoint center;
               int radius;
               center.x = cvRound (r->x + r->width * 0.5);
               center.y = cvRound (r->y + r->height * 0.5);
               radius = cvRound ((r->width + r->height) * 0.25);
               cvCircle (g_pGrayImage, center, radius, col, 3, 8, 0);
            }
         }


         // 結果を表示
         cvShowImage ("GrayImage", g_pGrayImage);
      }
      
      if( pDepthFrame )
      {
         NuiImageStreamReleaseFrame( m_pDepthStreamHandle, pDepthFrame );
      }

   }
}




使用した各SDKバージョンは、某カメラがv1.0-beta2の64ビット版
OpenCVが2.3.0を使用しました。

DirectXのテクスチャが扱えるようにと言っておきながら、
結果確認用にはOpenCVのHighGUI使って手抜きだったりですが・・・
あくまで軽く嗜むサンプルということで!!


深度情報は全く使ってないので正直普通のwebカメラでも出来る事だけど、
深度データも基本は似たようなもんなんで、
上のサンプルを参考に深度情報からも何か使ったりと遊んでみてはいかが?


参考までに、深度情報を使う際は16ビットのグレースケールデータのうち
下位3ビットはプレイヤー認識用のIDが振られているので、通常のグレースケール画像として扱う際には、
3ビットシフトしてやる必要があります。



まずは、検出用のデータを自前で作ってみてもよし、
グレースケール化した画像を今度はエッジ抽出してみてもよし。

ちなみに私は、まだ自前で検出用のデータを作る所で彷徨ってます。
適当にググった情報を頼りに作ってると、妙に大きなデータが出来て突っ込むと激重(0.01fpsくらい?)
だったり、変換途中でコンバータが落ちたり。。。。


とりあえず後は任せた!!

follow us in feedly
result = encodeURIComponent( "http://www.accessgames-blog.com/blog/2011/12/opencv-e832.html" );document.write( "result = " , result );&media=https%3A%2F%2Ffarm8.staticflickr.com%2F7027%2F6851755809_df5b2051c9_z.jpg&description=Next%20stop%3A%20Pinterest">

| | コメント (0) | トラックバック (0)

« 代替プラン | トップページ | もしもの時の為に »

プログラマー」カテゴリの記事

コメント

この記事へのコメントは終了しました。

トラックバック


この記事へのトラックバック一覧です: OpenCVと某カメラを使う:

« 代替プラン | トップページ | もしもの時の為に »