OpenCV的RobustMatch匹配算法


1.首先看看類定義:

class RobustMatcher   
{
private:
// pointer to the feature point detector object
cv::Ptr<cv::FeatureDetector> detector;
// pointer to the feature descriptor extractor object
cv::Ptr<cv::DescriptorExtractor> extractor;
// pointer to the matcher object
cv::Ptr<cv::DescriptorMatcher > matcher;
float ratio; // max ratio between 1st and 2nd NN
bool refineF; // if true will refine the F matrix
double distance; // min distance to epipolar
double confidence; // confidence level (probability)

public:
RobustMatcher() : ratio(0.65f), refineF(true),
confidence(0.99), distance(3.0)
{
// ORB is the default feature
detector= new cv::OrbFeatureDetector();
extractor= new cv::OrbDescriptorExtractor();
matcher= new cv::BruteForceMatcher<cv::HammingLUT>;
}

// Set the feature detector
void setFeatureDetector(cv::Ptr<cv::FeatureDetector>& detect)
{
detector= detect;
}
// Set the descriptor extractor
void setDescriptorExtractor(cv::Ptr<cv::DescriptorExtractor>& desc)
{
extractor= desc;
}
// Set the matcher
void setDescriptorMatcher(cv::Ptr<cv::DescriptorMatcher>& match)
{
matcher= match;
}
// Set confidence level
void setConfidenceLevel(double conf)
{
confidence= conf;
}
//Set MinDistanceToEpipolar
void setMinDistanceToEpipolar(double dist)
{
distance= dist;
}
//Set ratio
void setRatio(float rat)
{
ratio= rat;
}

cv::Mat match(cv::Mat& image1, cv::Mat& image2, // input images
// output matches and keypoints
std::vector<cv::DMatch>& matches,
std::vector<cv::KeyPoint>& keypoints1,
std::vector<cv::KeyPoint>& keypoints2);

cv::Mat ransacTest(
const std::vector<cv::DMatch>& matches,
const std::vector<cv::KeyPoint>& keypoints1,
const std::vector<cv::KeyPoint>& keypoints2,
std::vector<cv::DMatch>& outMatches);

void symmetryTest(
const std::vector<std::vector<cv::DMatch> >& matches1,
const std::vector<std::vector<cv::DMatch> >& matches2,
std::vector<cv::DMatch>& symMatches);

int ratioTest(std::vector<std::vector<cv::DMatch>>& matches);
};

2.cpp中的內容為:

int RobustMatcher::ratioTest(std::vector<std::vector<cv::DMatch> >  
&matches)
{
int removed=0;
// for all matches
for (std::vector<std::vector<cv::DMatch> >::iterator
matchIterator= matches.begin();
matchIterator!= matches.end(); ++matchIterator)
{
// if 2 NN has been identified
if (matchIterator->size() > 1)
{
// check distance ratio
if ((*matchIterator)[0].distance/
(*matchIterator)[1].distance > ratio)
{
matchIterator->clear(); // remove match
removed++;
}
} else
{ // does not have 2 neighbours
matchIterator->clear(); // remove match
removed++;
}
}
return removed;//返回被刪除的點數量
}

// Insert symmetrical matches in symMatches vector
void RobustMatcher::symmetryTest(
const std::vector<std::vector<cv::DMatch> >& matches1,
const std::vector<std::vector<cv::DMatch> >& matches2,
std::vector<cv::DMatch>& symMatches)
{
// for all matches image 1 -> image 2
for (std::vector<std::vector<cv::DMatch> >::
const_iterator matchIterator1= matches1.begin();
matchIterator1!= matches1.end(); ++matchIterator1)
{
// ignore deleted matches
if (matchIterator1->size() < 2)
continue;
// for all matches image 2 -> image 1
for (std::vector<std::vector<cv::DMatch> >::
const_iterator matchIterator2= matches2.begin();
matchIterator2!= matches2.end();
++matchIterator2)
{
// ignore deleted matches
if (matchIterator2->size() < 2)
continue;
// Match symmetry test
if ((*matchIterator1)[0].queryIdx ==
(*matchIterator2)[0].trainIdx &&
(*matchIterator2)[0].queryIdx ==
(*matchIterator1)[0].trainIdx)
{
// add symmetrical match
symMatches.push_back(
cv::DMatch((*matchIterator1)[0].queryIdx,
(*matchIterator1)[0].trainIdx,
(*matchIterator1)[0].distance));
break; // next match in image 1 -> image 2
}
}
}
}

