精华内容
下载资源
问答
  • FLANN特征匹配

    千次阅读 2019-06-21 11:36:39
    FLANN特征匹配 特征的概念: 一个图像块是由相似平面组成,其在原图像中会有大量相同的区域。 一个图像块取自原图像的边缘,其具有横向或纵向的差异性,而在与该方向垂直的角度上相同。 一个图像块取自原图像的角点...

    FLANN特征匹配

    特征的概念:

    • 一个图像块是由相似平面组成,其在原图像中会有大量相同的区域。
    • 一个图像块取自原图像的边缘,其具有横向或纵向的差异性,而在与该方向垂直的角度上相同。
    • 一个图像块取自原图像的角点,其具有移动后的不同性。…[其它具有不同特点的图像块]
      好的图像特征应具有唯一性,即选取该图像周围的一块区域进行移动,其视觉印象会不同

    图像的特征工程:

    1. 特征提取:寻找易于追踪和对比的特征————在图像所有区域中寻找向周围少量移动时变化最大的图像块————将这种操作映射到计算机语言中。
    2. 特征描述:对提取的特征[特征周围的区域]用计算机的语言进行描述,使得其能够在其它图像中寻找到相似区域。
    3. 特征匹配:根据特征描述,在其它图像中寻找所有相同的特征区域,以便进行需求的操作[如排列,整合等]。

    FLANN:
    FLANN是一种高效的数值或者字符串匹配算法,SIFT/SURF是基于浮点数的匹配,ORB是二值匹配,速度更快。对于FLANN匹配算法,当使用ORB匹配算法的时候,需要重新构造HASH。这个在C++的代码种做了演示。对匹配之后的输出结果,根据距离进行排序,就会得到距离比较的匹配点

    例图:
    在这里插入图片描述
    例子:

    #include <opencv2/opencv.hpp>
    #include <iostream>
    #include <cmath>
    
    const float  RATIO = 0.4;
    
    
    using namespace cv;
    using namespace std;
    
    int main(int argc, char** argv) {
    
    	Mat box = imread("E:/opencv/box.png");
    	Mat scene = imread("E:/opencv/box_in_scene.png");
    
    	if (!box.data || !scene.data) {
    		cout << "没有找到图片" << endl;
    		return -1;
    	}
    	imshow("box ", box);
    	imshow("box_in_scene", scene);
    
    	//创建关键点集变量
    	vector<KeyPoint> kpt_obj, kpt_sence;
    	//描述子
    	Mat descriptors_box, descriptors_sence;
    
    	//计算描述符(特征向量)
    	Ptr<ORB> detector = ORB::create();
    
    	//检测
    	detector->detectAndCompute(scene, Mat(), kpt_sence, descriptors_sence);
    	detector->detectAndCompute(box, Mat(), kpt_obj, descriptors_box);
    
    	vector<DMatch> matches;
    	//基于FLANN的描述符对象匹配
    	Ptr<DescriptorMatcher> matcher = makePtr<FlannBasedMatcher>(makePtr<flann::LshIndexParams>(12, 20, 2));
    	//匹配
    	matcher->match(descriptors_box, descriptors_sence, matches);
    
    	//发现匹配
    	vector<DMatch> goodMatches;
    	printf("total match points : %d\n", matches.size());
    
    	float maxdist = 0;
    	//matches[i].distance描述符欧式距离(knn)
    
    	//找到最大的距离
    	for (unsigned int i = 0; i < matches.size(); ++i) {
    		printf("dist : %.2f \n", matches[i].distance);
    		maxdist = max(maxdist, matches[i].distance);
    	}
    	for (unsigned int i = 0; i < matches.size(); ++i) {
    		if (matches[i].distance < maxdist*RATIO)
    			goodMatches.push_back(matches[i]);
    	}
    
    	Mat dst;
    
    	drawMatches(box, kpt_obj, scene, kpt_sence, goodMatches, dst);
    
    	imshow("output", dst);
    
    	waitKey(0);
    	return 0;
    }
    
    展开全文
  • 今天小编就为大家分享一篇opencv3/C++ FLANN特征匹配方式,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧
  • 特征描述子与匹配: 暴力匹配:Brute-Force匹配 class cv::BFMatcher : public cv::DescriptorMatcher { public: BFMatcher(int normType, bool crossCheck = false); virtual ~BFMatcher() {} ...FLANN特征匹配
  • 【总结】FLANN特征匹配

    千次阅读 2019-10-17 09:57:48
    工作需要用到FLANN特征匹配技术,在这里记录一些关键知识点。 ORB (Oriented FAST and Rotated BRIEF) 算法简介 分为两部分: 特征点提取 -由FAST(Features from Accelerated Segment Test)算法发展来的 特征...

    工作需要用到FLANN特征匹配技术,在这里记录一些关键知识点。

    ORB (Oriented FAST and Rotated BRIEF)  算法简介

       分为两部分:

    • 特征点提取 -由FAST(Features from Accelerated Segment Test)算法发展来的
    • 特征点描述 -根据BRIEF(Binary Robust IndependentElementary Features)特征描述算法改进的

    暴力匹配(cv2.BFMatcher)

    即两两匹配。该算法不做任何优化,假设ORB算法从图片A中提取了m个特征描述符,从图片B中提取了n个特征描述符。暴力匹配器将图片A中m个描述符逐一和图片B中的n个特征描述符求距离,然后对得到的距离排序,取距离最近的一个作为最佳匹配点,这种方法简单粗暴,其结果也是显而易见的,会有大量的错误匹配,这就需要使用一些机制来过滤掉错误的匹配(比如下面的Lowe’s算法

     

    cv2.BFMatcher参数说明:

     normType:它是用来指定要使用的距离测试类型。默认值为cv2.Norm_L2。这很适合SIFT和SURF等(c2.NORM_L1也可)。对于使用二进制描述符的ORB、BRIEF和BRISK算法等,要使用cv2.NORM_HAMMING,这样就会返回两个测试对象之间的汉明距离。如果ORB算法的参数设置为WTA_K==3或4,normType就应该设置成cv2.NORM_HAMMING2。
    crossCheck:使用交叉匹配的方法来滤除错误匹配,默认值为False。若设置为True,匹配条件就会更加严格,只有到图片A中的第i个特征点与图片B中的第j个特征点距离最近,反过来,还要图片B中的第j个特征点到图片A中的第i个特征点也是最近,才会认为他们是最佳匹配(i,j)并返回,即:这两个特征点要互相匹配才行。(你喜欢我,我也喜欢你,单恋可不行...)
     

    暴力匹配器BFMatcher有两个重要的方法,分别是BFMatcher.match() BFMatcher.knnMatch()。送入查询图片A和目标图片B

    match() 方法会为图片A从图片B中找到最佳的单个匹配点;

    knnMatch()方法会为图片A从图片B中找到最佳的前k个匹配点,k值由用户指定。当我们需要做一些额外的工作时,这种方法会很有用。

     

    Lowe’s算法:

    为了进一步筛选匹配点,获取优秀的匹配点,即“去粗取精”。为了排除因为图像遮挡和背景混乱而产生的无匹配关系的关键点,SIFT的作者Lowe提出了比较最近邻距离与次近邻距离的SIFT匹配方式:

    取一幅图像中的一个SIFT关键点,并找出其与另一幅图像中欧式距离最近的前两个关键点,在这两个关键点中,如果最近的距离除以次近的距离得到的比率ratio少于某个阈值T,则接受这一对匹配点。因为对于错误匹配,由于特征空间的高维性,相似的距离可能有大量其他的错误匹配,从而它的ratio值比较高。显然降低这个比例阈值T,SIFT匹配点数目会减少,但更加稳定,反之亦然。
      Lowe推荐ratio的阈值为0.8;

    有网友对大量存在任意尺度、旋转和亮度变化的两幅图片进行匹配,结果表明ratio取值在0. 4~0. 6 之间最佳,小于0. 4的很少有匹配点,大于0. 6的则存在大量错误匹配点,所以建议ratio的取值原则如下(仅供参考):

    ratio=0. 4:对于准确度要求高的匹配;

    ratio=0. 6:对于匹配点数目要求比较多的匹配;

    ratio=0. 5:一般情况下。

    Lowe's改进:可以反过来使用最近邻比次近邻,在匹配中可以作为置信度来使用,当满足最近邻比次近邻大于某个值的时候,作为某个条件的判别置信度;比如可以应用在双目视觉立体匹配中的视差选择与优化环节中(论文正在编写中);

    下面博客提到了ORB(二值特征编码)如何跟FLANN结合使用(很详细)

    https://www.jianshu.com/p/42b61d42e0bc

    需要修改的关键代码如下:

    FLANN_INDEX_LSH=6
    indexParams=dict(algorithm=FLANN_INDEX_LSH, 
                     table_number = 6, #12
                     key_size = 12,    #20
                     multi_probe_level = 1)#2
    searchParams=dict(checks=100)

    GPU加速的orb算法相关博客(c++):

    https://blog.csdn.net/bisheng250/article/details/53691099

    https://blog.csdn.net/dlphay/article/details/79021472

     

    PyCUDA官方教程:

    https://documen.tician.de/pycuda/ (英文)

    https://blog.cycleuser.org/pycuda-tutorial-zhong-wen-ban.html  (中文)

    https://www.cnblogs.com/noluye/p/11517489.html

    https://blog.csdn.net/qq_36387683/article/details/81075870 (pycuda和numba的比较)

    https://blog.csdn.net/u013390476/article/details/82194709

     

    利用深度学习来做特征匹配:

    论文笔记之:MatchNet: Unifying Feature and Metric Learning for Patch-Based Matching

    https://www.cnblogs.com/wangxiaocvpr/p/5515181.html

    里面关键一句:双塔的输出串联在一起作为度量网络的输入!

    基于深度学习的图像匹配技术专题

    https://blog.csdn.net/aaron121211/article/details/78707215

     

    展开全文
  • FLANN - Fast Library for Approximate Nearest Neighbors FLANN is a library for performing fast approximate nearest neighbor searches in high dimensional spaces. It contains a collection of algorithms ...
  • OpenCV学习笔记[5]FLANN特征匹配

    千次阅读 2014-11-05 15:59:03
    OpenCV学习笔记:FLANN特征匹配 本次给出FLANN特征匹配的Java实现。特征匹配记录下目标图像与待匹配图像的特征点(KeyPoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较、筛选,最终得到一...

    OpenCV学习笔记:FLANN特征匹配


            本次给出FLANN特征匹配的Java实现。

    [简介]

            特征匹配记录下目标图像与待匹配图像的特征点(KeyPoint),并根据特征点集合构造特征量(descriptor),对这个特征量进行比较、筛选,最终得到一个匹配点的映射集合。我们也可以根据这个集合的大小来衡量两幅图片的匹配程度。

            特征匹配与模板匹配不同,由于是计算特征点集合的相关度,转置操作对匹配影响不大,但它容易受到失真、缩放的影响。

    [特征匹配]

    FeatureMatching.java:

    import org.opencv.core.Mat;
    import org.opencv.core.MatOfDMatch;
    import org.opencv.core.MatOfKeyPoint;
    import org.opencv.features2d.DescriptorExtractor;
    import org.opencv.features2d.DescriptorMatcher;
    import org.opencv.features2d.FeatureDetector;
    import org.opencv.highgui.Highgui;
    
    import com.thrblock.opencv.fm.view.ConsoleView;
    import com.thrblock.opencv.fm.view.MatchingView;
    
    public class FeatureMatching {
    	private Mat src;
    	private MatOfKeyPoint srcKeyPoints;
    	private Mat srcDes;
    	
    	private FeatureDetector detector;
    	private DescriptorExtractor extractor;
    	private DescriptorMatcher matcher;
    
    	private MatchingView view;
    	public FeatureMatching(MatchingView view) {
    		this.view = view;
    		srcKeyPoints = new MatOfKeyPoint();
    		srcDes = new Mat();
    		detector = FeatureDetector.create(FeatureDetector.SURF);
    		extractor = DescriptorExtractor.create(DescriptorExtractor.SURF);
    		matcher = DescriptorMatcher.create(DescriptorMatcher.FLANNBASED);
    	}
    
    	public int doMaping(String dstPath) {
    		view.setDstPic(dstPath);
    		// 读入待测图像
    		Mat dst = Highgui.imread(dstPath);
    		System.out.println("DST W:"+dst.cols()+" H:" + dst.rows());
    		// 待测图像的关键点
    		MatOfKeyPoint dstKeyPoints = new MatOfKeyPoint();
    		detector.detect(dst, dstKeyPoints);
    		// 待测图像的特征矩阵
    		Mat dstDes = new Mat();
    		extractor.compute(dst, dstKeyPoints, dstDes);
    		// 与原图匹配
    		
    		MatOfDMatch matches = new MatOfDMatch();
    		matcher.match(dstDes, srcDes, matches);
    		//将结果输入到视图 并得到“匹配度”
    		return view.showView(matches, srcKeyPoints, dstKeyPoints);
    	}
    
    	public void setSource(String srcPath) {
    		view.setSrcPic(srcPath);
    		// 读取图像 写入矩阵
    		src = Highgui.imread(srcPath);
    		System.out.println("SRC W:"+src.cols()+" H:" + src.rows());
    		// 检测关键点
    		detector.detect(src, srcKeyPoints);
    		// 根据源图像、关键点产生特征矩阵数值
    		extractor.compute(src, srcKeyPoints, srcDes);
    	}
    
    	public static void main(String[] args) {
    		System.loadLibrary("opencv_java249");
    		FeatureMatching mather = new FeatureMatching(new ConsoleView());
    		//FeatureMatching mather = new FeatureMatching(new GEivView());
    		mather.setSource("./Data/Lession5/BK.jpg");
    		mather.doMaping("./Data/Lession5/BK_part_rr.png");
    	}
    }

    MatchingView.java 该接口用来计算并输出结果

    import org.opencv.core.MatOfDMatch;
    import org.opencv.core.MatOfKeyPoint;
    
    
    public interface MatchingView {
    	public void setDstPic(String dstPath);
    	public void setSrcPic(String picPath);
    	public int showView(MatOfDMatch matches,MatOfKeyPoint srcKP,MatOfKeyPoint dstKP);
    }
    ConsoleView.java:实现了视图接口,将结果打印在控制台中 ,如果实在没有什么拿手的图形环境的话就只能看文字了。
    import java.util.LinkedList;
    import java.util.List;
    
    import org.opencv.core.MatOfDMatch;
    import org.opencv.core.MatOfKeyPoint;
    import org.opencv.features2d.DMatch;
    
    public class ConsoleView implements MatchingView{
    
    	@Override
    	public int showView(MatOfDMatch matches,MatOfKeyPoint srcKP,MatOfKeyPoint dstKP) {
    		System.out.println(matches.rows() + " Match Point(s)");
    
    		double maxDist = Double.MIN_VALUE;
    		double minDist = Double.MAX_VALUE;
    		
    		DMatch[] mats = matches.toArray();
    		for(int i = 0;i < mats.length;i++){
    			double dist = mats[i].distance;
    			if (dist < minDist) {
    				minDist = dist;
    			}
    			if (dist > maxDist) {
    				maxDist = dist;
    			}
    		}
    		System.out.println("Min Distance:" + minDist);
    		System.out.println("Max Distance:" + maxDist);
    		//将“好”的关键点记录,即距离小于3倍最小距离,同时给定一个阈值(0.2f),这样不至于在毫不相干的图像上分析,可依据实际情况调整
    		List<DMatch> goodMatch = new LinkedList<>();
    		
    		for (int i = 0; i < mats.length; i++) {
    			double dist = mats[i].distance;
    			if(dist < 3*minDist&&dist < 0.2f){
    				goodMatch.add(mats[i]);
    			}
    		}
    		System.out.println(goodMatch.size() + " GoodMatch Found");
    		int i = 0;
    		for(DMatch ma:goodMatch){
    			System.out.println("GoodMatch" + "["+i+"]:" + ma.queryIdx + " TO: " + ma.trainIdx);
    			i++;
    		}
    		return i;
    	}
    
    	@Override
    	public void setDstPic(String dstPath) {}
    
    	@Override
    	public void setSrcPic(String picPath) {}
    }
    GEivView.java:使用自己的游戏引擎绘制图形界面输出结果,如果之前有部署过GEiv系统的话可以尝试(可参照博客内相关文章)。
    import geivcore.R;
    import geivcore.UESI;
    import geivcore.engineSys.texturecontroller.TextureController;
    import geivcore.enginedata.canonical.CANExPos;
    import geivcore.enginedata.obj.Obj;
    
    import java.awt.Color;
    import java.util.LinkedList;
    import java.util.List;
    
    import org.opencv.core.MatOfDMatch;
    import org.opencv.core.MatOfKeyPoint;
    import org.opencv.core.Point;
    import org.opencv.features2d.DMatch;
    import org.opencv.features2d.KeyPoint;
    
    import com.thrblock.util.RandomSet;
    
    public class GEivView implements MatchingView{
    	UESI UES;
    	Obj srcPicObj,dstPicObj;
    	public GEivView(){
    		UES = new R();
    		
    		srcPicObj = UES.creatObj(UESI.BGIndex);
    		srcPicObj.addGLImage(0, 0,TextureController.SYSTEM_DEBUG_TEXTURE);
    		
    		dstPicObj = UES.creatObj(UESI.BGIndex);
    		dstPicObj.addGLImage(0, 0,TextureController.SYSTEM_DEBUG_TEXTURE);
    	}
    	@Override
    	public int showView(MatOfDMatch matches, MatOfKeyPoint srcKP,
    			MatOfKeyPoint dstKP) {
    		System.out.println(matches.rows() + " Match Point(s)");
    
    		double maxDist = Double.MIN_VALUE;
    		double minDist = Double.MAX_VALUE;
    		
    		DMatch[] mats = matches.toArray();
    		for(int i = 0;i < mats.length;i++){
    			double dist = mats[i].distance;
    			if (dist < minDist) {
    				minDist = dist;
    			}
    			if (dist > maxDist) {
    				maxDist = dist;
    			}
    		}
    		System.out.println("Min Distance:" + minDist);
    		System.out.println("Max Distance:" + maxDist);
    		//将“好”的关键点记录,即距离小于3倍最小距离,可依据实际情况调整
    		List<DMatch> goodMatch = new LinkedList<>();
    		
    		for (int i = 0; i < mats.length; i++) {
    			double dist = mats[i].distance;
    			if(dist < 3*minDist&&dist < 0.2f){
    				goodMatch.add(mats[i]);
    			}
    		}
    		System.out.println(goodMatch.size() + " GoodMatch Found");
    		
    		DMatch[] goodmats = goodMatch.toArray(new DMatch[]{});
    		KeyPoint[] srcKPs = srcKP.toArray();//train
    		KeyPoint[] dstKPs = dstKP.toArray();//query
    		
    		for(int i = 0;i < goodmats.length;i++){
    			Point crtD = dstKPs[goodmats[i].queryIdx].pt;
    			Point crtS = srcKPs[goodmats[i].trainIdx].pt;
    			showMap(dstPicObj.getDx() + crtD.x,dstPicObj.getDy() + crtD.y,srcPicObj.getDx() + crtS.x,srcPicObj.getDy() + crtS.y);
    			System.out.println("MAP :("+(int)crtD.x+","+(int)crtD.y+") --->("+(int)crtS.x+","+(int)crtS.y+")");
    		}
    		return goodmats.length;
    	}
    	@Override
    	public void setDstPic(String dstPath) {
    		dstPicObj.setPath(dstPath,true);
    		dstPicObj.setPosition(CANExPos.POS_X_LEFT,50.0f);
    		dstPicObj.setPosition(CANExPos.POS_Y_CENTER);
    		
    		dstPicObj.show();
    	}
    	@Override
    	public void setSrcPic(String picPath) {
    		srcPicObj.setPath(picPath,true);
    		srcPicObj.setPosition(CANExPos.POS_X_RIGHT,50.0f);
    		srcPicObj.setPosition(CANExPos.POS_Y_CENTER);
    
    		srcPicObj.show();
    	}
    	private void showMap(double x,double y,double x1,double y1){
    		Color dstColor = RandomSet.getRandomColor();
    		
    		Obj oval = UES.creatObj(UESI.UIIndex);
    		oval.addGLOval("FFFFFF",0,0,5,5,12);
    		oval.setColor(dstColor);
    		oval.setCentralX((float)x1);
    		oval.setCentralY((float)y1);
    		oval.show();
    		
    		oval = UES.creatObj(UESI.UIIndex);
    		oval.addGLOval("FFFFFF",0,0,5,5,12);
    		oval.setColor(dstColor);
    		oval.setCentralX((float)x);
    		oval.setCentralY((float)y);
    		oval.show();
    		
    		Obj line = UES.creatObj(UESI.UIIndex);
    		line.addGLLine("FFFFFF",(float)x,(float)y,(float)x1,(float)y1);
    		line.setLineWidth(2.0f);
    		line.setColor(dstColor);
    		line.setAlph(0.5f);
    		line.show();
    	}
    }

    [测试用例]

    原图还是我们之前用的“贝壳”


    匹配图,它来自原图转置后截取的一部分:


    [测试结果]

    [控制台视图]

    输出内容:

    SRC W:358 H:300
    DST W:156 H:85
    84 Match Point(s)
    Min Distance:0.06136654317378998//所谓关键点的“距离”指的是两个关键点间的匹配程度,越小越匹配
    Max Distance:0.4693795144557953
    25 GoodMatch Found//共发现25个“好”的匹配点
    GoodMatch[0]:0 TO: 6//这里的0->6意思是关键点集合中的映射关系,即KeyPoint[0]->KeyPoint[6]
    GoodMatch[1]:1 TO: 23
    GoodMatch[2]:3 TO: 30
    GoodMatch[3]:4 TO: 20
    GoodMatch[4]:5 TO: 23
    GoodMatch[5]:6 TO: 27
    GoodMatch[6]:7 TO: 19
    GoodMatch[7]:9 TO: 73
    GoodMatch[8]:10 TO: 65
    GoodMatch[9]:12 TO: 96
    GoodMatch[10]:14 TO: 38
    GoodMatch[11]:15 TO: 97
    GoodMatch[12]:19 TO: 162
    GoodMatch[13]:20 TO: 175
    GoodMatch[14]:22 TO: 164
    GoodMatch[15]:29 TO: 247
    GoodMatch[16]:31 TO: 283
    GoodMatch[17]:33 TO: 155
    GoodMatch[18]:36 TO: 261
    GoodMatch[19]:39 TO: 218
    GoodMatch[20]:45 TO: 717
    GoodMatch[21]:48 TO: 487
    GoodMatch[22]:60 TO: 150
    GoodMatch[23]:68 TO: 91
    GoodMatch[24]:77 TO: 1036

    [GEiv视图]


    ↑这样更直观一些,可以看出大部分映射关系是正确的。

    [总结]

            对图像识别领域的一些概念进行了了解,包括特征点与特征量这样的叙述手段,但问题还是很多,例如特征点的计算依据(轮廓?拐点?)等,我希望在以后的学习中找到答案。

    展开全文
  • surf特征+FLANN特征匹配+knn筛选匹配点+单应性矩阵映射(代码来源)特征提取的三大步骤:(0.图像预处理)1.特征的提取2.计算特征向量3.特征匹配(4.减少误匹配率等后处理过程)//#include "stdafx.h" #...

    surf特征+FLANN特征匹配+knn筛选匹配点+单应性矩阵映射(代码来源)

    特征提取的三大步骤:

    (0.图像预处理)

    1.特征的提取

    2.计算特征向量

    3.特征匹配

    (4.减少误匹配率等后处理过程)

    
    
    //#include "stdafx.h"
    #include <stdio.h>
    #include <iostream>
    #include <opencv2/core/core.hpp>
    #include "opencv2/nonfree/features2d.hpp"
    #include<opencv2/legacy/legacy.hpp>
    #include <opencv2/highgui/highgui.hpp>
    
    using namespace cv;
    using namespace std;
    
    int main()
    {
    	//Mat 一种数字矩阵表示数字图像
    	Mat img_1 = imread("E:/海康威视云台摄像机控制/海康威视SDK/test/图片-液晶屏幕/向上/20180108144506_ch01.bmp", CV_LOAD_IMAGE_GRAYSCALE);//创建头部并分配矩阵
    	Mat img_2 = imread("E:/海康威视云台摄像机控制/海康威视SDK/test/图片-液晶屏幕/向上/20180108144640_ch01.bmp", CV_LOAD_IMAGE_GRAYSCALE);
    
    	if (!img_1.data || !img_2.data)//judge if the two photoes are same
    	{
    		return -1;
    	}
    
    	//-- Step 1: Detect the keypoints using SURF Detector 检测关键点
    	int minHessian = 400;//其构造函数参数(minHessian)用来平衡提取到的特征点的数量和特征提取的稳定性的,对于不同的特征提取器改参数具有不同的含义和取值范围。
    
    	SurfFeatureDetector detector(minHessian);
    
    	vector<KeyPoint> keypoints_1, keypoints_2;//存放关键点的结果
    
    	detector.detect(img_1, keypoints_1);//检测img_1的关键点keypoints_1
    	detector.detect(img_2, keypoints_2);
    
    	//-- Step 2: Calculate descriptors (feature vectors)  对得到的特征点提取并计算特征向量(特征描述符)
    	SurfDescriptorExtractor extractor;//代表用Surf特征点检测,若为SiftFeatureDetector即为Sift特征点检测
    	Mat descriptors_1, descriptors_2;//描述符
    
    	extractor.compute(img_1, keypoints_1, descriptors_1);//计算img_1中点keypoints1的描述符
    	extractor.compute(img_2, keypoints_2, descriptors_2);
    
    	//-- Step 3: Matching descriptor vectors using FLANN matcher
    	FlannBasedMatcher matcher;//FLANN特征匹配法(另:BruteForce暴力匹配,但效果不好)
    	vector< DMatch > matches;//最后的匹配结果保存在vector<DMatch>中
    	vector<vector<DMatch>> m_knnMatches;
    	//vector<DescriptorMatcher> zjm1; 用来进行描述符匹配,具体用法请CDSN
    
    	matches.clear();
    	const float minRatio = 1.f / 1.5f;//minRatio一个比值
    	//使用KNN-matching算法,令K=2。则每个match得到两个最接近的descriptor,然后计算最接近距离和次接近距离之间的比值,当比值大于既定值时,才作为最终match。为了尽量消除False-positive matches的误匹配
    	// KNN match will return 2 nearest   
    	// matches for each query descriptor,此处为descriptors_1,但是一般不是点集一为训练集点集二为查询集吗?
    	matcher.knnMatch(descriptors_1, descriptors_2, m_knnMatches, 2);
    
    	for (int i = 0; i<m_knnMatches.size(); i++)
    	{
    		const DMatch& bestMatch = m_knnMatches[i][0];
    		const DMatch& betterMatch = m_knnMatches[i][1];
    
    		float distanceRatio = bestMatch.distance / betterMatch.distance;//distanceRatio另一个比值
    
    		if (distanceRatio<minRatio)
    		{
    			matches.push_back(bestMatch);
    		}
    	}
    
    	vector< DMatch > good_matches;
    
    	if (!matches.size())
    	{
    		cout << "matches is empty! " << endl;
    		return -1;
    	}
    	else if (matches.size()<4)//匹配集至少含四个点,因为单应性矩阵
    	{
    		cout << matches.size() << " points matched is not enough " << endl;
    	}
    	else //单应性矩阵的计算最少得使用4个点
    	{
    		for (int i = 0; i < matches.size(); i++)
    		{
    			good_matches.push_back(matches[i]);
    		}
    
    		Mat img_matches;
    
    		//drawMatches 参数含义:
    		//good_matches - 源图像1的特征点匹配源图像2的特征点
    		/*img_matches - 输出图像(具体由最后一个参数Flags决定)
    		第一个Scalar::all(-1) - 匹配的颜色(特征点和连线), 若matchColor == Scalar::all(-1),颜色随机
    		第二个Scalar::all(-1) - 单个点的颜色,即未配对的特征点,若matchColor == Scalar::all(-1),颜色随机
    		vector<char>() - (定义 matchesMask – Mask)决定哪些点将被画出,若为空,则画出所有匹配点
    		flags – Fdefined by DrawMatchesFlags*/
    
    		drawMatches(img_1, keypoints_1, img_2, keypoints_2,
    			good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),
    			vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
    
    
    		//☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★☆★
    		//-- Localize the object from img_1 in img_2 
    		vector<Point2f> obj;
    		vector<Point2f> scene;
    
    		for (int i = 0; i < good_matches.size(); i++)
    		{
    			//-- Get the keypoints from the good matches
    			obj.push_back(keypoints_1[good_matches[i].queryIdx].pt);
    			scene.push_back(keypoints_2[good_matches[i].trainIdx].pt);
    		}
    		Mat H = findHomography(obj, scene, CV_RANSAC);//CV_EXPORTS Mat findHomography( InputArray srcPoints, InputArray dstPoints,OutputArray mask, int method = 0, double ransacReprojThreshold = 3); mask - 随机样本一致性RANSAC方法
    
    		//-- Get the corners from the image_1 ( the object to be "detected" )
    		vector<Point2f> obj_corners(4);//应该是说定义确定单应性矩阵的四个角点,然后输入角点
    		obj_corners[0] = cvPoint(0, 0);
    		obj_corners[1] = cvPoint(img_1.cols, 0);
    		obj_corners[2] = cvPoint(img_1.cols, img_1.rows);
    		obj_corners[3] = cvPoint(0, img_1.rows);
    		vector<Point2f> scene_corners(4);
    
    		perspectiveTransform(obj_corners, scene_corners, H);//进行透射变换???透射变换是干什么的?
    
    		for (int i = 0; i < 4; i++)
    		{
    			/* 作用和perspectiveTransform一样
    			double x = obj_corners[i].x;
    			double y = obj_corners[i].y;
    			double Z = 1./( H.at<double>(2,0)*x + H.at<double>(2,1)*y + H.at<double>(2,2) );
    			double X = ( H.at<double>(0,0)*x + H.at<double>(0,1)*y + H.at<double>(0,2) )*Z;
    			double Y = ( H.at<double>(1,0)*x + H.at<double>(1,1)*y + H.at<double>(1,2) )*Z;
    			scene_corners[i] = cvPoint( cvRound(X) + img_1.cols, cvRound(Y) );*/
    			scene_corners[i].x += img_1.cols;
    		}
    		
    		line(img_matches, scene_corners[0], scene_corners[1], Scalar(0, 255, 0), 2);
    		line(img_matches, scene_corners[1], scene_corners[2], Scalar(0, 255, 0), 2);
    		line(img_matches, scene_corners[2], scene_corners[3], Scalar(0, 255, 0), 2);
    		line(img_matches, scene_corners[3], scene_corners[0], Scalar(0, 255, 0), 2);
    		imshow("Good Matches & Object detection", img_matches);
    	}
    	
    
    	waitKey(0);
    
    	return 0;
    }
    
    展开全文
  • 本文接着上篇FLANN特征匹配,从上篇可以知道,如果特征匹配时全部是用线进行匹配,那么真的让人看着很窝心。那么,可不可以把匹配到的结果用矩形或圆表示出来呢?当然可以,这就是平面对象识别。是上一章节的...
  • 前言前面我们学了《C++ OpenCV特征提取之BFMatcher匹配》BFMatcher的匹配,这一章我们看一下FLANN特征匹配FLANN 是快速最近邻搜索包(Fast_Lib...
  • surf特征+FLANN特征匹配+knn筛选匹配点+单应性矩阵映射 #include "stdafx.h" #include #include #include #include "opencv2/nonfree/features2d.hpp" #include #include using namespace cv; using namespace ...
  • OpenCv-C++-FLANN特征匹配算法

    千次阅读 2018-12-08 20:25:54
    相比于上一篇的暴力匹配算法,FLANN更加精确,不会有过多的描述特征匹配到。 匹配基本步骤: 检测-&gt;提取-&gt;计算得到描述子-&gt;特征比对 实现代码: #include&lt;opencv2/opencv.hpp&gt; #...
  • FLANN特征匹配(Python)

    千次阅读 2018-07-25 22:02:24
    输入图片 算法输出图 ...可以看到,这里的算法效果比...ORB特征匹配(python) 代码 import cv2 from matplotlib import pyplot as plt queryImage = cv2.imread('6.jpg', 0) trainingImage = cv2.imread...
  • } FLANN特征匹配 #include #include #include #include using namespace cv; using namespace std; using namespace cv::xfeatures2d; int main(int argc, char** argv) { Mat img1 = imread("D:/vcprojects/...
  • FlannBasedMatcher中FLANN的含义是Fast Library forApproximate Nearest Neighbors,从字面意思可知它是一种近似法,算法更快但是找到的是最近邻近似匹配,所以当我们需要找到一个相对好的匹配但是不需要最佳匹配的...
  • opencv3/C++ FLANN特征匹配

    千次阅读 2018-01-25 21:16:26
    FLANN特征匹配示例: #include #include using namespace cv; using namespace cv::xfeatures2d; //FLANN对高维数据较快 int main() { Mat src1,src2; src1 = imread( "E:/image/image/card2....

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 3,069
精华内容 1,227
关键字:

flann特征匹配