使用BruteForceMatcher或FlannBasedMatcher的KnnMatch进行的面部/图像匹配不正确

Face/Image matching incorrectly done using KnnMatch of BruteForceMatcher or FlannBasedMatcher

本文关键字:面部 图像匹配 不正确 KnnMatch BruteForceMatcher FlannBasedMatcher 使用      更新时间:2023-10-16

Iam正在尝试使用ORB检测器/描述符和Flann或暴力匹配器识别较大目标图像(allimg.jpg包含3个人脸)中的源图像(c1.jpg-人脸)。c1.jpg是从allimg.jpg中通过裁剪/复制创建的。ORB检测器/描述符按预期工作,返回的检测器/描述符正确,但Flann或暴力匹配器给出的目标匹配结果不正确。因此,当我进一步尝试使用findHomography()时,它显示了不正确的结果,将源映射到目标上的其他地方,而不是目标中的正确面(allimg)。虽然下面没有显示代码,但在Knmatch之后,我在比赛结束后在c1.jpg和allimag.jpg上绘制了一个边界矩形,并显示了图像。我发现源边界矩形是正确的,但allimag的边界矩形非常大,包括源面。它应该刚刚在目标中找到了源面。我正在使用opencv 3.0。有人遇到过这样的问题吗?是否有其他匹配器可以准确地在目的地找到源图像(人脸或任何东西)?

我已经给出了下面的代码和图像(通过链接给出):

#include <opencv2/core/core.hpp>
#include <opencv2opencv.hpp>
#include <opencv2/features2d/features2d.hpp>
using namespace std;
using namespace cv;
const double nn_match_ratio = 0.80f; // Nearest-neighbour matching ratio
const double ransac_thresh = 2.5f; // RANSAC inlier threshold
const int bb_min_inliers = 100; // Minimal number of inliers to draw BBox     
Mat img1;
Mat img2;
bool refineMatchesWithHomography(const vector<cv::KeyPoint>& queryKeypoints,    
const vector<cv::KeyPoint>& trainKeypoints,     
float reprojectionThreshold,    
vector<cv::DMatch>& matches,    
Mat& homography  )  
{  
const int minNumberMatchesAllowed = 4;    
if (matches.size() <minNumberMatchesAllowed)    
return false;    
// Prepare data for cv::findHomography    
vector<cv::Point2f> queryPoints(matches.size());    
std::vector<cv::Point2f> trainPoints(matches.size());    
for (size_t i = 0; i <matches.size(); i++)    
{    
queryPoints[i] = queryKeypoints[matches[i].queryIdx].pt;    
trainPoints[i] = trainKeypoints[matches[i].trainIdx].pt;    
}    
// Find homography matrix and get inliers mask    
std::vector<unsigned char> inliersMask(matches.size());    
homography = findHomography(queryPoints,     
trainPoints,     
CV_FM_RANSAC,     
reprojectionThreshold,     
inliersMask);    
vector<cv::DMatch> inliers;    
for (size_t i=0; i<inliersMask.size(); i++)    
{    
if (inliersMask[i])    
inliers.push_back(matches[i]);    
}    
matches.swap(inliers);  
Mat homoShow;  
drawMatches (img1,queryKeypoints,img2,trainKeypoints,matches,homoShow,  
Scalar::all(-1),CV_RGB(255,255,255), Mat(),  2);       
imshow("homoShow",homoShow); 

waitKey(100000);
return matches.size() > minNumberMatchesAllowed;   
}  


int main()
{
//Stats stats;
vector<String> fileName;
fileName.push_back("D:\pmn\c1.jpg");
fileName.push_back("D:\pmn\allimg.jpg");
img1 = imread(fileName[0], CV_LOAD_IMAGE_COLOR);
img2 = imread(fileName[1], CV_LOAD_IMAGE_COLOR);
if (img1.rows*img1.cols <= 0)
{
cout << "Image " << fileName[0] << " is empty or cannot be foundn";
return(0);
}
if (img2.rows*img2.cols <= 0)
{
cout << "Image " << fileName[1] << " is empty or cannot be foundn";
return(0);
}
// keypoint  for img1 and img2
vector<KeyPoint> keyImg1, keyImg2;
// Descriptor for img1 and img2
Mat descImg1, descImg2;

Ptr<Feature2D> porb = ORB::create(500,1.2f,8,0,0,2,0,14);

porb->detect(img2, keyImg2, Mat());
// and compute their descriptors with method  compute
porb->compute(img2, keyImg2, descImg2);
// We can detect keypoint with detect method
porb->detect(img1, keyImg1,Mat());
// and compute their descriptors with method  compute
porb->compute(img1, keyImg1, descImg1);

//FLANN parameters
//  Ptr<flann::IndexParams> indexParams = 
makePtr<flann::LshIndexParams> (6, 12, 1);     
//  Ptr<flann::SearchParams> searchParams = makePtr<flann::SearchParams>                                                           
(50);   
String itMatcher = "BruteForce-L1";
Ptr<DescriptorMatcher> 
matdescriptorMatchercher(newcv::BFMatcher(cv::NORM_HAMMING, false)); 
vector<vector<DMatch> > matches,bestMatches;
vector<DMatch> m;
matdescriptorMatchercher->knnMatch(descImg1, descImg2, matches,2);
const float minRatio = 0.95f;//1.f / 1.5f; 
for (int i = 0; i<matches.size(); i++)
{
if(matches[i].size()>1)     
{
DMatch& bestMatch = matches[i][0];  
DMatch& betterMatch = matches[i][1];  
float distanceRatio = bestMatch.distance / betterMatch.distance;  
if (distanceRatio <minRatio)  
{
bestMatches.push_back(matches[i]);
m.push_back(bestMatch);
}
}
}

Mat homo;  
float homographyReprojectionThreshold = 1.0;  
bool homographyFound = refineMatchesWithHomography(  
keyImg1,keyImg2,homographyReprojectionThreshold,m,homo);  
return 0;
}
[c1.jpg][1]
[allimg.jpg][2]

[1]: https://i.stack.imgur.com/Uuy3o.jpg
[2]: https://i.stack.imgur.com/Kwne7.jpg

谢谢EdChum。我使用了链接中给出的代码(ratiotest/symmetrytest),只有当源图像是目的地的一部分时,它才提供了一些不错的图像匹配,尽管它不够准确。请注意,我确实对上次的ransactionTest进行了评论,因为它删除了很多不必要的阳性结果。我附上了两张图片(source.jpg/destination.jpg),通过突出显示destination中匹配的部分来显示我所说的话。是否有任何算法可以更准确/正确(>90%)地识别目的地的来源?

此外,如果源是一个类似的图像(并且与目的地不完全一样),我发现目的地图像匹配是不可能的,而且毫无用处。我说得对吗?请分享你的观点。1=来源,2=目的