直接上代碼吧
#include <iostream>
#include "opencv2/opencv.hpp"
#include"opencv2/core/core.hpp"
#include <opencv2/features2d/features2d.hpp>
bool siftPointsDetect(std::string imgName1, std::string imgName2, int pointNum)
{
cv::Mat img1, img2;
img1 = cv::imread(imgName1);
img2 = cv::imread(imgName2);
if (img1.empty() || img2.empty()) {
std::cout << "error: cannot reading image: " << std::endl;
return false;
}
// sift特征提取
std::vector<cv::KeyPoint> keyPoint1, keyPoint2;
cv::Ptr<cv::Feature2D> feature = cv::SIFT::create(pointNum); // 提取pointNum個特征點
feature->detect(img1, keyPoint1);
feature->detect(img2, keyPoint2);
std::cout << "detect feature ok\n";
cv::Mat descor1, descor2;
feature->compute(img1, keyPoint1, descor1);
feature->compute(img2, keyPoint2, descor2);
std::cout << "generate descor ok\n";
//繪制特征點(關鍵點)
cv::Mat feature_pic1, feature_pic2;
cv::drawKeypoints(img1, keyPoint1, feature_pic1, cv::Scalar(0, 255, 0), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
cv::drawKeypoints(img2, keyPoint1, feature_pic2, cv::Scalar(0, 255, 0), cv::DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
//顯示結果
cv::imwrite("feature1.jpg", feature_pic1);
cv::imwrite("feature2.jpg", feature_pic2);
cv::FlannBasedMatcher matcher; //執行個體化FLANN比對器
std::vector<cv::DMatch>matches; //定義比對結果變量
matcher.match(descor1, descor2, matches); //實作描述符之間的比對
std::cout << "original match numbers: " << matches.size() << std::endl;
cv::Mat oriMatchRes;
cv::drawMatches(img1, keyPoint1, img2, keyPoint2, matches, oriMatchRes,
cv::Scalar(0, 255, 0), cv::Scalar::all(-1));
cv::imwrite("oriMatchResult.jpg", oriMatchRes);
double sum = 0;
double max_dist = 0;
double min_dist = 100;
for (int i = 0; i<matches.size(); i++)
{
double dist = matches[i].distance;
if (dist < min_dist)
min_dist = dist;
if (dist > max_dist)
max_dist = dist;
}
std::cout << "max distance: " << max_dist << std::endl;
std::cout << "min distance: " << min_dist << std::endl;
//篩選出較好的比對點
std::vector<cv::DMatch> goodMatches;
double dThreshold = 0.5; //比對的門檻值,越大比對的點數越多
for (int i = 0; i<matches.size(); i++) {
if (matches[i].distance < dThreshold * max_dist) {
goodMatches.push_back(matches[i]);
}
}
//RANSAC 消除誤比對特征點 主要分為三個部分:
//1)根據matches将特征點對齊,将坐标轉換為float類型
//2)使用求基礎矩陣方法findFundamentalMat,得到RansacStatus
//3)根據RansacStatus來将誤比對的點也即RansacStatus[i]=0的點删除
//根據matches将特征點對齊,将坐标轉換為float類型
std::vector<cv::KeyPoint> R_keypoint01, R_keypoint02;
for (int i = 0; i<goodMatches.size(); i++) {
R_keypoint01.push_back(keyPoint1[goodMatches[i].queryIdx]);
R_keypoint02.push_back(keyPoint2[goodMatches[i].trainIdx]);
// 這兩句話的了解:R_keypoint1是要存儲img01中能與img02比對的特征點,
// matches中存儲了這些比對點對的img01和img02的索引值
}
//坐标轉換
std::vector<cv::Point2f> p01, p02;
for (int i = 0; i<goodMatches.size(); i++) {
p01.push_back(R_keypoint01[i].pt);
p02.push_back(R_keypoint02[i].pt);
}
//計算基礎矩陣并剔除誤比對點
std::vector<uchar> RansacStatus;
cv::Mat Fundamental = findHomography(p01, p02, RansacStatus, CV_RANSAC);
cv::Mat dst;
warpPerspective(img1, dst, Fundamental, cv::Size(img1.cols, img1.rows));
cv::imwrite("epipolarImage.jpg", dst); // 核線影像
// 剔除誤比對的點對
std::vector<cv::KeyPoint> RR_keypoint01, RR_keypoint02;
// 重新定義RR_keypoint 和RR_matches來存儲新的關鍵點和比對矩陣
std::vector<cv::DMatch> RR_matches;
int index = 0;
for (int i = 0; i<goodMatches.size(); i++) {
if (RansacStatus[i] != 0) {
RR_keypoint01.push_back(R_keypoint01[i]);
RR_keypoint02.push_back(R_keypoint02[i]);
goodMatches[i].queryIdx = index;
goodMatches[i].trainIdx = index;
RR_matches.push_back(goodMatches[i]);
index++;
}
}
std::cout << "refine match pairs: " << RR_matches.size() << std::endl;
// 畫出消除誤比對後的圖
cv::Mat img_RR_matches;
cv::drawMatches(img1, RR_keypoint01, img2, RR_keypoint02, RR_matches, img_RR_matches,
cv::Scalar(0, 255, 0), cv::Scalar::all(-1));
cv::imwrite("refineMatchResult.jpg", img_RR_matches);
return true;
}
main 函數如下:
int main(int argc, char *argv[])
{
if (argc < 3) {
std::cout << "error: little parameters\n";
return -1;
}
bool bOk = false;
std::string path = argv[1];
std::string imgName1 = path + argv[2];
std::string imgName2 = path + argv[3];
int detectPointNum = atoi(argv[4]);
if (detectPointNum < 5)
detectPointNum = 5000; // 預設提取5000個特征點
std::cout << "per image detect feature point number: " << detectPointNum << std::endl;
bOk = siftPointsDetect(imgName1, imgName2, detectPointNum);
return 0;
}
希望能幫到你啊