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準拠