diff --git a/src/examples/fundamental_matrix.cpp b/src/examples/fundamental_matrix.cpp index 6f97ffa9650b0a11ac2de33f345fff84de71f859..7dee8ae9d9c9e3f31c79dc2a669b3b9b251eb706 100644 --- a/src/examples/fundamental_matrix.cpp +++ b/src/examples/fundamental_matrix.cpp @@ -261,7 +261,7 @@ int main(int argc, char** argv) t_filter += double(tFilter - tMatch )/CLOCKS_PER_MSEC; t_fund += double( tFund - tFilter)/CLOCKS_PER_MSEC; - std::cout << "det: " << t_det/n_iter << "ms - desc: " << t_desc/n_iter << "ms - match: " << t_match/n_iter << "ms - filter: " << t_filter/n_iter << "ms - fund: " << t_fund/n_iter << "ms" << std::endl; + std::cout << "det: " << t_det/n_iter << "ms - desc: " << t_desc/n_iter << "ms - match: " << t_match/n_iter << "ms - filter: " << t_filter/n_iter << "ms - found: " << t_fund/n_iter << "ms" << std::endl; std::cout << "+++++++++++++++" << std::endl; diff --git a/src/examples/test_matcher.cpp b/src/examples/test_matcher.cpp index b8a58066fe135d7cb63ff236ea99a6253e79c55d..7f68a07044a5cb1a908f77ef94dc189ed3f91f66 100644 --- a/src/examples/test_matcher.cpp +++ b/src/examples/test_matcher.cpp @@ -142,8 +142,6 @@ int main(void) if (nframe > 1) { DMatchVector best_matches; - KeyPointVector kpts_matched_curf; - KeyPointVector kpts_matched_prevf; // get params MatcherParamsBasePtr mat_params_ptr = mat_ptr->getParams(); @@ -155,7 +153,7 @@ int main(void) mat_ptr->match(descriptors_old,descriptors,des_ptr->getSize(),matches); // filter - mat_ptr->filterByDistance(10, 0.25, kpts_old, kpts, matches, frame_cur.rows, frame_cur.cols, kpts_matched_prevf, kpts_matched_curf, best_matches); + mat_ptr->filterByDistance(10, 0.25, kpts_old, kpts, matches, frame_cur.rows, frame_cur.cols, best_matches); } else { @@ -164,9 +162,19 @@ int main(void) mat_ptr->match(descriptors_old,descriptors,des_ptr->getSize(),matches); //filter - mat_ptr->filterByDistance(10, 0.25, kpts_old, kpts, matches, frame_cur.rows, frame_cur.cols, kpts_matched_prevf, kpts_matched_curf, best_matches); + mat_ptr->filterByDistance(10, 0.25, kpts_old, kpts, matches, frame_cur.rows, frame_cur.cols, best_matches); } + // Get matched KeyPoints + KeyPointVector kpts_matched_curf; + KeyPointVector kpts_matched_prevf; + for (auto match : best_matches) + { + kpts_matched_prevf.push_back(kpts_old[match.queryIdx]); + kpts_matched_curf.push_back(kpts[match.trainIdx]); + } + + // Draw frame_old = frame_cur.clone(); frame_matches = frame_cur.clone(); diff --git a/src/matchers/matcher_base.cpp b/src/matchers/matcher_base.cpp index 40ccd24ae3f6278433a035f687361c5b4c06d053..15290d5be32e534e0cf7ce8dd7361b4a12cd7991 100644 --- a/src/matchers/matcher_base.cpp +++ b/src/matchers/matcher_base.cpp @@ -2,14 +2,14 @@ // yaml-cpp library #ifdef USING_YAML - #include <yaml-cpp/yaml.h> +#include <yaml-cpp/yaml.h> #endif namespace vision_utils { MatcherBase::MatcherBase(const std::string& _type) { - params_base_ptr_ = std::make_shared<MatcherParamsBase>(_type); + params_base_ptr_ = std::make_shared<MatcherParamsBase>(_type); } MatcherBase::~MatcherBase(void) @@ -21,21 +21,21 @@ Scalar MatcherBase::match(const cv::Mat& _desc1, const int& _desc_size_bytes, cv::DMatch& _match) { - std::vector<Scalar> normalized_scores; - if (params_base_ptr_->match_type == MATCH) - { - DMatchVector matches; - normalized_scores = match(_desc1,_desc2,_desc_size_bytes,matches); - _match = matches[0]; - } - else - { - std::vector< DMatchVector > matches; - normalized_scores = match(_desc1,_desc2,_desc_size_bytes,matches); - _match = matches[0][0]; - } - - return normalized_scores[0]; + std::vector<Scalar> normalized_scores; + if (params_base_ptr_->match_type == MATCH) + { + DMatchVector matches; + normalized_scores = match(_desc1,_desc2,_desc_size_bytes,matches); + _match = matches[0]; + } + else + { + std::vector< DMatchVector > matches; + normalized_scores = match(_desc1,_desc2,_desc_size_bytes,matches); + _match = matches[0][0]; + } + + return normalized_scores[0]; } std::vector<Scalar> MatcherBase::match(const cv::Mat& _desc1, @@ -44,29 +44,29 @@ std::vector<Scalar> MatcherBase::match(const cv::Mat& _desc1, DMatchVector& matches, cv::InputArray _mask) { - std::vector<Scalar> normalized_scores; + std::vector<Scalar> normalized_scores; if (params_base_ptr_->match_type==MATCH) { - clock_t tStart = clock(); - if (!_desc1.empty() && !_desc2.empty()) - { - // The following line is needed because flann by default is built with . - // This conversion is required when using with hamming descriptors outputs - // like BRIEF, ORB, FREAK, AKAZE etc - if (_desc1.type()!=CV_32F) - matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); - - matcher_->match( _desc1, _desc2, matches, _mask); - - // here we get only the best match score - for (auto m : matches) - normalized_scores.push_back(1.0 - m.distance/(desc_size_bytes*8)); - } - comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; + clock_t tStart = clock(); + if (!_desc1.empty() && !_desc2.empty()) + { + // The following line is needed because flann by default is built with . + // This conversion is required when using with hamming descriptors outputs + // like BRIEF, ORB, FREAK, AKAZE etc + if (_desc1.type()!=CV_32F) + matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); + + matcher_->match( _desc1, _desc2, matches, _mask); + + // here we get only the best match score + for (auto m : matches) + normalized_scores.push_back(1.0 - m.distance/(desc_size_bytes*8)); + } + comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; } else - std::cerr << "[" << name_ << "]:Wrong match type or output object." << std::endl; + std::cerr << "[" << name_ << "]:Wrong match type or output object." << std::endl; return normalized_scores; } @@ -76,51 +76,51 @@ std::vector<Scalar> MatcherBase::match(const cv::Mat& _desc1, std::vector< DMatchVector >& matches, cv::InputArray _mask) { - std::vector<Scalar> normalized_scores; + std::vector<Scalar> normalized_scores; if (params_base_ptr_->match_type == KNNMATCH)// knn match { - clock_t tStart = clock(); - if (!_desc1.empty() && !_desc2.empty()) - { - // The following line is needed because flann by default is built with . - // This conversion is required when using with hamming descriptors outputs - // like BRIEF, ORB, FREAK, AKAZE etc - if (_desc1.type()!=CV_32F) - matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); - matcher_->knnMatch(_desc1, _desc2, matches, 2); - - // here we get only the best match score - for (auto m : matches) + clock_t tStart = clock(); + if (!_desc1.empty() && !_desc2.empty()) + { + // The following line is needed because flann by default is built with . + // This conversion is required when using with hamming descriptors outputs + // like BRIEF, ORB, FREAK, AKAZE etc + if (_desc1.type()!=CV_32F) + matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); + matcher_->knnMatch(_desc1, _desc2, matches, 2); + + // here we get only the best match score + for (auto m : matches) if (m.size()>0) normalized_scores.push_back(1.0 - m[0].distance/(desc_size_bytes*8)); else normalized_scores.push_back(0.0); - } - comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; + } + comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; } else if (params_base_ptr_->match_type == RADIUSMATCH) // radius match - { - clock_t tStart = clock(); - if (!_desc1.empty() && !_desc2.empty()) - { - // The following line is needed because flann by default is built with . - // This conversion is required when using with hamming descriptors outputs - // like BRIEF, ORB, FREAK, AKAZE etc - if (_desc1.type()!=CV_32F) - matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); - matcher_->radiusMatch(_desc1, _desc2, matches, 2, _mask); - - for (auto m : matches) - if (m.size()>0) - normalized_scores.push_back(1.0 - m[0].distance/(desc_size_bytes*8)); + { + clock_t tStart = clock(); + if (!_desc1.empty() && !_desc2.empty()) + { + // The following line is needed because flann by default is built with . + // This conversion is required when using with hamming descriptors outputs + // like BRIEF, ORB, FREAK, AKAZE etc + if (_desc1.type()!=CV_32F) + matcher_ = new cv::FlannBasedMatcher(new cv::flann::LshIndexParams(LSH_TABLE_NUM, LSH_KEY_SIZE, LSH_MULTI_PROBE_LEVEL)); + matcher_->radiusMatch(_desc1, _desc2, matches, 2, _mask); + + for (auto m : matches) + if (m.size()>0) + normalized_scores.push_back(1.0 - m[0].distance/(desc_size_bytes*8)); else normalized_scores.push_back(0.0); - } - comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; - } + } + comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; + } else - std::cerr << "[" << name_ << "]:Wrong match type or output object." << std::endl; + std::cerr << "[" << name_ << "]:Wrong match type or output object." << std::endl; return normalized_scores; } @@ -130,47 +130,41 @@ std::vector<Scalar> MatcherBase::robustMatch(const KeyPointVector& _raw_kps1, const cv::Mat& _raw_desc1, const cv::Mat& _raw_desc2, const int& desc_size_bytes, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, DMatchVector& _inlier_matches, cv::InputArray _mask) { - assert(!_raw_desc1.empty() && !_raw_desc2.empty() && "[vision_utils]: Robust match: empty descriptors cv::Mat"); - clock_t tStart = clock(); std::vector<Scalar> normalized_scores; - // Obj: distance inliers - KeyPointVector _inlier_dist_kps1, _inlier_dist_kps2; - cv::Mat _inlier_dist_desc1, _inlier_dist_desc2; - DMatchVector _inlier_dist_matches; + if (!_raw_desc1.empty() && !_raw_desc2.empty()) + { + // Obj: distance inliers + DMatchVector _inlier_dist_matches; + if (params_base_ptr_->match_type==MATCH) + { + // Match + DMatchVector raw_matches; + normalized_scores = match(_raw_desc1, _raw_desc2, desc_size_bytes, raw_matches); - if (params_base_ptr_->match_type==MATCH) - { - // Match - DMatchVector raw_matches; - normalized_scores = match(_raw_desc1, _raw_desc2, desc_size_bytes, raw_matches); + // Filter by distance + filterByDistance(_raw_kps1, _raw_kps2, raw_matches, _inlier_dist_matches); + } + else if (params_base_ptr_->match_type == KNNMATCH || params_base_ptr_->match_type == RADIUSMATCH) + { + // Match + std::vector< DMatchVector > raw_matches; + normalized_scores = match(_raw_desc1, _raw_desc2, desc_size_bytes, raw_matches); - // Filter by distance - normalized_scores = filterByDistance(_raw_kps1, _raw_kps2, _raw_desc1, _raw_desc2, raw_matches, _inlier_dist_kps1, _inlier_dist_kps2, _inlier_dist_desc1, _inlier_dist_desc2, _inlier_dist_matches, normalized_scores); - } - else if (params_base_ptr_->match_type == KNNMATCH || params_base_ptr_->match_type == RADIUSMATCH) - { - // Match - std::vector< DMatchVector > raw_matches; - normalized_scores = match(_raw_desc1, _raw_desc2, desc_size_bytes, raw_matches); + // Filter by distance + filterByDistance(_raw_kps1, _raw_kps2, raw_matches, _inlier_dist_matches); + } - // Filter by distance - normalized_scores = filterByDistance(_raw_kps1, _raw_kps2, _raw_desc1, _raw_desc2, raw_matches, _inlier_dist_kps1, _inlier_dist_kps2, _inlier_dist_desc1, _inlier_dist_desc2, _inlier_dist_matches, normalized_scores); + // Ransac test + ransacTest(_raw_kps1, _raw_kps2, _inlier_dist_matches, _inlier_matches); } - // Ransac test - normalized_scores = ransacTest(_inlier_dist_kps1, _inlier_dist_kps2, _inlier_dist_desc1, _inlier_dist_desc2, _inlier_dist_matches, _inlier_kps1, _inlier_kps2, _inlier_desc1, _inlier_desc2, _inlier_matches, normalized_scores); - comp_time_ = (double)(clock() - tStart) / CLOCKS_PER_SEC; return normalized_scores; @@ -184,34 +178,28 @@ void MatcherBase::filterByDistance(const int& _max_pixel_dist, const DMatchVector& _dirty, const int& _img_width, const int& _img_height, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, DMatchVector& _inlier_matches) { - if (params_base_ptr_->match_type == MATCH) - { - double tresholdDist = _img_size_percentage * sqrt(double(_img_height*_img_height + _img_width*_img_width)); - - _inlier_matches.reserve(_dirty.size()); - for (size_t ii = 0; ii < _dirty.size(); ++ii) - { - cv::Point2f p1 = _kps1[_dirty[ii].queryIdx].pt; - cv::Point2f p2 = _kps2[_dirty[ii].trainIdx].pt; - - //calculate local distance for each possible match - double dist = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); - - //save as best match if local distance is in specified area - if (dist < tresholdDist && std::abs(p1.y-p2.y)<_max_pixel_dist && std::abs(p1.x-p2.x)<_max_pixel_dist) - { - _inlier_matches.push_back(_dirty[ii]); - _inlier_kps1.push_back(cv::KeyPoint(p1,1)); - _inlier_kps2.push_back(cv::KeyPoint(p2,1)); - } - } - } - else - std::cerr << "[" << name_ << "]: Wrong input type in filterByDistance method." << std::endl; + if (params_base_ptr_->match_type == MATCH) + { + double tresholdDist = _img_size_percentage * sqrt(double(_img_height*_img_height + _img_width*_img_width)); + + _inlier_matches.reserve(_dirty.size()); + for (size_t ii = 0; ii < _dirty.size(); ++ii) + { + cv::Point2f p1 = _kps1[_dirty[ii].queryIdx].pt; + cv::Point2f p2 = _kps2[_dirty[ii].trainIdx].pt; + + //calculate local distance for each possible match + double dist = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); + + //save as best match if local distance is in specified area + if (dist < tresholdDist && std::abs(p1.y-p2.y)<_max_pixel_dist && std::abs(p1.x-p2.x)<_max_pixel_dist) + _inlier_matches.push_back(_dirty[ii]); + } + } + else + std::cerr << "[" << name_ << "]: Wrong input type in filterByDistance method." << std::endl; } void MatcherBase::filterByDistance(const int& _max_pixel_dist, @@ -221,8 +209,6 @@ void MatcherBase::filterByDistance(const int& _max_pixel_dist, const std::vector< DMatchVector >& _dirty, const int& _img_width, const int& _img_height, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, DMatchVector& _inlier_matches) { if (params_base_ptr_->match_type == KNNMATCH || params_base_ptr_->match_type == RADIUSMATCH) @@ -244,8 +230,6 @@ void MatcherBase::filterByDistance(const int& _max_pixel_dist, if (dist < tresholdDist && std::abs(p1.y-p2.y)<_max_pixel_dist && std::abs(p1.x-p2.x)<_max_pixel_dist) { _inlier_matches.push_back(_dirty[ii][jj]); - _inlier_kps2.push_back(cv::KeyPoint(p2,1)); - _inlier_kps1.push_back(cv::KeyPoint(p1,1)); jj = _dirty[ii].size(); // Keep best match from NN } } @@ -255,17 +239,10 @@ void MatcherBase::filterByDistance(const int& _max_pixel_dist, std::cerr << "[" << name_ << "]: Wrong input type in filterByDistance method." << std::endl; } -std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps1, - const KeyPointVector& _raw_kps2, - const cv::Mat& _raw_desc1, - const cv::Mat& _raw_desc2, - const DMatchVector& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores) +void MatcherBase::filterByDistance(const KeyPointVector& _raw_kps1, + const KeyPointVector& _raw_kps2, + const DMatchVector& _raw_matches, + DMatchVector& _inlier_matches) { std::vector<Scalar> normalized_scores; @@ -276,43 +253,23 @@ std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps { cv::Point2f p1 = _raw_kps1[_raw_matches[ii].queryIdx].pt; cv::Point2f p2 = _raw_kps2[_raw_matches[ii].trainIdx].pt; - cv::Mat d1 = _raw_desc1.row(_raw_matches[ii].queryIdx); - cv::Mat d2 = _raw_desc2.row(_raw_matches[ii].trainIdx); - //calculate local distance for each possible match Scalar dist = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); //save as best match if local distance is in specified area if (dist < params_base_ptr_->max_match_euclidean_dist) - { _inlier_matches.push_back(_raw_matches[ii]); - _inlier_kps1.push_back(cv::KeyPoint(p1,1)); - _inlier_kps2.push_back(cv::KeyPoint(p2,1)); - _inlier_desc1.push_back(d1); - _inlier_desc2.push_back(d2); - if (!_normalized_scores.empty()) - normalized_scores.push_back(_normalized_scores[ii]); - } } } else std::cerr << "[" << name_ << "]: Wrong input type in filterByDistance method." << std::endl; - - return normalized_scores; } -std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps1, - const KeyPointVector& _raw_kps2, - const cv::Mat& _raw_desc1, - const cv::Mat& _raw_desc2, - const std::vector< DMatchVector >& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores) +void MatcherBase::filterByDistance(const KeyPointVector& _raw_kps1, + const KeyPointVector& _raw_kps2, + const std::vector< DMatchVector >& _raw_matches, + DMatchVector& _inlier_matches) { std::vector<Scalar> normalized_scores; @@ -325,8 +282,6 @@ std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps { cv::Point2f p1 = _raw_kps1[_raw_matches[ii][jj].queryIdx].pt; cv::Point2f p2 = _raw_kps2[_raw_matches[ii][jj].trainIdx].pt; - cv::Mat d1 = _raw_desc1.row(_raw_matches[ii][jj].queryIdx); - cv::Mat d2 = _raw_desc2.row(_raw_matches[ii][jj].trainIdx); //calculate local distance for each possible match double dist = std::sqrt((p1.x - p2.x) * (p1.x - p2.x) + (p1.y - p2.y) * (p1.y - p2.y)); @@ -335,12 +290,6 @@ std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps if (dist < params_base_ptr_->max_match_euclidean_dist) { _inlier_matches.push_back(_raw_matches[ii][jj]); - _inlier_kps1.push_back(cv::KeyPoint(p2,1)); - _inlier_kps2.push_back(cv::KeyPoint(p1,1)); - _inlier_desc1.push_back(d1); - _inlier_desc2.push_back(d2); - if (!_normalized_scores.empty()) - normalized_scores.push_back(_normalized_scores[ii]); break; } } @@ -348,56 +297,41 @@ std::vector<Scalar> MatcherBase::filterByDistance(const KeyPointVector& _raw_kps } else std::cerr << "[" << name_ << "]: Wrong input type in filterByDistance method." << std::endl; - - return normalized_scores; } -std::vector<Scalar> MatcherBase::ransacTest(const KeyPointVector& _raw_kps1, - const KeyPointVector& _raw_kps2, - cv::Mat& _raw_desc1, - cv::Mat& _raw_desc2, - const DMatchVector& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores) +void MatcherBase::ransacTest(const KeyPointVector& _raw_kps1, + const KeyPointVector& _raw_kps2, + const DMatchVector& _raw_matches, + DMatchVector& _inlier_matches) { std::vector<Scalar> normalized_scores; - // Convert keypoints into Point2f - PointVector raw_pts1, raw_pts2; - for (std::vector<cv::DMatch>::const_iterator it= _raw_matches.begin(); it!= _raw_matches.end(); ++it) + if (_raw_matches.size() > 0) { - raw_pts1.push_back(_raw_kps1[it->queryIdx].pt); - raw_pts2.push_back(_raw_kps2[it->trainIdx].pt); - } + // Convert keypoints into Point2f + PointVector raw_pts1, raw_pts2; + for (std::vector<cv::DMatch>::const_iterator it= _raw_matches.begin(); it!= _raw_matches.end(); ++it) + { + raw_pts1.push_back(_raw_kps1[it->queryIdx].pt); + raw_pts2.push_back(_raw_kps2[it->trainIdx].pt); + } - // Compute F matrix using RANSAC - std::vector<uchar> inliers(raw_pts1.size(),0); - cv::Mat fundemental= cv::findFundamentalMat(raw_pts1, - raw_pts2, // matching points - inliers, // match status (inlier ou outlier) - CV_FM_RANSAC, // RANSAC method - params_base_ptr_->ransac_epipolar_distance, // distance to epipolar line - params_base_ptr_->ransac_confidence_prob); // confidence probability - - // extract the surviving (inliers) matches - for (unsigned int ii=0; ii<inliers.size(); ii++) - { - if (inliers[ii])// it is a valid match + // Compute F matrix using RANSAC + std::vector<uchar> inliers(raw_pts1.size(),0); + cv::Mat fundemental= cv::findFundamentalMat(raw_pts1, + raw_pts2, // matching points + inliers, // match status (inlier ou outlier) + CV_FM_RANSAC, // RANSAC method + params_base_ptr_->ransac_epipolar_distance, // distance to epipolar line + params_base_ptr_->ransac_confidence_prob); // confidence probability + + // extract the surviving (inliers) matches + for (unsigned int ii=0; ii<inliers.size(); ii++) { - _inlier_matches.push_back(_raw_matches[ii]); - _inlier_kps1.push_back(_raw_kps1[_raw_matches[ii].queryIdx]); - _inlier_kps2.push_back(_raw_kps2[_raw_matches[ii].trainIdx]); - _inlier_desc1.push_back(_raw_desc1.row(_raw_matches[ii].queryIdx)); - _inlier_desc2.push_back(_raw_desc2.row(_raw_matches[ii].trainIdx)); - if (!_normalized_scores.empty()) - normalized_scores.push_back(_normalized_scores[ii]); + if (inliers[ii])// it is a valid match + _inlier_matches.push_back(_raw_matches[ii]); } } - return normalized_scores; } void MatcherBase::nnSymmetryTest(const std::vector<DMatchVector>& _matches1, @@ -429,18 +363,18 @@ void MatcherBase::nnSymmetryTest(const std::vector<DMatchVector>& _matches1, cv::Mat MatcherBase::drawMatches(const cv::Mat _img1, const cv::Mat _img2, KeyPointVector _kpts12_img1, KeyPointVector _kpts12_img2) { - // Concatenate images + // Concatenate images cv::Mat img_graphics; cv::hconcat(_img1, _img2, img_graphics); if (img_graphics.channels()==1) - cvtColor(img_graphics, img_graphics, cv::COLOR_GRAY2RGB); + cvtColor(img_graphics, img_graphics, cv::COLOR_GRAY2RGB); for (int ii = 0; ii < _kpts12_img2.size(); ++ii) { - _kpts12_img2[ii].pt.x = _kpts12_img2[ii].pt.x + _img1.cols; - cv::circle(img_graphics, _kpts12_img1[ii].pt, 5, cv::Scalar(0,255,255)); - cv::circle(img_graphics, _kpts12_img2[ii].pt, 5, cv::Scalar(0,255,255)); - cv::line(img_graphics, _kpts12_img1[ii].pt, _kpts12_img2[ii].pt, cv::Scalar(0,128,128)); + _kpts12_img2[ii].pt.x = _kpts12_img2[ii].pt.x + _img1.cols; + cv::circle(img_graphics, _kpts12_img1[ii].pt, 5, cv::Scalar(0,255,255)); + cv::circle(img_graphics, _kpts12_img2[ii].pt, 5, cv::Scalar(0,255,255)); + cv::line(img_graphics, _kpts12_img1[ii].pt, _kpts12_img2[ii].pt, cv::Scalar(0,128,128)); } return img_graphics; @@ -449,27 +383,27 @@ cv::Mat MatcherBase::drawMatches(const cv::Mat _img1, const cv::Mat _img2, KeyPo cv::Mat MatcherBase::drawMatches(const cv::Mat& _img1, const cv::Mat& _img2, const cv::Mat& _img3, KeyPointVector _kpts12_img1, KeyPointVector _kpts12_img2, KeyPointVector _kpts23_img2, KeyPointVector _kpts23_img3) { - // Concatenate images - cv::Mat img_graphics = drawMatches(_img1, _img2, _kpts12_img1, _kpts12_img2); - cv::Mat img_tmp = _img3.clone(); - if (img_tmp.channels()==1) - cvtColor(img_tmp, img_tmp, cv::COLOR_GRAY2RGB); - cv::hconcat(img_graphics, img_tmp, img_graphics); + // Concatenate images + cv::Mat img_graphics = drawMatches(_img1, _img2, _kpts12_img1, _kpts12_img2); + cv::Mat img_tmp = _img3.clone(); + if (img_tmp.channels()==1) + cvtColor(img_tmp, img_tmp, cv::COLOR_GRAY2RGB); + cv::hconcat(img_graphics, img_tmp, img_graphics); for (int ii = 0; ii < _kpts23_img2.size(); ++ii) { - _kpts23_img2[ii].pt.x = _kpts23_img2[ii].pt.x + _img1.cols; - _kpts23_img3[ii].pt.x = _kpts23_img3[ii].pt.x + _img1.cols + _img2.cols; - cv::circle(img_graphics, _kpts23_img2[ii].pt, 5, cv::Scalar(255,0,255)); - cv::circle(img_graphics, _kpts23_img3[ii].pt, 5, cv::Scalar(255,0,255)); - cv::line(img_graphics, _kpts23_img2[ii].pt, _kpts23_img3[ii].pt, cv::Scalar(128,128,0)); + _kpts23_img2[ii].pt.x = _kpts23_img2[ii].pt.x + _img1.cols; + _kpts23_img3[ii].pt.x = _kpts23_img3[ii].pt.x + _img1.cols + _img2.cols; + cv::circle(img_graphics, _kpts23_img2[ii].pt, 5, cv::Scalar(255,0,255)); + cv::circle(img_graphics, _kpts23_img3[ii].pt, 5, cv::Scalar(255,0,255)); + cv::line(img_graphics, _kpts23_img2[ii].pt, _kpts23_img3[ii].pt, cv::Scalar(128,128,0)); } return img_graphics; } cv::Mat MatcherBase::drawMatches(const cv::Mat& _img1, const cv::Mat& _img2, const cv::Mat& _img3, KeyPointVector _kpts123_img1, KeyPointVector _kpts123_img2, KeyPointVector _kpts123_img3) { - return drawMatches(_img1, _img2, _img3, _kpts123_img1, _kpts123_img2, _kpts123_img2, _kpts123_img3); + return drawMatches(_img1, _img2, _img3, _kpts123_img1, _kpts123_img2, _kpts123_img2, _kpts123_img3); } @@ -491,15 +425,15 @@ MatcherBasePtr setupMatcher(const std::string& _type, const std::string& _unique #ifdef USING_YAML MatcherBasePtr setupMatcher(const std::string& _type, const std::string& _unique_name, const std::string& _filename_dot_yaml) { - ParamsBasePtr params_ptr = ParamsFactory::get().create(_type+" MAT", _filename_dot_yaml); - return setupMatcher(_type, _unique_name, params_ptr); + ParamsBasePtr params_ptr = ParamsFactory::get().create(_type+" MAT", _filename_dot_yaml); + return setupMatcher(_type, _unique_name, params_ptr); } #else MatcherBasePtr setupMatcher(const std::string& _type, const std::string& _unique_name, const std::string& _filename_dot_yaml) { - std::cerr << "[Vision utils]: Current version of the library has no YAML support. " - << "Try installing YAML-related libraries and recompile and reinstall the Vision Utils library." - << std::endl; + std::cerr << "[Vision utils]: Current version of the library has no YAML support. " + << "Try installing YAML-related libraries and recompile and reinstall the Vision Utils library." + << std::endl; return NULL; } #endif diff --git a/src/matchers/matcher_base.h b/src/matchers/matcher_base.h index c89a3cbfadb5ff6219e962ec21445836f647bc33..9df141218f1afd543ff04b67b9520479dc9f5100 100644 --- a/src/matchers/matcher_base.h +++ b/src/matchers/matcher_base.h @@ -95,10 +95,6 @@ class MatcherBase : public VUBase, public std::enable_shared_from_this<MatcherBa const cv::Mat& _raw_desc1, const cv::Mat& _raw_desc2, const int& desc_size_bytes, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, DMatchVector& _inlier_matches, cv::InputArray _mask=cv::noArray()); @@ -109,8 +105,6 @@ class MatcherBase : public VUBase, public std::enable_shared_from_this<MatcherBa const DMatchVector& _dirty, const int& _img_width, const int& _img_height, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, DMatchVector& _inlier_matches); void filterByDistance(const int& _max_pixel_dist, @@ -120,46 +114,23 @@ class MatcherBase : public VUBase, public std::enable_shared_from_this<MatcherBa const std::vector< DMatchVector >& _dirty, const int& _img_width, const int& _img_height, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, DMatchVector& _inlier_matches); - std::vector<Scalar> filterByDistance(const KeyPointVector& _raw_kps1, + void filterByDistance(const KeyPointVector& _raw_kps1, const KeyPointVector& _raw_kps2, - const cv::Mat& _raw_desc1, - const cv::Mat& _raw_desc2, const DMatchVector& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores = std::vector<Scalar>()); - - std::vector<Scalar> filterByDistance(const KeyPointVector& _raw_kps1, + DMatchVector& _inlier_matches); + + void filterByDistance(const KeyPointVector& _raw_kps1, const KeyPointVector& _raw_kps2, - const cv::Mat& _raw_desc1, - const cv::Mat& _raw_desc2, const std::vector< DMatchVector >& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores = std::vector<Scalar>()); + DMatchVector& _inlier_matches); // Identify good matches using RANSAC - std::vector<Scalar> ransacTest(const KeyPointVector& _raw_kps1, + void ransacTest(const KeyPointVector& _raw_kps1, const KeyPointVector& _raw_kps2, - cv::Mat& _raw_desc1, - cv::Mat& _raw_desc2, const DMatchVector& _raw_matches, - KeyPointVector& _inlier_kps1, - KeyPointVector& _inlier_kps2, - cv::Mat& _inlier_desc1, - cv::Mat& _inlier_desc2, - DMatchVector& _inlier_matches, - const std::vector<Scalar>& _normalized_scores = std::vector<Scalar>()); + DMatchVector& _inlier_matches); // Check symmetry between nn matches from <im1->im2> and from <im2->im1> pairs void nnSymmetryTest(const std::vector<DMatchVector>& _matches1, diff --git a/src/test/gtest_matcher_base.cpp b/src/test/gtest_matcher_base.cpp index ca651f01dfbcf70fd5e25abb65c44c45378c5b42..8290a8193c5bb8956121776087344163458f4541 100644 --- a/src/test/gtest_matcher_base.cpp +++ b/src/test/gtest_matcher_base.cpp @@ -97,11 +97,8 @@ TEST(MatcherBase, filterByDistance) mat_ptr->match(desc1,desc2,des_ptr->getSize(),matches); ASSERT_TRUE(matches.size()-75>0); - KeyPointVector inlier_kpts1, inlier_kpts2; - cv::Mat inlier_desc1, inlier_desc2; DMatchVector inlier_matches; - mat_ptr->filterByDistance(kpts1, kpts2, desc1, desc2, matches, - inlier_kpts1, inlier_kpts2, inlier_desc1, inlier_desc2, inlier_matches); + mat_ptr->filterByDistance(kpts1, kpts2, matches, inlier_matches); ASSERT_TRUE(inlier_matches.size()<40); } @@ -155,11 +152,8 @@ TEST(MatcherBase, ransacTest) mat_ptr->match(desc1,desc2,des_ptr->getSize(),matches); ASSERT_TRUE(matches.size()-75>0); - KeyPointVector inlier_kpts1, inlier_kpts2; - cv::Mat inlier_desc1, inlier_desc2; DMatchVector inlier_matches; - mat_ptr->ransacTest(kpts1, kpts2, desc1, desc2, matches, - inlier_kpts1, inlier_kpts2, inlier_desc1, inlier_desc2, inlier_matches); + mat_ptr->ransacTest(kpts1, kpts2, matches, inlier_matches); ASSERT_TRUE(inlier_matches.size()<50); } diff --git a/src/test/gtest_matchers.cpp b/src/test/gtest_matchers.cpp index 4bda4f81feb3b056f15d856a0c2595762ed0da7e..b8920cffc5de20a340db062759daeb11ae504bfb 100644 --- a/src/test/gtest_matchers.cpp +++ b/src/test/gtest_matchers.cpp @@ -66,9 +66,7 @@ TEST(Matchers, MATCH) // filter DMatchVector best_matches; - KeyPointVector kpts_matched_img2; - KeyPointVector kpts_matched_img1; - mat_ptr->filterByDistance(10, 0.25, kpts1, kpts2, matches, image1.rows, image1.cols, kpts_matched_img1, kpts_matched_img2, best_matches); + mat_ptr->filterByDistance(10, 0.25, kpts1, kpts2, matches, image1.rows, image1.cols, best_matches); ASSERT_TRUE(best_matches.size()-35>0); } @@ -119,9 +117,7 @@ TEST(Matchers, KNNMATCH) // filter DMatchVector best_matches; - KeyPointVector kpts_matched_img2; - KeyPointVector kpts_matched_img1; - mat_ptr->filterByDistance(10, 0.25, kpts1, kpts2, matches_vec, image1.rows, image1.cols, kpts_matched_img1, kpts_matched_img2, best_matches); + mat_ptr->filterByDistance(10, 0.25, kpts1, kpts2, matches_vec, image1.rows, image1.cols, best_matches); ASSERT_TRUE(best_matches.size()-45>0); }