问题描述
我正在学习OpenCV,并且已经开始探索用于图像匹配的SURF算法。我已通过修改Microsoft Windows 7可用的默认图像创建了示例图像库。
I am learning OpenCV and have started exploring the SURF Algorithm for image matching. I have created a sample image library by modifying the default images available with Microsoft Windows 7.
每个图像在同一文件夹中具有旋转,缩放,模糊和倾斜的版本。
Each image has a rotated, scaled, blurred and skewed version in the same folder.
我找到匹配图片的代码如下所示。从代码中可以看出,距离通过 dis / objectDescriptors-> total 行测量,进一步的相似性由 100 - (dis / objectDescriptors-> total)* 100 。
My code for finding out matching images is as shown below. As can be seen in the code, the distance is measured by the line dis/objectDescriptors->total and further similarity is calculated by 100 - (dis/objectDescriptors->total) *100.
不幸的是,这给了我一些奇怪的误报。例如,它匹配image1与完全不同的image2(85%相似性),但将显示只有60%的相似性与轻微模糊版本的image1。
Unfortunately, this is giving me some weird false positives. For example, it matches the image1 with completely different image2 (85% similarity) but will show only 60% similarity with the slight blurred version of image1.
如何摆脱假阳性?
下面的代码是从网站href =http://opencvuser.blogspot.in/2012/07/surf-source-code-part-2.html =nofollow> http://opencvuser.blogspot.in/2012/07/surf -source-code-part-2.html
The below code was inspired from the website: http://opencvuser.blogspot.in/2012/07/surf-source-code-part-2.html
#include <cv.h>
#include <highgui.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <iostream>
#include <vector>
using namespace std;
static double dis=0;//For calculating the distance
IplImage *image = 0;
double
compareSURFDescriptors( const float* d1, const float* d2, double best, int length )
{
double total_cost = 0;
assert( length % 4 == 0 );
for( int i = 0; i < length; i += 4 )
{
double t0 = d1[i] - d2[i];
double t1 = d1[i+1] - d2[i+1];
double t2 = d1[i+2] - d2[i+2];
double t3 = d1[i+3] - d2[i+3];
total_cost += t0*t0 + t1*t1 + t2*t2 + t3*t3;
if( total_cost > best )
break;
}
return total_cost;
}
int
naiveNearestNeighbor( const float* vec, int laplacian,
const CvSeq* model_keypoints,
const CvSeq* model_descriptors )
{
int length = (int)(model_descriptors->elem_size/sizeof(float));
int i, neighbor = -1;
double d, dist1 = 1e6, dist2 = 1e6;
CvSeqReader reader, kreader;
cvStartReadSeq( model_keypoints, &kreader, 0 );
cvStartReadSeq( model_descriptors, &reader, 0 );
for( i = 0; i < model_descriptors->total; i++ )
{
const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
const float* mvec = (const float*)reader.ptr;
CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
if( laplacian != kp->laplacian )
continue;
d = compareSURFDescriptors( vec, mvec, dist2, length );
if( d < dist1 )
{
dist2 = dist1;
dist1 = d;
neighbor = i;
}
else if ( d < dist2 )
dist2 = d;
}
dis=dis+dist1;
/*We are finding the distance from every descriptor of probe image to every descriptor of the galley image. Finally in the findpairs function, we divide this distance with the total no. of descriptors to get the average of all the distances
*/
if ( dist1 < 0.6*dist2 )
return neighbor;
return -1;
}
void
findPairs( const CvSeq* objectKeypoints, const CvSeq* objectDescriptors,
const CvSeq* imageKeypoints, const CvSeq* imageDescriptors, vector<int>& ptpairs )
{
int i;
CvSeqReader reader, kreader;
cvStartReadSeq( objectKeypoints, &kreader );
cvStartReadSeq( objectDescriptors, &reader );
ptpairs.clear();
for( i = 0; i < objectDescriptors->total; i++ )
{
const CvSURFPoint* kp = (const CvSURFPoint*)kreader.ptr;
const float* descriptor = (const float*)reader.ptr;
CV_NEXT_SEQ_ELEM( kreader.seq->elem_size, kreader );
CV_NEXT_SEQ_ELEM( reader.seq->elem_size, reader );
int nearest_neighbor = naiveNearestNeighbor( descriptor, kp->laplacian, imageKeypoints, imageDescriptors);
//For every descriptor, we are trying to find it's nearest neighbour in the probe image
if( nearest_neighbor >= 0 )
{
ptpairs.push_back(i);
ptpairs.push_back(nearest_neighbor);
}
}
printf("\n%lf\n",(dis/objectDescriptors->total));////Here's where I am outputting the distance between the images
/*Dileep: If you are using this for recognition, write this distance to a file along with the name of the image you are matching against. After doing this for several images, you can then sort them in ascending order to find the best possible match - the one with the smallest distance. Here, I am outputting the distance to stdout
*/
}
int main(int argc, char** argv)
{
const char* object_filename = argc == 3 ? argv[1] : "box.png";
const char* scene_filename = argc == 3 ? argv[2] : "box_in_scene.png";
//Dileep:When you are excuting the object file, please write Command:./objectfile probe_image Gallery_image
/*Dileep:
Probe_image - This is the image for which you need to find the match
Gallery_image - This is one of the set of images, you use for matching
You keep the same probe image same, repeatedly changing the gallery image and outputting the distance in the format
<Gallery_name distance> into a file
Finally you can sort the distances in ascending order. And the one with the shortest distance - You can output it's name as the best possible match
It may become tedious to continually write the same command multiple times, changing the gallery file name. Try to use shell script with a for loop
*/
CvMemStorage* storage = cvCreateMemStorage(0);
IplImage* object = cvLoadImage( object_filename, CV_LOAD_IMAGE_GRAYSCALE );
IplImage* image = cvLoadImage( scene_filename, CV_LOAD_IMAGE_GRAYSCALE );
if( !object || !image )
{
fprintf( stderr, "Can not load %s and/or %s\n"
"Usage: find_obj [<object_filename> <scene_filename>]\n",
object_filename, scene_filename );
exit(-1);
}
CvSeq *objectKeypoints = 0, *objectDescriptors = 0;
CvSeq *imageKeypoints = 0, *imageDescriptors = 0;
int i;
CvSURFParams params = cvSURFParams(500, 1);
double tt = (double)cvGetTickCount();
cvExtractSURF( object, 0, &objectKeypoints, &objectDescriptors, storage, params );
printf("Object Descriptors: %d\n", objectDescriptors->total);
cvExtractSURF( image, 0, &imageKeypoints, &imageDescriptors, storage, params );
printf("Image Descriptors: %d\n", imageDescriptors->total);
tt = (double)cvGetTickCount() - tt;
printf( "Extraction time = %gms\n", tt/(cvGetTickFrequency()*1000.));
vector<int> ptpairs;
findPairs( objectKeypoints, objectDescriptors, imageKeypoints, imageDescriptors, ptpairs );
return 0;
}
推荐答案
- 从两个图片获取功能。
- 计算与相邻比率的假定对应
- 查找支持图像之间的几何关系的一致性对应关系的子集。
您已完成步骤1和2,但缺少3。注意,推定的对应是非常嘈杂的。你会得到很多信件,很多都是错的,但有些正确。很难确定他们是否只是通过绘制他们正确计算。
You have done steps 1 and 2, but 3 is missing. Note that putative correspondences are very noisy. You will obtain a lot of correspondences, many of them wrong, but some correct. It is difficult to tell for sure if them are correctly computed just by drawing them. So, it is normal that you see apparently weird correspondences.
要做第3步,在你的情况下,你可以找到一个与RANSAC的单应性,@ user3481173说。这很容易,因为OpenCV已经提供了同时执行这两个操作的函数 cvFindHomography
。因为你处理的是平面图像的透视变换,所以单应性在你的情况下应该工作得很好。
To do step 3, in your case you can find a homography with RANSAC, as @user3481173 says. It is very easy, because OpenCV already provides the function cvFindHomography
that does both things at the same time. A homography should work well in your case, since you are dealing with perspective transformations of planar images.
顺便说一下,在将来你会更容易使用OpenCV的C ++ API。相同的代码可能占据您所拥有的一半。
By the way, it will be much easier to you in the future to use the C++ API of OpenCV. The same code will probably occupy half the lines you have.
这篇关于OpenCV - 冲浪算法 - 提供大量的误报的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!