投稿

6月, 2014の投稿を表示しています

パワーポイントファイルから動画ファイルを取り出す

パワーポイントのファイル*.pptxに埋め込まれた動画ファイルを抽出したい場合が稀にある。このような場合には、以下の手順で埋め込まれている動画を抽出することが出来る。 ファイルの拡張子をpptxからzipに変更する。(元のファイルを残したい場合は、事前にコピーしておくこと) zipファイルを解凍(展開)する。 解凍したフォルダ中にあるpptフォルダの中に埋め込まれている動画ファイルなどが格納されているので、ここから目的のファイルを見つける。 最近、動画をふんだんにちりばめたパワーポイントを作ったらpptxファイルの容量が1GBを超えていた。動画が多い場合は、埋め込みではなく動画へのリンクを指定した方が良いかもしれない。ただし、この場合には、上記の方法では、動画は取り出せない。

iOS Developer Programの種類

iOS用のアプリを開発する場合、iOS Developer Programに参加する必要がある。個人だとiOSデベロッパプログラム(年間¥7,800, 2014.06.22現在)を選択することになる。 一方で、企業や大学などの団体で利用する場合は、以下の三種類から選択することが出来る。 iOSデベロッパプログラム(年間¥7,800, 2014.06.22現在) iOSデベロッパエンタープライズプログラム(年間¥23,800, 2014.06.22現在) iOSデベロッパユニバーシティプログラム(無料) 各プログラムの違いについては、Appleのサイトに比較表があるのでこちらを参考にすれば良い。 https://developer.apple.com/jp/programs/start/ios/ 注意しないとならないのは、2014.06.22時点では、各プログラムに関して以下のような制約がある。 iOSデベロッパプログラム:1法人につき1ライセンス iOSデベロッパエンタープライズプログラム:1法人につき1ライセンス iOSデベロッパユニバーシティプログラム:学科ごとに1ライセンス なので、まずは自分の所属する機関に相談してから申請する必要がある。

VisualSfMの使い方 その5 -三次元点の追加-

イメージ
これまでに紹介した方法では、まず画像間で対応点を探索し、対応づいた特徴点に対して復元処理を行っていた。この最初の対応点探索処理は、画像から抽出される特徴量のみを用いて実行される。 一方で、復元処理が完了した後は、画像から抽出される特徴量に加え、カメラ間の幾何学的な関係も対応付けの際の拘束として利用することが出来る。この拘束を用いることで、より多くの特徴点を対応付ける事が可能となる。 これを実現するために、VisualSfMでは、"SfM->More Functions->Find More Points"を選択することで既知のカメラ位置・姿勢を用いた対応点情報の追加を行うことができる。 以下は、Find More Pointsにより、対応点の追加の結果である。追加後の方が、点の密度が高くなっていることが確認できる。 対応点追加前  対応点追加後

2D-3Dの対応から射影行列を求める方法(非線形最小化)

射影行列を求める方法として、以前DLTアルゴリズムを紹介した( 2D-3Dの対応から射影行列を求める方法(DLTアルゴリズム) )。この方法は、線形演算で高速に射影行列を求めることができるという特長を持つが、ノイズに弱いという欠点がある。 より高精度な推定手法として、再投影誤差を最小化することにより射影行列を求める方法がある。再投影誤差とは、三次元点\(X_{i}\)を射影行列\(P\)を用いて投影した点\(\hat{x_{i}}\)と観測座標\(x_{i}\)との差\(d\left(x_{i}, \hat{x_{i}}\right)\)である。再投影誤差最小化による手法では、この差を最小とする射影行列を求める方法である。 具体的には、以下の誤差関数を最小化する。 \[E=\sum_{i}d\left(x_{i}, \hat{x_{i}}\right)\] ただし、再投影誤差の最小化は非線形な問題であるため、Levenberg-Marquardt法などの非線形最小化アルゴリズムを利用する必要がある。ここでは、以前紹介した非線形最小化ライブラリCeres-Solverを用いた実装方法について紹介する。( 非線形最小化ライブラリCeres Solverの導入方法(Windows+Visual Studio 2012) ) 以下のプログラムでは、非線形最小化の前にDLTアルゴリズムなどによって初期解が得られていることを前提としている。 まず、Ceres-Solverを利用するために以下のヘッダファイルの指定とnamespaceの利用を宣言しておく。 #include <ceres/ceres.h> using ceres::AutoDiffCostFunction; using ceres::CostFunction; using ceres::Problem; using ceres::Solver; using ceres::Solve; 次に、誤差関数を以下のように定義する。 struct ErrorFunction{   ErrorFunction(cv::Point2d ip, cv::Point3d wp){     p2d[0] = ip.x; p2d[1] = ip.y;     p3d[0] = wp.x;

