我目前正在开发可以匹配使用热像仪从固定点拍摄的红外和非红外图像的软件。
用例如下: 使用红外热像仪和标准相机使用固定点的三脚架拍摄照片。拍摄完照片后,摄影师想要匹配来自每个相机的图像。在某些情况下,仅使用一个相机拍摄图像,因为不需要其他图像类型。是的,可以使用时间戳来匹配图像,但最终用户要求它们使用计算机视觉进行匹配。
我查看了 StackOverflow 上的其他图像匹配帖子——他们经常专注于使用直方图匹配和特征检测器。直方图匹配在这里不是一个选项,因为我们无法匹配两种图像类型之间的颜色。结果,我开发了一个进行特征检测的应用程序。除了标准特征检测之外,我还添加了一些逻辑,即如果两个关键点不在一定的范围内,则它们不能匹配(查询图像最左侧的关键点无法匹配上的关键点)候选图像的最右边)——这个过程发生在下面代码的第 3 阶段。
为了让您了解当前输出,这里是生成的有效和无效匹配 -请注意热成像图像在左侧。我的目标是提高匹配过程的准确性。
有效匹配:
无效匹配:
这是代码:
// for each candidate image specified on the command line, compare it against the query image
Mat img1 = imread(argv[1], CV_LOAD_IMAGE_GRAYSCALE); // loading query image
for(int candidateImage = 0; candidateImage < (argc - 2); candidateImage++) {
Mat img2 = imread(argv[candidateImage + 2], CV_LOAD_IMAGE_GRAYSCALE); // loading candidate image
if(img1.empty() || img2.empty())
{
printf("Can't read one of the images\n");
return -1;
}
// detecting keypoints
SiftFeatureDetector detector;
vector<KeyPoint> keypoints1, keypoints2;
detector.detect(img1, keypoints1);
detector.detect(img2, keypoints2);
// computing descriptors
SiftDescriptorExtractor extractor;
Mat descriptors1, descriptors2;
extractor.compute(img1, keypoints1, descriptors1);
extractor.compute(img2, keypoints2, descriptors2);
// matching descriptors
BFMatcher matcher(NORM_L1);
vector< vector<DMatch> > matches_stage1;
matcher.knnMatch(descriptors1, descriptors2, matches_stage1, 2);
// use nndr to eliminate weak matches
float nndrRatio = 0.80f;
vector< DMatch > matches_stage2;
for (size_t i = 0; i < matches_stage1.size(); ++i)
{
if (matches_stage1[i].size() < 2)
continue;
const DMatch &m1 = matches_stage1[i][0];
const DMatch &m2 = matches_stage1[i][3];
if(m1.distance <= nndrRatio * m2.distance)
matches_stage2.push_back(m1);
}
// eliminate points which are too far away from each other
vector<DMatch> matches_stage3;
for(int i = 0; i < matches_stage2.size(); i++) {
Point queryPt = keypoints1.at(matches_stage2.at(i).queryIdx).pt;
Point trainPt = keypoints2.at(matches_stage2.at(i).trainIdx).pt;
// determine the lowest number here
int lowestXAxis;
int greaterXAxis;
if(queryPt.x <= trainPt.x) { lowestXAxis = queryPt.x; greaterXAxis = trainPt.x; }
else { lowestXAxis = trainPt.x; greaterXAxis = queryPt.x; }
int lowestYAxis;
int greaterYAxis;
if(queryPt.y <= trainPt.y) { lowestYAxis = queryPt.y; greaterYAxis = trainPt.y; }
else { lowestYAxis = trainPt.y; greaterYAxis = queryPt.y; }
// determine if these points are acceptable
bool acceptable = true;
if( (lowestXAxis + MARGIN) < greaterXAxis) { acceptable = false; }
if( (lowestYAxis + MARGIN) < greaterYAxis) { acceptable = false; }
if(acceptable == false) { continue; }
//// it's acceptable -- provide details, perform input
matches_stage3.push_back(matches_stage2.at(i));
}
// output how many individual matches were found for this training image
cout << "good matches found for candidate image # " << (candidateImage+1) << " = " << matches_stage3.size() << endl;
我以这个网站的代码为例。我遇到的问题是特征检测不可靠,而且我似乎错过了 NNDR 比率的目的。我知道我正在为查询图像中的每个点找到 K 个可能的匹配项,并且我有 K = 2。但我不明白示例代码中这部分的目的:
vector< DMatch > matches_stage2;
for (size_t i = 0; i < matches_stage1.size(); ++i)
{
if (matches_stage1[i].size() < 2)
continue;
const DMatch &m1 = matches_stage1[i][0];
const DMatch &m2 = matches_stage1[i][1];
if(m1.distance <= nndrRatio * m2.distance)
matches_stage2.push_back(m1);
}
关于如何进一步改进这一点的任何想法?任何建议将一如既往地受到赞赏。