Edited at

OpenCVとOpenGLによるARひな形コード


はじめに

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();