OpenCVで処理した画像をDirectXで表示する。

Posted on Thu 22 May 2008 in OpenCV

OpenCVではIplImage型に画像データが格納され、
IplImageのimageDataから画像データにアクセスできる。
データの格納順はBGRAとなっている。
これをDirectXのテクスチャに変換できないかと思って実行した。

手順はこんな感じ
・IDirect3DTexture9::CreateTextureでテクスチャを作成
・IDirect3DTexture9::LockRectを行ってデータを転送

カメラに写っている内容をDirectXで表示
f:id:hiroki0:20080523003112p:image

コードはこんな感じでいけると思う。(OpenCV側のデータが符号なし8ビット整数のときだけだが・・・)

HRESULT CreateTextureIPLImage(LPDIRECT3DDEVICE9 pDevice, IplImage* iplImage, UINT Width, UINT Height, UINT Levels, LPDIRECT3DTEXTURE9* ppTexture)
{
  HRESULT hr;
  //テクスチャ作成
  hr = pDevice->CreateTexture(Width, Height, Levels, 0, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED, ppTexture, NULL);
  if(FAILED(hr)){
    return hr;
  }
  //ロック
  D3DLOCKED_RECT pLockedRect;
  hr = (*ppTexture)->LockRect(0, &pLockedRect, NULL, 0);
  if(FAILED(hr)){
    return hr;
  }
  //転送
  switch(iplImage->depth){
    case IPL_DEPTH_8U:
      {
        if(iplImage->nChannels <= 2){//チャンネル数が2以下ならエラーを返す
            return E_FAIL;
        }
        int byte = iplImage->nChannels*8;
        unsigned long data; //32bit
        unsigned long r;
        unsigned long g;
        unsigned long b;
        unsigned long a;
        unsigned long *to = (unsigned long*)pLockedRect.pBits;
        for(UINT y=0; y<Height; y++){
          for(UINT x=0; x<Width; x++){
            // OpenCVのBGRA順のデータを32bit変数にARGB順につめなおす
            data = 0;
            b = ((unsigned char*)(iplImage->imageData + iplImage->widthStep * y))[x * 3];      //B
            data += b;
            g = ((unsigned char*)(iplImage->imageData + iplImage->widthStep * y))[x * 3 + 1]; //G
            g <<= 8;
            data += g;
            r = ((unsigned char*)(iplImage->imageData + iplImage->widthStep * y))[x * 3 + 2]; //R
            r <<= 16;
            data += r;
            if(iplImage->nChannels == 4){
              a = ((unsigned char*)(iplImage->imageData + iplImage->widthStep * y))[x * 3 + 3]; //A
              a <<= 24;
              data += a;
            }else{
              data += 0xFF000000;
            }
            *to++ = data;
          }
        }
      }
      break;
    default:
      return E_FAIL;
      break;
  }
  //アンロック
  hr = (*ppTexture)->UnlockRect(0);
  if(FAILED(hr)){
    return hr;
  }
  return S_OK;
}