// Identify good matches using RANSAC
// Return fundemental matrix
cv::Mat RobustMatcher::ransacTest(
const std::vector<cv::DMatch>& matches,
const std::vector<cv::KeyPoint>& keypoints1,
const std::vector<cv::KeyPoint>& keypoints2,
std::vector<cv::DMatch>& outMatches)
{
// Convert keypoints into Point2f
std::vector<cv::Point2f> points1, points2;
cv::Mat fundemental;
for (std::vector<cv::DMatch>::
const_iterator it= matches.begin();
it!= matches.end(); ++it)
{
// Get the position of left keypoints
float x= keypoints1[it->queryIdx].pt.x;
float y= keypoints1[it->queryIdx].pt.y;
points1.push_back(cv::Point2f(x,y));
// Get the position of right keypoints
x= keypoints2[it->trainIdx].pt.x;
y= keypoints2[it->trainIdx].pt.y;
points2.push_back(cv::Point2f(x,y));
}
// Compute F matrix using RANSAC
std::vector<uchar> inliers(points1.size(),0);
if (points1.size()>0&&points2.size()>0)
{
cv::Mat fundemental= cv::findFundamentalMat(
cv::Mat(points1),cv::Mat(points2), // matching points
inliers, // match status (inlier or outlier)
CV_FM_RANSAC, // RANSAC method
distance, // distance to epipolar line
confidence); // confidence probability
// extract the surviving (inliers) matches
std::vector<uchar>::const_iterator
itIn= inliers.begin();
std::vector<cv::DMatch>::const_iterator
itM= matches.begin();
// for all matches
for ( ;itIn!= inliers.end(); ++itIn, ++itM)
{
if (*itIn)
{ // it is a valid match
outMatches.push_back(*itM);
}
}
if (refineF)
{
// The F matrix will be recomputed with
// all accepted matches
// Convert keypoints into Point2f
// for final F computation
points1.clear();
points2.clear();
for (std::vector<cv::DMatch>::
const_iterator it= outMatches.begin();
it!= outMatches.end(); ++it)
{
// Get the position of left keypoints
float x= keypoints1[it->queryIdx].pt.x;
float y= keypoints1[it->queryIdx].pt.y;
points1.push_back(cv::Point2f(x,y));
// Get the position of right keypoints
x= keypoints2[it->trainIdx].pt.x;
y= keypoints2[it->trainIdx].pt.y;
points2.push_back(cv::Point2f(x,y));
}
// Compute 8-point F from all accepted matches
if (points1.size()>0&&points2.size()>0)
{
fundemental= cv::findFundamentalMat(
cv::Mat(points1),cv::Mat(points2), // matches
CV_FM_8POINT); // 8-point method
}
}
}
return fundemental;
}

