左右两个平行四边形分别是相机在不同位置的成像平面,C0, C1分别是两个位置中相机的光心,也就是针孔相机模型中的针孔,P是空间中的一个三维点,p0, p1分别是P点在不同成像平面上对应的像素点
p0, p1都是图像上的二维点,不过,这里我们会把它变成三维的方向向量来考虑
方向向量:只考虑它的方向,而不考虑它的起点或终点的向量。我们假设一个归一化的图像平面,该平面上焦距f =1 ,因此我们可以定义在以C0为原点的坐标系下
=30x30而在以C1为原点的坐标系下
C0-p0就可以用p0表示,向量C0-C1就是光心C1相对于C0的平移,我们记为t, 向量C1-p1根据前面的讨论,可以用 Rp1 来表示
记为本质矩阵或本征矩阵(Essential Matrix)为
得:
点p在直线l上的充分必要条件就是 直线l 的系数与p的齐次坐标p’的内积为0
可以把Ep1看做是直线的方程,p0看做是直线上的点,也就是说Ep1就是以C0为原点坐标系中的极线了。如下图中红色线条所示,就是极线啦,它的方程是E*p1。
void cv::computeCorrespondEpilines ( InputArray points,
int whichImage,
InputArray F,
OutputArray lines
)
Python:
lines = cv.computeCorrespondEpilines( points, whichImage, F[, lines] )
#include
#include
#include
#include
#include
#include
#include
using namespace std;
using namespace cv;
int main( int argc, char** argv )
{
Mat rgb1 = imread( "/home/xiaohu/learn_SLAM/zuoye11/code/rgb1.ppm" );
Mat rgb2 = imread( "/home/xiaohu/learn_SLAM/zuoye11/code/rgb2.ppm" );
// Ptr detector;
// Ptr descriptor;
// detector = FeatureDetector::create("ORB");
// descriptor = DescriptorExtractor::create("ORB");
// used in OpenCV3
Ptr<FeatureDetector> detector = ORB::create();
Ptr<DescriptorExtractor> descriptor = ORB::create();
// use this if you are in OpenCV2
// Ptr detector = FeatureDetector::create ( "ORB" );
// Ptr descriptor = DescriptorExtractor::create ( "ORB" );
vector< KeyPoint > kp1, kp2;
detector->detect( rgb1, kp1 );
detector->detect( rgb2, kp2 );
// 计算描述子
Mat desp1, desp2;
descriptor->compute( rgb1, kp1, desp1 );
descriptor->compute( rgb2, kp2, desp2 );
// 匹配描述子
vector< DMatch > matches;
BFMatcher matcher;
matcher.match( desp1, desp2, matches );
cout<<"Find total "<<matches.size()<<" matches."<<endl;
// 筛选匹配对
vector< DMatch > goodMatches;
double minDis = 9999;
for ( size_t i=0; i<matches.size(); i++ )
{
if ( matches[i].distance < minDis )
minDis = matches[i].distance;
}
for ( size_t i=0; i<matches.size(); i++ )
{
if (matches[i].distance < 10*minDis)
goodMatches.push_back( matches[i] );
}
vector< Point2f > pts1, pts2;
for (size_t i=0; i<goodMatches.size(); i++)
{
pts1.push_back(kp1[goodMatches[i].queryIdx].pt);
pts2.push_back(kp2[goodMatches[i].trainIdx].pt);
}
// 请先计算基础矩阵并据此绘制出前10个匹配点对应的对极线,可以调用opencv函数
//首先根据对应点计算出两视图的基础矩阵,基础矩阵包含了两个相机的外参数关系
Mat fundamental_matrix=findFundamentalMat(pts1,pts2,CV_FM_8POINT);
//计算对应点的外极线epilines是一个三元组(a,b,c),表示点在另一视图中对应的外极线ax+by+c=0;
vector<cv::Vec<float, 3>> epilines1,epilines2;
computeCorrespondEpilines(pts1,1,fundamental_matrix,epilines1);
computeCorrespondEpilines(pts2,2,fundamental_matrix,epilines2);
cv::RNG &rng = theRNG();
for (int i = 0; i < 10; ++i) {
//随机产生颜色
Scalar color = Scalar(rng(255), rng(255), rng(255));
circle(rgb1, pts1[i], 5, color, 3);
//绘制外极线的时候,选择两个点,一个是x=0处的点,一个是x为图片宽度处
line(rgb1, cv::Point(0, -epilines2[i][2] / epilines2[i][1]),Point(rgb1.cols, -(epilines2[i][2] + epilines2[i][0] * rgb1.cols) / epilines2[i][1]), color);
circle(rgb2, pts2[i], 5, color, 3);
line(rgb2, cv::Point(0, -epilines1[i][2] / epilines1[i][1]),Point(rgb2.cols, -(epilines1[i][2] + epilines1[i][0] * rgb2.cols) / epilines1[i][1]), color);
}
imshow("epiline1", rgb2);
imwrite("../epiline1.jpg",rgb2);
imshow("epiline2", rgb1);
imwrite("../epiline2.jpg",rgb1);
waitKey(0);
return 0;
}