射影行列の分解

射影行列\(P\)はカメラの内部パラメータ行列\(K\)とカメラの外部パラメータ行列\(\left[R|t\right]\)を掛けあわせたもので構成されている。ここでは、射影行列から、カメラの内部パラメータ行列\(K\)とカメラの姿勢\(R\)を求める方法について紹介する。(射影行列の推定方法については、 2D-3Dの対応から射影行列を求める方法(DLTアルゴリズム) を参照) 3行4列の射影行列\(P\)は左側の3×3の行列と右端の列ベクトルに分けることができ、それぞれ内部パラメータ\(K\)、カメラ姿勢\(R\)、カメラ位置\(C\)を用いて以下のように書ける。 \[P=\left[M|-MC\right]=K\left[R|-RC\right]\] ここから、内部パラメータ\(K\)は上三角行列、カメラ姿勢を表す\(R\)は直交行列なので、行列\(M\)をQR分解により上三角行列と直交行列に分解することで\(K\)、\(R\)を算出できることがわかる。OpenCVを用いる場合、 cv::RQDecomp3x3 を用いてQR分解を行うことができる。 以下は、3行4列の射影行列projectionMatを分解して内部パラメータ\(K\)、カメラ姿勢\(R\)を求めるOpenCVのコードである。 //射影行列の3x3要素を抽出 cv::Mat M = projectionMat.colRange(cv::Range(0, 3)); std::cout << M << std::endl; cv::Mat R, Q; cv::RQDecomp3x3(M, R, Q); std::cout << "Intrinsic Camera Parameters:\n" << R << std::endl; std::cout << "Rotation matrix:\n" << Q << std::endl; ただし、OpenCVには、射影行列を分解して、内部パラメータ\(K\)、カメラ姿勢\(R\)、カメラ位置\(C\)を求める cv::decomposeProjectionMatrix 関数が用意されており、上記と

2D-3Dの対応から射影行列を求める方法(DLTアルゴリズム)

