OpenCVのhighgui
には簡易的な機能しかないので、SDLと連携させてみました。
OpenCVのcv::VideoCapture
でWebカメラの映像を取得して、SDLでレンダリングしました。
環境
- OS: ArchLinux 64bit
- 言語: C++
- コンパイラ: clang++
- ライブラリ: OpenCV3.2, SDL2.0.5
どうやって連携させるか
OpenCVのcv::Mat
クラスはピクセルデータに直接アクセスする方法を提供しています。また、SDLのSDL_Texture
構造体はピクセルデータを書き込む方法を提供しています。
今回はcv::VideoCapture
でカメラの映像をcv::Mat
クラスに格納し、そのピクセルデータをSDL_Texture
構造体に書き込んでそれをレンダリングしました。
cv::Matクラスのピクセルデータへのアクセス
cv::Mat
クラスのピクセルデータへのアクセス方法は、主に以下の5通りとされています。
cv::Mat::at
cv::Mat::data
cv::Mat::ptr
cv::MatIterator_
cv::Point
今回は一番高速とされるcv::Mat::ptr
を利用しました。
以下はカラー画像の全てのピクセルの値を青・緑・赤の順に標準出力するコードです。
for (auto row { 0 }; row < mat.rows; ++row)
{
auto const data { mat.ptr<Vec3b>(row) };
for (auto col { 0 }; col < mat.cols; ++col)
{
std::cout << data[col][0] << "," << data[col][1] << "," << data[col][2] << std::endl;
}
}
SDL_Texture構造体のピクセルデータへの書き込み
SDL_Texture
構造体のピクセルデータへの書き込みは、SDL_UpdateTexture
を用いる方法とSDL_LockTexture
を用いる方法の2つがありますが、今回は速いとされるSDL_LockTexture
を利用しました。
書き込みは以下の手順で行います。
書き込み可能なSDL_Texture構造体を作成する
SDL_CreateTexture
の第3引数ではテクスチャのアクセスパターンを指定できるのですが、SDL_TEXTUREACCESS_STREAMING
を指定することで書き込み可能なSDL_Texture
構造体を作成できます。
auto texture {
SDL_CreateTexture(renderer, SDL_PIXELFORMAT_RGBA8888, SDL_TEXTUREACCESS_STREAMING, 640, 480)
};
SDL_Texture構造体を書き込み専用にするためにロックする
SDL_LockTexture
を用いることで、テクスチャをロックしてピクセルデータへのポインタと水平方向のバイト数を取得することができます。ピクセルデータの書き込み操作はこのポインタに対して行います。
void *pixels;
int32_t pitch;
SDL_LockTexture(texture, nullptr, &pixels, &pitch);
ポインタを介してピクセルデータを書き込む
先ほど取得したポインタを介してピクセルデータを書き込みます。ピクセルデータは1次元の配列状に並んでいるので、任意の座標のピクセルに書き込む際は水平方向のバイト数を考慮して、書き込むピクセルの位置を計算しなければなりません。
以下は1024番目のピクセルを白くするコードです。
auto const format { SDL_AllocFormat(SDL_PIXELFORMAT_RGBA8888) };
reinterpret_cast<uint32_t *>(pixels)[1024] = SDL_MapRGB(format, 255, 255, 255);
書き込み終わったSDL_Texture構造体をアンロックする
SDL_UnlockTexture
でテクスチャをアンロックしてピクセルデータの変更を反映します。
SDL_UnlockTexture(texture);