F行列に基づき,エピポーラ線の情報を計算してくれる
fmatrixの情報に基づき,points内の点に対応する直線の方程式を計算する
#geshi(c++,number){{
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/calib3d/calib3d.hpp> #include <iostream> const char windowName[] = "Test"; const char LeftImageFileName[] = "hogehoge\\Left.jpg"; const char RightImageFileName[] = "hogehoge\\Right.jpg"; const int pointCount = 10; using namespace cv; int main(int argc, char** argv); // 対応する特徴点を適当に読み込む関数. void readPointsLeft(const Mat& imageLeft, Mat& pointsLeft); void readPointsRight(const Mat& imageRight, Mat& pointsRight); // エピポーラ線を描画する関数 void drawEpilines(Mat& image, std::vector<Vec3f> lines, std::vector<uchar> mask); // 直線の方程式があるx座標を通過するときのy座標を求める inline double solveY(Vec3f efficient, double x); // ×点を描画する関数 void drawCross(Mat& image, Mat& points); // 画像を2枚描画する関数 void showBothImage(Mat *image); int main(int argc, char** argvv){ // 2枚の画像. Mat inputImage[2]; inputImage[0] = imread(LeftImageFileName); // ファイル名を適当に設定 inputImage[1] = imread(RightImageFileName); // ファイル名を適当に設定
// 2枚とも表示 showBothImage(inputImage); // 各画像から特徴点を読み込む // 今回は事前に取った特徴点をハードコーディングしてある Mat points[2]; readPointsLeft(inputImage[0], points[0]); readPointsRight(inputImage[1], points[1]); // 画像に特徴点を×として描画 for(int i = 0;i < 2;i++){ drawCross(inputImage[i], points[i]); } // 2枚とも表示 showBothImage(inputImage); Mat FMatrix; // F行列用変数 std::vector<uchar> mask; // F行列計算に使われた特徴点を表す変数 // F行列を計算 // ここでwhichImageの1か2が決まる↓ここに入るのが1番の画像 FMatrix = findFundamentalMat(points[0], points[1], mask); // ↑ここに入るのが2番の画像 for(int i = 0;i < 2;i++){ std::vector<Vec3f> lines; // F行列と特徴点から,エピポーラ線の方程式を計算 computeCorrespondEpilines(points[i], 1+i, FMatrix, lines); // ↑で計算されたエピポーラ線の方程式を元に描画 drawEpilines(inputImage[1-i], lines, mask); } // 2枚とも表示 showBothImage(inputImage); // ウィンドウを破棄 destroyWindow(windowName); return 0; } // 特徴点の座標を格納する関数 // 格納方法は適当で良いが,格納順に注目 void readPointsLeft(const Mat& imageLeft, Mat& pointsLeft){ static float points[] = { 17,175, // x1, y1, 370,24, // x2, y2, 192,456, // : 614,202, // : 116,111, // : 305,32, // : 249,268, // : 464,157, // : 259,333, // : 460,224};// x10, y10 // floatの配列を元にMatを作成 // double (CV_64F)にすると findFundamentalMat でassertionエラーが出るので注意 // CV_32FC2 にしたのは,データの格納方法をわかり易くするため pointsLeft = Mat::Mat(cv::Size(1, pointCount), CV_32FC2, (void*)points); } // 基本的に readPointsLeft と同じ void readPointsRight(const Mat& imageRight, Mat& pointsRight){ static float points[] = { 295,28, 584,221, 67,172, 400,443, 330,9, 480,140, 181,140, 350,265, 176,193, 333,313}; pointsRight = Mat::Mat(cv::Size(1, pointCount), CV_32FC2, (void*)points); } // 方程式を元に直線を描画する void drawEpilines(Mat& image, std::vector<Vec3f> lines, std::vector<uchar> mask){ // 直線の方程式を格納したvector std::vector<Vec3f>::iterator it; // 使われた特徴点フラグ std::vector<uchar>::iterator itmask; it = lines.begin(); itmask = mask.begin(); while(it != lines.end()){ if(*itmask == 0){ // mask の値が0ということは,計算に使われなかったということ it++; itmask++; continue; } if((*it)[1]){ // Y軸と交わる直線の場合 double width = image.size().width; // left は x=0 における直線の通過座標 Point2d left = Point2d(0.0, solveY(*it, 0.0)); // right は x=width における直線の通過座標 Point2d right = Point2d(width, solveY(*it, width)); // 左端から右端に直線を引く line(image, left, right, Scalar(0, 0, 255), 2); }else{ // Y軸に平行な直線の場合 // x座標は一定なので,あらかじめ求める double x = -(*it)[2]/(*it)[0]; // 画像の上端を通過する座標 Point2d top = Point2d(x, 0.0); // 画像の下端を通過する座標 Point2d bottom = Point2d(x, image.size().height); // 上端から下端に直線を引く line(image, top, bottom, Scalar(0, 0, 255), 2); } it++; itmask++; } } // 直線の方程式とx座標からy座標を計算する inline double solveY(Vec3f efficient, double x){ return - (efficient[0] * x + efficient[2]) / efficient[1]; } // points で与えた座標を中心に×印を描く void drawCross(Mat& image, Mat& points){ Point2f cross1 = Point2f(2, 2); Point2f cross2 = Point2f(2, -2); for(int i = 0;i < points.size().height;i++){ Point2f point = Point2f(points.at<float>(i, 0), points.at<float>(i, 1)); line(image, point - cross1, point + cross1, Scalar(255, 255 - 20 * i, 20 * i)); line(image, point - cross2, point + cross2, Scalar(255, 255 - 20 * i, 20 * i)); } } // ウィンドウに画像を表示 void showBothImage(Mat *image){ namedWindow(windowName, CV_WINDOW_FREERATIO | CV_GUI_EXPANDED | CV_WINDOW_AUTOSIZE); for(int i = 0;i < 2;i++){ imshow(windowName, image[i]); waitKey(0); } }
}}
左カメラ画像に引いた,右カメラからのエピポーラ線.何点かエピポーラ線が描かれてない点はF行列を求める最適化の過程で,外れ値としてはじかれた値
右カメラ画像に引いた,左カメラからのエピポーラ線.何点かエピポーラ線が描かれてない点はF行列を求める最適化の過程で,外れ値としてはじかれた値
ジャンル:OpenCV:OpenCV 1.0:OpenCV 1.1:OpenCV 2.0:OpenCV 2.1:OpenCV 2.2準拠