F行列に基づき,エピポーラ線の情報を計算してくれる

void cvComputeCorrespondEpilines( CvMat* points, int whichImage, CvMat* fmatrix, CvMat* lines );

fmatrixの情報に基づき,points内の点に対応する直線の方程式を計算する

引数

返り値

void computeCorrespondEpilines( Mat& points, int whichImage, Mat& fmatrix, std::vector<Vec3f>& lines);

解説

サンプルコード

#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);
        }
}

}}

実体ファイル

実行結果

左カメラ画像.見づらいけれど,計10点×印が付いている.
http://tessy.org/wiki/index.php?plugin=attach&pcmd=open&refer=%A5%A8%A5%D4%A5%DD%A1%BC%A5%E9%C0%FE%A4%CE%B7%D7%BB%BB&file=left_before.png

右カメラ画像.見づらいけれど,計10点×印が付いている.
http://tessy.org/wiki/index.php?plugin=attach&pcmd=open&refer=%A5%A8%A5%D4%A5%DD%A1%BC%A5%E9%C0%FE%A4%CE%B7%D7%BB%BB&file=right_before.png

左カメラ画像に引いた,右カメラからのエピポーラ線.何点かエピポーラ線が描かれてない点はF行列を求める最適化の過程で,外れ値としてはじかれた値
http://tessy.org/wiki/index.php?plugin=attach&pcmd=open&refer=%A5%A8%A5%D4%A5%DD%A1%BC%A5%E9%C0%FE%A4%CE%B7%D7%BB%BB&file=left_after.png

右カメラ画像に引いた,左カメラからのエピポーラ線.何点かエピポーラ線が描かれてない点はF行列を求める最適化の過程で,外れ値としてはじかれた値
http://tessy.org/wiki/index.php?plugin=attach&pcmd=open&refer=%A5%A8%A5%D4%A5%DD%A1%BC%A5%E9%C0%FE%A4%CE%B7%D7%BB%BB&file=right_after.png

注意

ジャンル:OpenCV:OpenCV 1.0:OpenCV 1.1:OpenCV 2.0:OpenCV 2.1:OpenCV 2.2準拠


添付ファイル: fileleft_after.png 13173件 [詳細] fileleft_before.png 13146件 [詳細] fileright_after.png 13113件 [詳細] fileright_before.png 13148件 [詳細]

トップ   編集 凍結 差分 履歴 添付 複製 名前変更 リロード   新規 一覧 検索 最終更新   ヘルプ   最終更新のRSS
Last-modified: 2011-03-04 (金) 10:41:16