catalinaの備忘録

ソフトウェアやハードウェアの備忘録。後で逆引きできるように。

OpenCVで気になったモジュールを試してみた

自分のやりたいことをやってる時間というのは充実しているものだと、最近はそう感じます。かたりぃなです。

FileStorageモジュール

XML/YAML形式でread/writeできる便利なモジュール。
ドキュメントはこちら。
OpenCV: cv::FileStorage Class Reference
今回の使い道は数学でいう行列(not画像)の保存/読み出しなどですね。

カメラキャリブレーションの結果の3つの行列(内部パラメータ、外部パラメータ、歪みパラメータ)をXML形式で出力する例。

	cv::FileStorage			fs(fileName, cv::FileStorage::WRITE);
	if (fs.isOpened()) {
		cv::write(fs, "extrinsic", cam_ext);
		cv::write(fs, "intrinsic", cam_int);
		cv::write(fs, "distortion", dist);
	}

こんな形でxmlファイルを吐き出してくれました。

<?xml version="1.0"?>
<opencv_storage>
<extrinsic type_id="opencv-matrix">
  <rows>4</rows>
  <cols>4</cols>
  <dt>d</dt>
  <data>
    -9.9305776780672794e-01 -3.4058957106407342e-02
    -1.1258888595035788e-01 -1.5680892918531333e+02
    1.1384691321616840e-03 -9.5990137467839998e-01
    2.8033561097112358e-01 2.2311113599467828e+02
    -1.1762216494672212e-01 2.7826127709644033e-01
    9.5327629152408078e-01 9.1508148149913336e+02 0. 0. 0. 1.</data></extrinsic>
<intrinsic type_id="opencv-matrix">
  <rows>3</rows>
  <cols>3</cols>
  <dt>d</dt>
  <data>
    9.2246418807201553e+02 0. 3.3045069724184663e+02 0.
    9.1528831192908842e+02 2.2281712474807887e+02 0. 0. 1.</data></intrinsic>
<distortion type_id="opencv-matrix">
  <rows>1</rows>
  <cols>5</cols>
  <dt>d</dt>
  <data>
    6.5901038525089195e-01 -6.1369184814174949e+00
    1.9503639590909172e-02 1.4560644371180317e-02 1.7415994956396972e+01</data></distortion>
</opencv_storage>

XMLを読み出すときも簡単に。

	cv::FileStorage fs(filename, cv::FileStorage::READ);
	fs["intrinsic"] >> intrinsic;
	fs["distortion"] >> distcoeffs;

このコード中では全部トップレベルに記述しましたが、fs["string"]の式はcv::FileNode型なので、階層構造も簡単に扱えそうですね。(試してはいない)

メモリ上にあるファイルイメージのデコード

画像ファイルのI/Oとファイルのデコードを分離したいケースがあります。
opencvの関数でメモリ上からデコードできそうなものがあったので試してみました。
ドキュメントはこちら
OpenCV: Image file reading and writing

まずファイルからメモリ上にファイルイメージそのまま展開します。
readでもfreadでもお好みのもので。環境によってはAAsset_readとかかもしれませんね。

    // メモリ上に展開されたpngファイルをデコードする
    cv::Mat fileImage(1, _size, CV_8UC1, _buf);     // _bufにはファイルのバイナリイメージそのまま入っている
    cv::Mat rawImage = cv::imdecode(fileImage, 1);  // 第二引数に1を指定し、RGBフォーマットで取り出す

これだけで_bufに格納してあった画像ファイルのデコードができました。
あとはrawImageを好きなように料理できます。

openCVのビルド情報をログに出す

ライブラリ使っているとありがちなのですが、バージョン違いだったり依存ライブラリの不足なんてことが稀によくあります。
問題を早く解決できるように、openCV自身のビルド情報をログに出しておくと便利です。

    std::cout << cv::getBuildInformation() << std::endl;

ArUcoモジュール

軽量なARライブラリらしいです。
opencv3.0以降、opencv_contribに含まれるようになってました。
ドキュメントはこちら。
OpenCV: ArUco Marker Detection

Arucoでの姿勢推定はcv::aruco::estimatePoseSingleMarkersとかで。
中身は当然のことながらcv::solvePnpでした。
パラレルforっぽい記述が見受けられたので、複数マーカーの場合はPNP問題を解く処理はパラレルに走るのかも?(詳しく調べてはいない)

cv::aruco::drawAxis()が何気に便利。デバッグとかの用途に使いやすいですね。
ARの姿勢推定もそうですが、三次元空間上の物体の姿勢を表示する機能って毎回作ってる気がします。
(加速度センサ・ジャイロセンサーから取ってきた値の確認とか)

oglモジュール

OpenCVOpenGLの相互運用のためのモジュールらしい。
このエントリ書き始めてから存在に気づいたので、また気が向いたら調べてみたいと思います。
ドキュメントはこちら。
OpenGL interoperability — OpenCV 3.0.0-dev documentation

AR,VRについて思うこと

今回のエントリとは若干話がそれますが、思っていることを書いてみます。
最近は某HMDが話題になったりと、VR界隈が賑やかでいいですね。
ARについても今回のエントリで書いたArUcoや一昔前のAR-Toolkitのようなマーカー型ARではなくマーカーレスARの研究も進んでいるようです。
技術的には新しいことが出てきて興味深いのですが、個人的にはVRもARも目的は「従来とは異なる特別な(新しい)ユーザー体験を提供する」ってところにあると思っています。

さて、この「特別な体験」というものが今のARでは作り手側から受け手側への一方通行になってしまっているのがすごく勿体ないと思います。
以前「グリコのポッキーのドラえもんの絵柄を専用アプリで撮影すると立体表示される」というARアプリがありましたが、
これって一発目のインパクトの強さだけで終わってしまうんですよね。「おお、すげー。」って。
VRも同様で、某イベントで「任意の角度から女性キャラの3Dモデルを眺めることができる」というものがありました。
これらのARやVR技術を使った表現方法はインパクトは強く、技術的にも興味深いものですが、何か物足りないと私は感じています。

先にあげた「一方通行」ですが、従来型のテレビや新聞などのマスメディアによる情報の伝達は、基本的に一方通行です。
ARにしてもVRにしても、ほとんどのケースでは従来型マスメディアと同様に一方通行になっているのが残念です。
さらにVRについては、HMDを利用する場合は「周囲の人間が楽しめない」という課題もあると考えています。

じゃあARに関して、どのような方式であれば先にあげた物足りなさ、残念さが解消できるのかを考えると、、、

  • 利用するコンテンツ(3Dモデルなど)はユーザー自身が選び、
  • 現実世界の物体との紐づけもユーザー自身が行える

などが考えられます。
ただ、このままでは「自分だけのAR環境に閉じこもる」だけになってしまうので、MMDが発展してきたように何らかの形で「発表・共有する場」があるといいかもしれません。

なんか整理つかなくなってきたのでこのくらいで。