GpuMatの画像データをhighguiのウィンドウに表示する

  • 7
    Like
  • 0
    Comment
More than 1 year has passed since last update.

はじめに

この記事ではcv::cuda::GpuMatの画像データをhighguiのウィンドウに表示する方法について紹介します.

前提条件

  • CUDAが動作するPC上で動作させる必要あり
    • cv::cuda::GpuMatを使うため

  • OpenCVをビルドする際にWITH_CUDAを有効にする必要あり
    • cv::cuda::GpuMatを使うため

  • OpenCVをビルドする際にWITH_OPENGLを有効にする必要あり
    • ウィンドウ描画にOpenGLの機能を用いるため

GpuMatデータの表示方法

cv::cuda::GpuMatの画像データをhighguiのウィンドウに表示する方法は大まかに以下の3パターンがあります.

  • ホストメモリに転送して表示する
  • highgui(OpenGL)を使って表示する
  • ogl::Texture2Dを使って表示する

ホストメモリに転送して表示する

おそらく一般的に用いられているのは,

  • cv::cuda::GpuMatのデータをdownloadメソッド等を使ってホスト側に転送する
  • cv::imshow関数を使って表示する

という手順で表示する方法です.ただし,表示のためにホスト側にデータを転送する処理が入ってしまいます.

highgui(OpenGL)を使って表示する

downloadメソッド等の転送処理を介さずに表示する方法として最も簡単なのは

  • cv::namedWindow関数のフラグとしてcv::WINDOW_OPENGLをセットする
  • cv::imshow関数にcv::cuda::GpuMatの変数を直接渡す

という手順で表示する方法です.highguiの内部処理では後述する「ogl::Texture2Dを使って表示する」とほぼ同じ処理が動いています.

ogl::Texture2Dを使って表示する

OpenCVにはOpenGLとの連携を行うための機能が入っています(詳細は公式ドキュメントを参照ください).
ここではcv::ogl::Texture2Dを使った方法について紹介することとします.

cv::ogl::Texture2Dを使ってGpuMatデータを表示するには,

  • cv::namedWindow関数のフラグとしてcv::WINDOW_OPENGLをセットする
  • cv::cuda::GpuMatのデータからcv::ogl::Texture2Dのデータを生成する
  • cv::setOpenGlDrawCallback関数によりOpenGLコールバック関数をセットする
  • cv::updateWindow関数によりウィンドウ描画内容を更新する

という手順で実現できます.
ウィンドウ描画内容の更新タイミング等を制御したい場合はこちらの方法を用いた方がよいかもしれません.

ウィンドウサイズ変更

画像サイズに応じて表示するウィンドウサイズを変えたい場合は,cv::resizeWindow関数を呼ぶ必要があります.

サンプルコード

  • ホストメモリに転送して表示する
  • highgui(OpenGL)を使って表示する
  • ogl::Texture2Dを使って表示する

これまで紹介した上記3つの方法を用いてcv::cuda::GpuMatの画像データをhighguiのウィンドウに表示するサンプルコードです.

display_gpumat.cpp
#include <opencv2/core.hpp>
#include <opencv2/core/opengl.hpp>
#include <opencv2/core/cuda.hpp>
#include <opencv2/cudaimgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>

#include <iostream>

void drawTexture_cb(void* userdata)
{
    cv::ogl::Texture2D* texture = static_cast<cv::ogl::Texture2D*>(userdata);
    cv::ogl::render(*texture);
}

int main(int argc, char *argv[])
{
    cv::Mat src = cv::imread("lena.jpg", cv::IMREAD_UNCHANGED), dst;
    if(src.empty())
    {
        return -1;
    }

    cv::cuda::GpuMat d_src(src), d_dst;
    cv::cuda::cvtColor(d_src, d_dst, cv::COLOR_BGR2GRAY);

    // highgui(normal)を使った表示
    d_dst.download(dst); // ホストメモリに転送する
    cv::namedWindow("normal", cv::WINDOW_AUTOSIZE);
    cv::imshow("normal", dst);

    // highgui(OpenGL)を使った表示
    cv::namedWindow("highgui(OpenGL)", cv::WINDOW_AUTOSIZE | cv::WINDOW_OPENGL);
    cv::imshow("highgui(OpenGL)", d_dst);

    // ogl::Texture2Dを使った表示
    cv::namedWindow("highgui(Texture2D)", cv::WINDOW_OPENGL);
    cv::ogl::Texture2D texture(d_dst);
    cv::resizeWindow("highgui(Texture2D)", d_dst.cols, d_dst.rows);
    cv::setOpenGlContext("highgui(Texture2D)");
    cv::setOpenGlDrawCallback("highgui(Texture2D)", drawTexture_cb, &texture);
    cv::updateWindow("highgui(Texture2D)");

    cv::waitKey(0);
    cv::destroyAllWindows();

    return 0;
}

おわりに

この記事ではcv::cuda::GpuMatの画像データをhighguiのウィンドウに表示する方法について紹介しました.

備考

筆者は以下の環境で動作確認しました.

  • OpenCV 3.1.0
  • Windows 10 Pro(64bit)
  • Visual Studio 2013 Update5
  • NVIDIA CUDA Toolkit 7.5