2D-3Dの複数の対応から射影行列を求める方法は色々とあるが、Direct Linear Transform(DLT)と呼ばれる方法について紹介する。詳しくは、Multiple view geometryの7章に載っているので、不足している情報は、本を読んで補間して欲しい。 三次元座標を\(X_{i}\)、その画像上の観測座標を\(x_{i}\)(以下の式中の\(x_{i}, y_{i}, w_{i}\)はこのベクトルの各要素を表す)とすると、三次元座標\(X_{i}\)と観測座標\(x_{i}\)は射影行列\(P\)を用いて以下の様な関係を導くことができる。 \[ \begin{bmatrix}0^{T} & -w_{i}X_{i}^{T} & y_{i}X_{i}^T\\ w_{i}X_{i}^{T} & 0^{T} & -x_{i}X_{i}^{T} \end{bmatrix} \left(\begin{array}{c} p^{1^{T}} \\ p^{2^{T}} \\ p^{3^{T}}\end{array}\right) = 0 \] ここで\( p^{j^{T}}\)は射影行列\(P\)の\(j\)行目の行ベクトルを表す。 \(Ap=0\)の形になっており\(\left|p\right|\neq0\)なので、射影行列\(P\)は行列\(A\)を特異値分解し、最小特異値に対応する右特異ベクトルを求めることで得ることが出来る。 (\bmが使えないとベクトルとスカラーが分からなくなるなぁ。。。) 以下は、三次元座標とその画像上の観測座標から射影行列を求めるための関数。 求められた射影行列にはスケールの不定性があるため、検証する際には射影行列の右下(3行4列の要素)を1.0とするなどの処理が必要になる。 cv::Mat calcProjectionMatrix(std::vector<cv::Point3d> op, std::vector<cv::Point2d> ip) {   cv::Mat A;   A.create(cv::Size(12, op.size()*2), CV_64FC1);   for (int i = 0, j = 0; i < op.siz

非線形最小化ライブラリCeres Solverの導入方法(Windows+Visual Studio 2012)

非線形最小化問題を解くためのライブラリとしてGoogleのCeres Solverがある。このライブラリは、比較的使い勝手がよく、また、バンドル調整のような大規模な疎行列を扱うような問題にも対応している。 ここでは、Windows+Visual Studio 2012での導入方法について個人的なメモも兼ねて記載しておく。 基本的には、 このページ の手順にしたがって進めていくと問題なくコンパイルできました。 以下のフィアルをダウンロード Ceres Solverのソースコード( http://code.google.com/p/ceres-solver/downloads/list ) gflags( http://code.google.com/p/gflags/downloads/list ) glogs( http://code.google.com/p/google-glog/downloads/list ) CXSparse( https://github.com/PetterS/CXSparse ) Eigen( http://eigen.tuxfamily.org/index.php?title=Main_Page ) gflags, glogs, CXSparseのライブラリを生成 ダウンロードしたファイルを展開すると、それぞれのフォルダにVisual Studioのソリューションファイルがあるので、これを開いてビルド。参考にしたページに書かれているようなソースコードの修正は必要ありませんでした。 CMakeをつかってCeres Solverのソリューションファイルを生成 ソースコードの位置をceres/ceres-solver-1.8.0に設定し、バイナリ生成のためのフォルダをceres/ceres-solver/buildのように設定する。設定後、gflags, glogs, CXSparse, Eigen3のヘッダファイルの場所、ライブラリを以下のように指定し、configure, generateするとソリューションファイルが生成される。 EIGEN_INCLUDE_DIRにEigenへのパス GFLAGS_INCLUDE_DIRにgflags-2.0\src\window

Computer vision, Computer GraphicsのJournal 一覧

Online Computer Vision and Graphics Journals というページにCVやCG関係の論文誌一覧がある。論文誌の名前とともにImpact factorも記載されている。CVだとPAMIやIJCV、CGだとACM ToGが影響度が高いことが分かる。

ユークリッド座標系 <-> 同次座標系の変換

座標変換を行う際には、ある点の座標を同次座標で表現したほうが計算が便利な場合がある。 OpenCVでは、ユークリッド座標から同次座標、同次座標からユークリッド座標へ変換するための関数が用意されている。 cv::convertPointsToHomogeneous 同次座標系への変換。n次元の座標をn+1次元の同次座標へ変換する。 cv::convertPointsFromHomogeneous ユークリッド座標系への変換。n+1次元の同次座標をn次元のユークリッド座標へ変換する。 cv::convertPointsHomogeneous 自動でユークリッド座標系 -> 同次座標系、ユークリッド座標系 <- 同次座標系を判断し変換する。内部で、cv::convertPointsToHomogeneousまたはcv::convertPointsFromHomogeneousを呼び出している。 以下に使用例を示す。 #include <iostream> #include <vector> #include <opencv2/opencv.hpp> int main(int argc, char** argv) {   std::vector<cv::Point2d> points2D;   //適当に二次元座標を生成   for (int i = 0; i < 10; ++i)   {     cv::Point2d p;     p.x = rand();     p.y = rand();     points2D.push_back( p );   }   std::vector<cv::Point3d> points3D;   //ユークリッド座標 -> 同次座標系への変換   cv::convertPointsToHomogeneous(points2D, points3D);   std::cout << "Euclidean to Homogeneous" << std::endl;   for (int i = 0; i < points2D.size(); ++i)   {     std

OpenCVを使った動画ファイルの入出力

OpenCVを使うと動画の入出力が簡単に出来る。動画ファイルを読み込む際には cv::VideoCapture クラスを用い、書き込みには cv::VideoWriter クラスを用いる。書き込みの際には、コーデック、フレームレート、解像度を指定する。 各フレームの情報は ">>", "<<" 演算子で読み込み・書き込みが可能。 以下は、動画ファイルを読み込んで、別の動画ファイルに書き込みを行うコードの例。 OpenCV3.0以降を用いる場合は、CV_FOURCCが廃止されているので、cv::VideoWriter::fourccを用いてコーデックを指定する必要がある。 #include <opencv2/opencv.hpp> int main(int argc, char** argv) {   //入力動画ファイルを指定   cv::VideoCapture cap( "input.avi" );   //出力動画ファイルの指定   cv::VideoWriter writer( "output.avi", cv::VideoWriter::fourcc('M','J','P','G'), cap.get(cv::CAP_PROP_FPS), cv::Size((int)cap.get(cv::CAP_PROP_FRAME_WIDTH), (int)cap.get(cv::CAP_PROP_FRAME_HEIGHT)));   cv::Mat frame;   while( 1 )   {     //1フレーム読み込み     cap >> frame;     if( frame.empty() )       break;     //出力動画ファイルへ書き込み     writer << frame;   }   return 0; }

マイクロソフト・エルゴノミクス・キーボード&マウス

イメージ
数年くらい前からマイクロソフトのエルゴノミクスキーボードとマウスを使っています。周りはRealForceやHHKBを使っている人が多いですが、個人的に打鍵音が大きすぎて好きになれません。(仕事している感はでるかもしれませんが。。。) 最初は、DellのPCを買うと標準でついてくるキーボードに比べると、真ん中部分が割れているし非常に使いづらいなぁという印象でした。 ただ、暫く使っていると、アームパッドも徐々に馴染んでき、また、手前から奥へ行くにつれて高さが低くなっている仕様にも慣れ非常に快適にタイピングできるようになりました。ただ、一つ欠点があるとすれば、このキーボードに慣れてしまうと、他のキーボード操作の際にミスタイプが非常に増えてしまうことです。 当店は5,000円(税別)以上のお買いもので送料が無料です!【送料無料】 マイクロソフト ワイヤレ... 価格:13,260円(税込、送料込)

Vaio Tap 11

イメージ
外出用PCとしてVaio Tap 11を購入してみた。 2ヶ月ほど使用してみた感想としては、キーボードカバーは鞄などに入れている際に外れていることが良くあるので固定用のオプションを購入したほうがいいかも。 あとは、ファンというか排気の音がうるさく静かな環境で利用している場合はかなり気になるかも。 基本的には快適に使えているけれど、自宅の無線LANにつなごうとすると制限ありの状態になりインターネットに接続できない。 なぜ。。。 【特価展示品/送料無料】【沖縄・一部離島を除く】【即納・送料無料】SONY VAIO Tap 11 SVT1121... 価格:121,240円(税込、送料込)

レンズカメラ

イメージ
SonyのレンズカメラQX100とQX10を購入。 iPhoneについないで撮影してみた。  撮影された画像については、携帯のカメラに比べると綺麗に取れているかなという感じ。  ただ、処理が追いついていないのか、ネットワークの帯域が足りていないのか分からないけれど、プレビュー映像がガタついてしまうところがいまいち。プレビュー映像のクオリティもユーザ側で調整出来るといいんだけれど。 【送料無料】【あす楽】 ソニー Cyber-shot DSC-QX100 B ブラック 価格:50,700円(税込、送料込) 【送料無料】【あす楽】 ソニー Cyber-shot DSC-QX10 B ブラック 価格:19,800円(税込、送料込)

特定のフォルダでコマンドプロンプトを開く

Windowsを利用していて特定のフォルダでコマンドプロンプトを開きたい時がある。アプリケーションからコマンドプロンプトを起動して、cd コマンドで移動しても良いが面倒くさい。 そんな時には、開いているフォルダのアドレスバーにcmd と入力するとそのフォルダをカレントディレクトリとするコマンドプロンプトを開くことが出来る。また、シフトキーを押した状態で右クリックすると「コマンドウィンドウをここで開く」が出てくる。 これらの方法は、意外と知らない人が多いと思う。

VisualSfMの使い方 その4 -対応点リストの読み込み-

イメージ
VisualSfMでは、三次元復元を行う際にSIFTを用いたマッチング結果を利用するようになっている。ただし、拡張現実感などで復元結果を利用したトラッキングを作ろうとした場合には、SIFTは計算コストが高くリアルタイムでのトラッキングには適さない(SIFT-GPUを使えば別ですが)。 また、VisualSfMで利用しているSIFTのプログラムとOpenCVに実装されているSIFTでは、得られる特徴点や特徴量が微妙に異なる。なので、どうせならOpenCVで抽出した点に対して復元処理を行いたい。 SIFT以外の特徴点検出手法の利用やOpenCVに実装されている手法の利用は、自分で各画像の特徴点情報ファイル(".sift"という拡張子のファイル)とマッチングリストを用意することで実現できる。方法については、 VisualSfMのDocument に書かれているが、各ファイルの準備方法について簡単に述べる。 ・特徴点情報ファイル VisualSfMでは、各画像から抽出された特徴点の情報は、一旦、"画像ファイル名.sift"というファイルに書き込まれる。このファイルを自分で用意することで、SIFT以外の特徴点検出結果を利用することが可能となる。 特徴点情報ファイルには、以下のフォーマットで特徴点情報が書き込まれている。 [Header][検出位置情報][特徴量][EOF] なお、情報は全てバイナリファイルとして書き込まれる必要がある。 - ヘッダ情報 ヘッダ情報はint型の大きさ5の配列で以下の情報が書き込まれる。   int[5] = {name, version, npoint, 5, 128};   name = ('S'+ ('I'<<8)+('F'<<16)+('T'<<24));   version = ('V'+('4'<<8)+('.'<<16)+('0'<<24)); (色情報を含めてある場合は ('V'+('5'<<8)+('.'

Windowsのプログラムでコマンドプロンプトを消す方法

デモなどを行う際に、コマンドプロンプトが出ているとカッコ悪いので消したい。そんな場合には、以下の1行をソースコードに加えることで、コマンドプロンプトを消すことが出来る。 #pragma comment( linker, "/subsystem:\"windows\" /entry:\"mainCRTStartup\"" ) 参考 GLUT Tutorial: http://www.lighthouse3d.com/opengl/glut/

OpenCVで超解像処理

イメージ
OpenCVには超解像処理モジュールがあり、これを利用することで簡単に超解像処理を実行することが出来る。 使い方は、 SuperResolution クラスを生成し、入力画像系列の指定、各種パラメータの設定(必要に応じて)を行うだけ。ただし、モジュールを使用するためにはsuperres.hppのインクルードとopencv_superresxxx.libのリンクが必要。 #include <opencv2/opencv.hpp> //SuperResolutionモジュールを使うために必要 #include <opencv2/superres.hpp> int main(int argc, char** argv) {   //SuperResolutionクラスを生成   cv::Ptr<cv::superres::SuperResolution> superResolution = cv::superres::createSuperResolution_BTVL1();   //入力画像系列の指定とパラメータの指定   superResolution->setInput(cv::superres::createFrameSource_Video("elephant.avi"));   superResolution->set("iterations", 20);   superResolution->set("scale", 2);   //結果出力   cv::namedWindow("SuperResolved");   cv::namedWindow("Original(scaled)");   //オリジナルのビデオ   cv::VideoCapture cap("elephant.avi");   cv::Mat original;   while( 1 )   {     cv::Mat frame;     //超解像結果の取り出し     superResolution->nextFrame( frame );     if(frame.empty()

VisualSfMの使い方 その3 -既知のカメラパラメータを用いた復元-

イメージ
今回は、画像を撮影したカメラの内部パラメータが既知かつ全ての画像で同じ場合の復元について説明します。 Structure-from-motionでは、カメラの外部パラメータ(並進、回転)、カメラの内部パラメータ(焦点距離、画像中心、レンズ歪など)、特徴点の三次元位置を推定することが出来ます。VisualSfMもデフォルトではこれらのパラメータを推定するようになっています。 しかし、事前にカメラキャリブレーションを行ったカメラを用いて撮影した画像を用いる場合には、カメラの内部パラメータの推定は不要になります。VisualSfMでは、このような場合に事前のキャリブレーション結果を利用することが出来る機能が用意されています。 カメラパラメータは、SfM -> More Functions -> Set Fixed Calibrationを選択することで焦点距離 fx, fy [pixel]、画像中心 cx, cy、レンズ歪係数 rを指定することが出来ます。ただし、歪係数は1次の項のみなので、歪が大きな画像を入力する場合には、以下のように事前に歪を取り除いた画像を用意し、r=0を指定するのが良いかもしれません。 #include <opencv2/opencv.hpp> int main(int argc, char** argv) {   cv::Mat K;   cv::Mat distCoeffs;   //内部パラメータの読み込み   cv::FileStorage fs("camera.xml", CV_STORAGE_READ);   fs["intrinsicMat"] >> K;   fs["distCoeffs"] >> distCoeffs;   cv::Mat input = cv::imread("image1.jpg");   cv::Mat undistorted;   //レンズ歪の除去   cv::undistort(input, undistorted, K, distCoeffs);   //オリジナル画像   cv::namedWindow("Original")

VisualSfMの使い方 その2 -時系列画像からの復元-

イメージ
VisualSfMの使い方 その1 では、最も基本的な使い方について紹介しました。その際に、大量の画像を扱う場合には、対応点探索に膨大な時間が掛かると書きましたが、これは全ての画像の組み合わせで対応関係を求めるためです。しかし、動画で撮影した画像から物体形状の復元を行う場合などでは、大量の画像を入力することになったりします。 このような、時系列画像を入力とする場合には、Pairwise Matching -> Compute Sequence Matchを利用することで、対応点探索の範囲を近傍のフレームのみに限定することが出来ます。 あとは、 VisualSfMの使い方 その1 と同様にReconstruct Sparseを実行することで復元を行うことが出来ます。 Sequence Matchを行うと大幅に処理時間を短縮することが出来ますが、全ての対応関係を計算することが可能な場合は、そちらのほうが推定誤差が小さくて良いと思います。画像枚数や計算機パワーを考慮して、どちらを利用するかは検討して下さい。

VisualSfMの使い方 その1 -最も単純な使い方-

イメージ
これから何度かに分けて、Structure-from-Motion(SfM)法で画像から三次元情報を復元してくれる VisualSfM というソフトの使い方を説明していこうと思います。VisualSfMは、Changchang Wu博士(現在、Google?)が作成したソフトで、マルチコア計算機で特徴抽出、マッチング、バンドル調整を効率よく計算できるようになっています。 さらに、SfM法で得られるのは疎な形状情報なので、密な形状復元を行いたい場合は PMVS/CMVS を後処理で行うことが出来るようになっています。ただし、 PMVS/CMVS を使う場合には、別途 PMVS/CMVS の実行ファイルをダウンロードしておく必要があります。 また、密な復元+面貼りが可能な CMP-MVS 用の入力データの書き出しを行うことも出来ます。 ソフトウェアは VisualSfM のトップページにあるリンクからダウンロードすることが出来ます(現在、Windows, linux, Mac OSX版がダウンロード可能)。 以下では、Windows版のソフトの基本的な使い方を紹介していきます。 ダウンロードしたファイルを回答すると、VisualSFM.exeという実行ファイルがあると思います。まずは、これを実行します。 File -> Open+Multi Imagesを選択し、復元対象の画像群を選択します。画像の読み込みが終わるとサムネイル画像がウィンドウ内に表示されます。画像枚数が多い場合には一部の画像だけが表示されます。 画像の読み込み完了後に、特徴抽出および対応点の探索を行います。SfM -> Pairwise Matching -> Compute Missing Matchを選択して下さい。この際に、特徴抽出に SIFT-GPU を用いたい場合には事前に実行ファイルをダウンロードしてVisualSfMと同じフォルダに配置しておく必要があります。GPU版を使わない場合は、事前にTools -> Enable GPU -> Disable SIFTGPUを選択しておきます。 対応点の探索が終わったら、SfM -> Reconstruct Sparseで復元を行います。復元が始まると三次元位置の推定やバンドル調整の

2画像からの三次元復元

5点アルゴリズムによるカメラ位置・姿勢の推定 で2枚の画像を撮影したカメラの相対的な位置・姿勢情報を推定することができた。ここでは、推定された位置・姿勢情報を使って対応点の三次元情報を復元する方法を紹介する。 カメラの位置・姿勢情報、カメラの内部パラメータ、画像間での2D-2D対応から、三角測量の原理に基づいて対応点の三次元座標を推定することが出来る。OpenCVでは、この三角測量による三次元座標の計算を行うためのcv::triangulatePointsが用意されている。引数は、第1,2カメラの射影行列、それぞれの画像の対応点座標を格納した配列、三次元座標出力用の配列である。 先日の 5点アルゴリズムによるカメラ位置・姿勢の推定 のプログラムでcv::recoverPoseした後に、下記のコードを加えることで、対応点の三次元情報を復元することが出来る。 ただし、誤対応情報を利用する場合には、cv::findEssentialMatの部分を以下のように書き換える必要がある。 cv::Mat mask; //RANSACの結果を保持するためのマスク cv::Mat essentialMat = cv::findEssentialMat(p1, p2, 1.0, cv::Point2f(0, 0), cv::RANSAC, 0.9999, 0.003, mask); 以下のプログラムでは、三次元座標の復元は焦点距離1.0の正規化座標系での対応点座標を用いている。なので、それぞれのカメラの内部パラメータ行列は単位行列となり、射影行列はカメラの外部パラメータ行列と一致する。     //正規化座標系で計算しているのでProjection matrix=Extrinsic camera parameter matrix     cv::Mat prjMat1, prjMat2;     prjMat1 = cv::Mat::eye(3, 4, CV_64FC1); //片方は回転、並進ともに0     prjMat2 = cv::Mat(3, 4, CV_64FC1);     for (int i = 0; i < 3; ++i)       for (int j = 0; j < 3; ++j)       {         prjM

5点アルゴリズムによるカメラ位置・姿勢の推定

2枚の画像間のカメラ位置・姿勢を推定する際に、それぞれの画像を撮影したカメラの内部パラメータが既知の場合には5点アルゴリズムが利用できる。OpenCVにも5点アルゴリズムでカメラ位置・姿勢を推定するための関数 cv::findEssentialMat が用意されている。 使い方は、対応点の座標を以下のように指定するだけ。 cv::Mat essentialMat = cv::findEssentialMat(p1, p2); ただし、デフォルトでは焦点距離1.0、画像中心座標(0, 0)で計算するようになっているので、下記のコードのように内部パラメータ行列を用いて座標変換を行うか焦点距離、画像中心座標を指定する必要がある。座標変換を行わずに利用したい場合は、焦点距離、画像中心座標を第3,4引数に設定すれば良い。 推定したEssential Matrixからカメラの並進と回転を求めるためには、 cv::recoverPose で並進ベクトルと回転ベクトルに分解することができる。 以下のように、2枚の画像から対応点を求めて、5点アルゴリズムでカメラ位置・姿勢を推定することができる。 #include <iostream> #include <vector> #include <opencv2/opencv.hpp> #include <opencv2/nonfree.hpp> int main(int argc, char** argv) {   cv::initModule_nonfree(); //モジュールの初期化   //カメラパラメータの読み込みとレンズ歪の除去   cv::Mat img1; //入力画像1   cv::Mat img2; //入力画像2   cv::Mat K;   cv::Mat distCoeffs;   cv::FileStorage fs("camera.xml", CV_STORAGE_READ);   fs["intrinsicMat"] >> K;   fs["distCoeffs"] >> distCoeffs;   cv::undistort(cv::imrea

2D-3D対応からのカメラ位置・姿勢の推定

画像からの三次元復元処理や拡張現実感のための位置合わせ処理において、画像を撮影したカメラの位置・姿勢が必要になることがある。ここでは、カメラの内部パラメータ(焦点距離、画像中心座標、アスペクト比など)は既知とし、カメラの外部パラメータ(並進と回転)を求める方法を紹介する。 カメラの位置・姿勢は、三次元位置が既知の点Pとその画像上での観測座標pの複数の対応から求めることが出来る。このような問題はPerspective-n-Pont Problem(PnP問題)として知られている。OpenCVにはPnP問題を解くための関数cv::SolvePnPが用意されている。この関数の入力は三次元位置が既知の点の配列(objectPoints)とその画像上での観測座標の配列(imagePoints)、カメラの内部パラメータ行列、歪係数を入力とし、カメラの外部パラメータ(回転ベクトル、並進ベクトル)を推定する。 対応点の組み合わせに誤対応が含まれている場合は、cv::SolvePnPRansacを用いることでロバスト推定手法であるRANSACを用いた誤対応の排除が可能である。 また、推定手法としてLevenberg-Marquardt法による最適化(cv::ITERATIVE)や高速な推定手法であるEPnP(cv::EPNP)を選択することができる。経験的にはcv::ITERATIVEの方が安定した推定を実現できるように思う。 さらに、回転ベクトル、並進ベクトルの初期値が得られている場合には、第7引数をtrueにし、出力用のrvec, tvecに値を設定しておくことで、最適化の際の初期値として使用することができる。拡張現実感などの場合には、直前のフレームでの推定結果などを初期値として用いることで推定結果の安定性を向上させることができる。 #include <iostream> #include <vector> #include <opencv2/opencv.hpp> void genRT(cv::Mat& rvect, cv::Mat& tvect); void getCorrespondingPairs(cv::Mat K, cv::Mat d, cv::Mat rvec, cv::Mat tvec, std:

特徴点の対応付け

イメージ
2枚の画像から抽出した特徴点を対応付ける。特徴点の抽出方法は OpenCVを使った特徴点抽出 を参照。 対応付けを行うためにはcv::DescriptorMatcherクラスを用いる。 最初にcv::DescriptorMatcher::createでオブジェクトを生成する。この時、マッチングの方法を指定することが出来る。下記のコードではBruteForceを指定して全探索によって対応点を見つけている。 使い方は、DescriptorMatcher::matchを呼び出し、2枚の画像から抽出した特徴量と対応付け結果を格納するためのDMatch配列を引数として渡すだけ。 ただし、一方向のみの探索では、対応付け対象の特徴点が複数の特徴点と対応づく可能性がある。誤対応を減らすためには、Discriminabilityのチェックや下記のコードのおまけにあるようなクロスチェックを行う必要がある。 #include <vector> #include <opencv2/opencv.hpp> #include <opencv2/nonfree.hpp> int main(int argc, char** argv) { cv::initModule_nonfree(); //モジュールの初期化 cv::Ptr<cv::FeatureDetector> detector = cv::FeatureDetector::create( "ORB" ); //検出器 cv::Ptr<cv::DescriptorExtractor> descriptorExtractor = cv::DescriptorExtractor::create( "FREAK" ); //特徴量 cv::Ptr<cv::DescriptorMatcher> matcher = cv::DescriptorMatcher::create("BruteForce"); //対応点探索方法の設定 cv::Mat img1 = cv::imread("image1.jpg"); //入力画像1 cv::Mat img2 = cv::imrea

同次線形方程式の解

\(AX=0\)かつ\(X\neq0\)の時の解は行列\(A\)を特異値分解し、最小特異値に対応する右特異ベクトルとして得ることが出来る。 OpenCVにはこれを行ってくれる関数SVD::solveZが用意されている。 使い方は簡単で、以下のように入力の行列と結果を格納するための行列を引数として渡すことで計算結果を得ることが出来る。 このプログラムでは、以下の同次線形方程式を解いている。 \[\left\{ \begin{array}{@{}1} 2x-y+4z=0\\ -6x+3y-12z=0\\ 4x-2y+8z=0 \end{array} \right. \] #include <iostream> #include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat A = (cv::Mat_<double>(3, 3) << 2, -1, 4, -6, 3, -12, 4, -2, 8); cv::Mat X; cv::SVD::solveZ(A, X); std::cout << X << std::endl; return 0; } 結果 [-0.2445084883048524; -0.9623980449408547; -0.1183452670827875]

OpenCVを使った特徴点抽出

OpenCVには画像から特徴点の抽出および特徴量の抽出を行うためのクラスが用意されている。基本的には、cv::FeatureDetector::create()で利用したい検出器を作成、cv::DescriptorExtractor::create()で特徴量の抽出器を作成する。SIFTやSURFを使う場合はnonfree.hppをインクルードし、cv::initModule_nonfree()で利用前にモジュールを初期化する必要がある。以下、カメラ画像から特徴点抽出および特徴量抽出を行うためのコード。 #include <iostream> #include <vector> #include <opencv2/opencv.hpp> #include <opencv2/nonfree.hpp> //SIFT,SURFを用いる場合に必要 int main(int argc, char** argv) { cv::Mat input; cv::VideoCapture cap( 0 ); //ビデオデバイス番号 if( !cap.isOpened() ) //デバイスのオープンに成功したかどうか return -1; cv::initModule_nonfree(); //SIFT, SURFを用いる場合にはモジュールを初期化する必要がある cv::Ptr<cv::FeatureDetector> detector = cv::FeatureDetector::create( "SURF" ); //検出器を指定(SIFT, SURF, ORBなど) cv::Ptr<cv::DescriptorExtractor> descriptorExtractor = cv::DescriptorExtractor::create( "SURF" ); //特徴量を指定(SIFT, SURF, ORBなど ) if ( detector.empty() ) //検出器の作成に成功したか { std::cout << "Cannot create detector" << std::en

OpenCVを使ったカメラ画像の取得

OpenCVを使ったカメラ画像の取得方法 カメラからの画像の取得にはcv::VideoCaptureクラスを使う。 使い方は簡単で、以下の様なコードでデバイスをオープンし、カメラ画像を取得することが出来る。 #include <opencv2/opencv.hpp> int main(int argc, char** argv) { cv::Mat input; cv::VideoCapture cap( 0 ); //ビデオデバイス番号 if( !cap.isOpened() ) //デバイスのオープンに成功したかどうか return -1; cv::namedWindow( "Video" ); while( 1 ) { cap >> input; //画像の取得 cv::imshow( "Video", input ); if( cv::waitKey( 30 ) >= 0 ) break; } return 0; }