大型連休っていいですね!!
ということで日がな一日好きなコードを書き続けています。こんばんは。
ちょっと勉強がてら、OpenCVでカメラからキャプチャした画像をOpenGLで描画しようとして、またしてもハマったのでメモ。
ということで日がな一日好きなコードを書き続けています。こんばんは。
ちょっと勉強がてら、OpenCVでカメラからキャプチャした画像をOpenGLで描画しようとして、またしてもハマったのでメモ。
やろうとしたこと
冒頭にも書いた通り、今回はOpenCVで読み込んだ画像をOpenGLで出力-CPPのようなことをやろうとしてました。
他にも類似の記事はたくさん引っかかったので、すぐできるだろー、と思いコードを書くことに。
方針としては、cvQueryFrame()を使ってIplImageを取ってきて、それを毎回glDrawPixels()に渡して描画する、という流れを考えてました。
cvQueryFrame()で取れた画像をglDrawPixels()に直接渡して描画*1しようとした結果が以下です。
どうしてこうなった……(´・ω:;.:...
どうやらcvQueryFrame()で取得できるIplImageには、各行ごとにパディング用の領域が確保されていて、その領域をOpenGLが読み飛ばせずにおかしな描画をしていたようです。
で、結果↓
……まぁすっきりしたからよしとしましょう!!
方針としては、cvQueryFrame()を使ってIplImageを取ってきて、それを毎回glDrawPixels()に渡して描画する、という流れを考えてました。
結果
うまくいきませんでした……orzcvQueryFrame()で取れた画像を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を見ると、それぞれ、
(※ともにwidth=640, nChannels=3)
となっており、確かに余計な領域が入っていることが確認できました。
そんなわけで、cvQueryFrame()でキャプチャした画像を直接OpenGLに渡す場合には気をつけましょうね!
- cvQueryFrame()のIplImage->widthStep = 2560 (= 640 * 4)
- cvCreateImage()のIplImage->widthStep = 1920 (= 640 * 3)
(※ともにwidth=640, nChannels=3)
となっており、確かに余計な領域が入っていることが確認できました。
そんなわけで、cvQueryFrame()でキャプチャした画像を直接OpenGLに渡す場合には気をつけましょうね!
……と、ここまで書いて気づきました。
cvCopy()一発でいけるんじゃ……?
ということで、forループを2周してコピーしている部分を以下のように書き変えました。
ということで、forループを2周してコピーしている部分を以下のように書き変えました。
cvCopy(_pFrame, frame);
で、結果↓
……まぁすっきりしたからよしとしましょう!!
結論
- cvQueueFrame()で取得したIplImageをglDrawPixels()に渡す際は、一度cvCopy()でコピーしておくと良い
変なコードを書く前に調べる
- *1:cvCloneImage()してコピーした画像を渡したりもしてみた