// Match feature points using symmetry test and RANSAC
// returns fundemental matrix
cv::Mat RobustMatcher:: match(cv::Mat& image1,
cv::Mat& image2, // input images
// output matches and keypoints
std::vector<cv::DMatch>& matches,
std::vector<cv::KeyPoint>& keypoints1,
std::vector<cv::KeyPoint>& keypoints2)
{
// 1a. Detection of the ORB features
detector->detect(image1,keypoints1);
detector->detect(image2,keypoints2);
// 1b. Extraction of the ORB descriptors
cv::Mat descriptors1, descriptors2;
extractor->compute(image1,keypoints1,descriptors1);
extractor->compute(image2,keypoints2,descriptors2);

// 2. Match the two image descriptors
// Construction of the matcher
//cv::BruteForceMatcher<cv::L2<float>> matcher;
// from image 1 to image 2
// based on k nearest neighbours (with k=2)
std::vector<std::vector<cv::DMatch> > matches1;
matcher->knnMatch(descriptors1,descriptors2,
matches1, // vector of matches (up to 2 per entry)
2); // return 2 nearest neighbours
// from image 2 to image 1
// based on k nearest neighbours (with k=2)
std::vector<std::vector<cv::DMatch> > matches2;
matcher->knnMatch(descriptors2,descriptors1,
matches2, // vector of matches (up to 2 per entry)
2); // return 2 nearest neighbours

// 3. Remove matches for which NN ratio is
// > than threshold
// clean image 1 -> image 2 matches
int removed= ratioTest(matches1);
// clean image 2 -> image 1 matches
removed= ratioTest(matches2);

// 4. Remove non-symmetrical matches
std::vector<cv::DMatch> symMatches;
symmetryTest(matches1,matches2,symMatches);

//=========================================測試代碼
cv::Mat img_matches;
cv::drawMatches( image1, keypoints1, image2, keypoints2,
symMatches, img_matches, cv::Scalar::all(-1), cv::Scalar::all(-1),
std::vector<char>(), cv::DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
/*imshow("Test",img_matches);*/
//cvWaitKey(0);
//=========================================測試代碼

// 5. Validate matches using RANSAC
cv::Mat fundemental= ransacTest(symMatches,
keypoints1, keypoints2, matches);

//=========================================測試代碼
std::vector<cv::Point2f> obj;
std::vector<cv::Point2f> scene;

for( int i = 0; i < symMatches.size(); i++ )
{
//-- Get the keypoints from the good matches
obj.push_back( keypoints1[ symMatches[i].queryIdx ].pt );
scene.push_back( keypoints2[ symMatches[i].trainIdx ].pt );
}
cv::Mat H = cv::findHomography( obj, scene, CV_RANSAC ,2);

//-- Get the corners from the image_1 ( the object to be "detected" )
std::vector<cv::Point2f> obj_corners(4);
obj_corners[0]=cvPoint(0,0);
obj_corners[1]=cvPoint(image1.cols, 0 );
obj_corners[2]=cvPoint(image1.cols,image1.rows);
obj_corners[3]=cvPoint(0,image1.rows);
std::vector<cv::Point2f> scene_corners(4);

cv::perspectiveTransform( obj_corners, scene_corners, H);
for( int i = 0; i < 4; i++ )
{
scene_corners[i].x+=image1.cols;
}
line( img_matches, scene_corners[0], scene_corners[1], cv::Scalar(0, 255, 0), 2 );
line( img_matches, scene_corners[1], scene_corners[2], cv::Scalar( 0, 255, 0), 2 );
line( img_matches, scene_corners[2], scene_corners[3], cv::Scalar( 0, 255, 0), 2 );
line( img_matches, scene_corners[3], scene_corners[0], cv::Scalar( 0, 255, 0), 2 );
imshow("Test",img_matches);
cvWaitKey(0);
//=========================================測試代碼


// return the found fundemental matrix
return fundemental;
}
剔除低質量匹配點
ratioTest用來剔除距離比例相差過大的配對點,配對點之間的距離相差越大,能匹配上的概率也就越小。這里使用一個參數ratio來控制剔除距離相差在一定范圍之外的特征點。

symmetryTest用來判斷兩個圖像間的特征點匹配是否是一一映射,對於不是的點則剔除掉

3.具體調用的例子:

void main()  
{
// set parameters

int numKeyPoints = 1500;

//Instantiate robust matcher

RobustMatcher rmatcher;

//instantiate detector, extractor, matcher

cv::Ptr<cv::FeatureDetector> detector = new cv::OrbFeatureDetector(numKeyPoints);
cv::Ptr<cv::DescriptorExtractor> extractor = new cv::OrbDescriptorExtractor;
cv::Ptr<cv::DescriptorMatcher> matcher = new cv::BruteForceMatcher<cv::HammingLUT>;

rmatcher.setFeatureDetector(detector);
rmatcher.setDescriptorExtractor(extractor);
rmatcher.setDescriptorMatcher(matcher);

//Load input image detect keypoints

cv::Mat img1;
std::vector<cv::KeyPoint> img1_keypoints;
cv::Mat img1_descriptors;
cv::Mat img2;
std::vector<cv::KeyPoint> img2_keypoints;
cv::Mat img2_descriptors;

std::vector<cv::DMatch> matches;

img1 = cv::imread("C:\\temp\\PyramidPattern.jpg", CV_LOAD_IMAGE_GRAYSCALE);
/*img2 = cv::imread("C:\\temp\\PyramidPatternTest.bmp", CV_LOAD_IMAGE_GRAYSCALE);*/
//img2 = cv::imread("C:\\temp\\test1.jpg", CV_LOAD_IMAGE_GRAYSCALE);
img2 = cv::imread("C:\\temp\\test2.jpg", CV_LOAD_IMAGE_GRAYSCALE);

rmatcher.match(img1, img2, matches, img1_keypoints, img2_keypoints);
}

最后,對於OpenCV中的所有特征匹配算法都可以用這個辦法來做,比如SIFT, SURF等等。只需要簡單的替換第一步中的extractor和detector就可以了。

匹配效果還不錯,上個圖

但是缺點也是存在的,如果完整匹配下來,大約一幀耗時100+ms,不適合實時性要求較高的應用






注意!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。



 
粤ICP备14056181号  © 2014-2021 ITdaan.com