はじめに
Augmented Reality(AR)のように、毎フレーム画像を取得して画像処理を行った上でCGを描画したい時があるとします。画像の取得や出力やCGの描画には、それぞれOpenCVとOpenGLというライブラリが有名です。今回は、OpenCVとOpenGLを用いてARのための簡単なフレームワークを作りました。
環境設定
環境は以下の通りです。
Windows10, Visual Studio 2015, C++, x64 Releaseモード
ライブラリはGLFW3.1.2, OpenCV3.0
インクルードディレクトリ
opencv\build\include
glfw-3.1.2.bin.WIN64\include\GLFW
ライブラリ
opencv\build\x64\vc14\lib
glfw-3.1.2.bin.WIN64\lib-vc2015
追加の依存ファイル
opencv_world310.lib
GLFW3.lib
opengl32.lib
コード
GLFWの描画関数display()のループ内で画像を一枚ずつ読み込みます。OpenGLとOpenCVでは座標系が異なることに注意してください。また、画像の三次元座標について z = 0 としています。以下にひな形コードを示します。
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <glfw3.h>
#include <iostream>
VideoCapture cap(InputVideoPath); // 使用する動画
uint numberOfFrame = 0; // フレーム番号
const uint lastFrame = 100; // 終わりのフレーム番号
const uint WIDTH = 540, HEIGHT = 540; // 画像のサイズ
static void init()
{
glClearColor(0.0, 0.0, 0.0, 1.0);
tt = 0;
}
static void display()
{
glClear(GL_COLOR_BUFFER_BIT);
cv::Mat img; // 画像の宣言
cap >> img; // 画像の読み込み
//////////////////////////////////////////////
// 画像処理などOpenCVによる操作 //
//////////////////////////////////////////////
/* OpenCVの座標系をOpenGLの座標系に合わせる */
cv::flip(img, img, 0); // x軸まわりの反転
cv::cvtColor(img, img, CV_BGR2RGB); // BGR-->RGB
glDrawPixels(img.cols, img.rows, GL_RGB,GL_UNSIGNED_BYTE, img.data); // 入力画像の表示
cv::flip(img, img, 0);
cv::cvtColor(img, img, CV_BGR2RGB);
//////////////////////////////////////////////
// テクスチャマッピングなどOpenGLによる操作 //
//////////////////////////////////////////////
/* 動画作成してプログラム終了 */
if (tt == LastFrame) {
exit(0);
}
++tt;
glFlush();
}
int main(int argc, char * argv[])
{
glfwInit();
GLFWwindow* window = glfwCreateWindow(WIDTH, HEIGHT, "Dynamic Projection Mapping", NULL, NULL);
glfwMakeContextCurrent(window);
init();
// 射影変換 (GLとCVの座標系が異なることに注意)
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrtho(-WIDTH / 2, WIDTH / 2, -HEIGHT / 2, HEIGHT / 2, -1, 1);
while (!glfwWindowShouldClose(window)) {
display();
glfwSwapBuffers(window);
glfwPollEvents();
}
glfwDestroyWindow(window);
glfwTerminate();
return 0;
}
OpenCVとOpenGLの座標系の違い
OpenCVでは画像左上が原点でOpenGLが画像中心が原点です。x軸方向は一致していますが、y軸方向が逆になっています。例えば1つの点を黒色で表示したい場合は以下のように書く必要があります。
cv::Point2i point;
// pointsの設定は省略
glPointSize(5.0);
glColor3f(0.0, 0.0, 0.0);
glBegin(GL_POINT);
glVertex3i(point.x - (WIDTH / 2), -(point.y - (HEIGHT / 2), 0);
glEnd();