0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

机の上にUnityChan

Posted at

ARマーカーの上にUnityChanを表示させてみた

Screenshot from 2023-12-19 18-37-07.png

OpenCVのChARUcoを使うと,簡単にマーカーの位置姿勢を推定することができます.
今回はこれを使って,位置が推定されたマーカーの上にUnityChanを表示させるプログラムを作ってみました.

テクスチャを張り付けたメッシュを画面に表示させるため、自分でOpenGLのシェーダーを書いて、表示させました。ライティングは特に考えていません。単にテクスチャを貼っただけです。

この記事ではOpenCVとOpenGLの連携にかかわることに絞って書いていきます。連携さえできればあとはOpenGLのプログラミングになるので、その辺はlearn openglなどを見ていただければいいんじゃないかなと思います。

なお、Mesh fileの読み込みなどは、Assimpを使用しました。クロスプラットフォームで使用でき、いろいろな形式の3Dモデルを読み込むことができます。

ソースコード

cv::MatをOpenGLのtextureにする

こちらの記事を参考にさせていただきました。

以下のコードでは、cv::Matの画像からOpenGLのテクスチャを作成しています。"texture_data"が作られたやつです。

	cv::Mat src_img = src_img_data.clone();
	cv::flip(src_img, src_img, 0);
	cv::cvtColor(src_img, src_img, cv::COLOR_BGR2RGB);
	
	glGenTextures(1, &texture_data);
	glActiveTexture(GL_TEXTURE0);
	glBindTexture(GL_TEXTURE_2D, texture_data);

	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
	glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);

	width = src_img.cols;
	height = src_img.rows;
	glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, src_img.cols, src_img.rows, 0, GL_RGB, GL_UNSIGNED_BYTE, src_img.data);
	// Generates MipMaps
	glGenerateMipmap(GL_TEXTURE_2D);
	glBindTexture(texture_data, 0);		// unbind

カメラの内部パラメータを踏まえた投影行列

こちらの記事を参考にさせていただきました。

まず、何らかの方法で使用するカメラの内部パラメータを取得します。ここではcv::calibrateCamera()を使用しました。そのパラメータを以下の変数に格納します。

   cv::Mat cameraMat = (cv::Mat_<double>(3,3) << 852.8839555848483, 0, 639.5, 0, 852.215118770151, 359.5, 0, 0, 1);
   cv::Mat distCoeffs = (cv::Mat_<double>(1,5) << 0.08005910250868746, -0.3113160415419927, 0, 0, 0.196456176823346);

投影行列は次のようになります。上のQiitaの記事で書かれていた行列をそのままプログラムに落とし込んだ形になります。

        glm::vec2 screenSize(848, 480);
        const double nearP = 0.1f;
        const double farP = 200;
        glm::mat4 camProj = glm::mat4(
            2*cameraMat.at<double>(0, 0)/screenSize.x, 0.0, 0.0, 0.0,
            0.0, 2.0*cameraMat.at<double>(1, 1)/screenSize.y, 0.0, 0.0,
            -2*cameraMat.at<double>(0, 2)/screenSize.x + 1, 2.0*cameraMat.at<double>(1, 2)/screenSize.y - 1,  -(farP + nearP)/(farP - nearP), -1.0,
            0.0, 0.0, -2*farP*nearP/(farP - nearP), 0.0
        );

OpenCVでは、カメラのz軸が撮影方向、y軸が下、x軸が撮影方向に対して右向きとなっているので、View行列は次のようになります。

       glm::mat4 camView = glm::lookAt(glm::vec3(0.f), glm::vec3(0.f, 0.f, 1.f), glm::vec3(0.f, -1.f, 0.f));

+z方向を見て、-yが上ベクトルとなっています。
なので、頂点シェーダーでは次のような雰囲気のコードになります。

gl_Position = camProj * camView * ModelTransform * vec4(Position, 1.0);

参考文献

OGLdev https://ogldev.org/
UnityChan https://unity-chan.com/

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?