2012年5月3日木曜日

アラインメントの罠

大型連休っていいですね!!

ということで日がな一日好きなコードを書き続けています。こんばんは。
ちょっと勉強がてら、OpenCVでカメラからキャプチャした画像をOpenGLで描画しようとして、またしてもハマったのでメモ。

やろうとしたこと

冒頭にも書いた通り、今回はOpenCVで読み込んだ画像をOpenGLで出力-CPPのようなことをやろうとしてました。
他にも類似の記事はたくさん引っかかったので、すぐできるだろー、と思いコードを書くことに。

方針としては、cvQueryFrame()を使ってIplImageを取ってきて、それを毎回glDrawPixels()に渡して描画する、という流れを考えてました。

結果

うまくいきませんでした……orz

cvQueryFrame()で取れた画像をglDrawPixels()に直接渡して描画*1しようとした結果が以下です。

どうしてこうなった……(´・ω:;.:...

原因

設定がおかしいのかとも思いましたが、結局、正しいデータを渡せていないことが原因でした。
cvCreateImage()で作ったIplImageにcvQueryFrame()で取れたIplImageのデータを「ちゃんと」コピーすることで、期待通りの動作をするようになります。

具体的には以下のようにコピーすることでうまく動作しました。
    // _pFrameはcvQueryFrame()で取得したIplImage
    // frameはcvCreateImage()で作成したIplImage↓
    // IplImage *frame = cvCreateImage( cvSize( _pFrame->width, _pFrame->height ), IPL_DEPTH_8U, 3);
    for (int y = 0; y < frame->height; y++) {
        for (int x = 0; x < frame->width; x++) {
            frame->imageData[frame->widthStep * y + x * 3] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3];
            frame->imageData[frame->widthStep * y + x * 3 + 1] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3 + 1];
            frame->imageData[frame->widthStep * y + x * 3 + 2] =
                    _pFrame->imageData[_pFrame->widthStep * y + x * 3 + 2];
                    
        }
    }

実行結果↓

どうやらcvQueryFrame()で取得できるIplImageには、各行ごとにパディング用の領域が確保されていて、その領域をOpenGLが読み飛ばせずにおかしな描画をしていたようです。
実際、cvQueryFrame()で取れたIplImageとcvCreateImage()で作ったIplImageのwidthStepを見ると、それぞれ、

  • cvQueryFrame()のIplImage->widthStep = 2560 (= 640 * 4)
  • cvCreateImage()のIplImage->widthStep = 1920 (= 640 * 3)

(※ともにwidth=640, nChannels=3)
となっており、確かに余計な領域が入っていることが確認できました。

そんなわけで、cvQueryFrame()でキャプチャした画像を直接OpenGLに渡す場合には気をつけましょうね!




……と、ここまで書いて気づきました。



cvCopy()一発でいけるんじゃ……?



ということで、forループを2周してコピーしている部分を以下のように書き変えました。
    cvCopy(_pFrame, frame);

で、結果↓


……まぁすっきりしたからよしとしましょう!!

結論

  • cvQueueFrame()で取得したIplImageをglDrawPixels()に渡す際は、一度cvCopy()でコピーしておくと良い
  • 変なコードを書く前に調べる


  • *1:cvCloneImage()してコピーした画像を渡したりもしてみた

0 件のコメント:

コメントを投稿