学习OpenCV——BOW特征提取函数(特征点篇)

from:  http://www.xuebuyuan.com/582331.html

简单的通过特征点分类的方法:                                                                      

一、train

1.提取+/- sample的feature,每幅图提取出的sift特征个数不定(假设每个feature有128维)

2.利用聚类方法(e.g K-means)将不定数量的feature聚类为固定数量的(比如10个)words即BOW(bag of word)

(本篇文章主要完成以上的工作!)

3.normalize,并作这10个类的直方图e.g [0.1,0.2,0.7,0...0];

4.将each image的这10个word作为feature_instance 和 (手工标记的) label(+/-)进入SVM训练

二、predict

1. 提取test_img的feature(如137个)

2. 分别求each feature与10个类的距离(e.g. 128维欧氏距离),确定该feature属于哪个类

3. normalize,并作这10个类的直方图e.g [0,0.2,0.2,0.6,0...0];

4. 应用SVM_predict进行结果预测

通过OpenCV实现feature聚类 BOW

首先在此介绍一下OpenCV的特征描述符与BOW的通用函数。

主要的通用接口有:

 

1.特征点提取

Ptr<FeatureDetector> FeatureDetector::create(const string& detectorType)

	Ptr<FeatureDetector> FeatureDetector::create(const string& detectorType)
// 	"FAST" – FastFeatureDetector
// 	"STAR" – StarFeatureDetector
// 	"SIFT" – SIFT (nonfree module)//必须使用 initModule_nonfree()初始化
// 	"SURF" – SURF (nonfree module)//同上;
// 	"ORB" – ORB
// 	"MSER" – MSER
// 	"GFTT" – GoodFeaturesToTrackDetector
// 	"HARRIS" – GoodFeaturesToTrackDetector with Harris detector enabled
// 	"Dense" – DenseFeatureDetector
// 	"SimpleBlob" – SimpleBlobDetector 

根据以上接口,测试不同的特征点:

对同一幅图像进行水平翻转前后的两幅图像检测特征点检测结果,

检测到的特征点的坐标类型为:pt: int / float(与keyPoint的性质有关)

数量分别为num1, num2,

"FAST" – FastFeatureDetector           pt:int (num1:615  num2:618)
 "STAR" – StarFeatureDetector           pt:int (num1:43   num2:42 )
 "SIFT" – SIFT (nonfree module)          pt:float(num1:155  num2:135)            //必须使用 initModule_nonfree()初始化
 "SURF" – SURF (nonfree module)     pt:float(num1:344  num2:342)           
//同上; 
 "ORB" – ORB                                        pt:float(num1:496  num2:497)
 "MSER" – MSER                                 pt:float(num1:51   num2:45 )
 "GFTT" – GoodFeaturesToTrackDetector        pt:int (num1:744  num2:771)
 "HARRIS" – GoodFeaturesToTrackDetector with Harris detector enabled         pt:float(num1:162  num2:160)
 "Dense" – DenseFeatureDetector          pt:int (num1:3350 num2:3350)

2.特征描述符提取

Ptr<DescriptorExtractor> DescriptorExtractor::create(const string& descriptorExtractorType)

//  Ptr<DescriptorExtractor> DescriptorExtractor::create(const string& descriptorExtractorType)
// 	"SIFT" – SIFT
// 	"SURF" – SURF
// 	"ORB" – ORB
// 	"BRIEF" – BriefDescriptorExtractor

3.描述符匹配

Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create(const string& descriptorMatcherType)

// 	descriptorMatcherType – Descriptor matcher type.
//	Now the following matcher types are supported:
// 		BruteForce (it uses L2 )
// 		BruteForce-L1
// 		BruteForce-Hamming
// 		BruteForce-Hamming(2)
// 		FlannBased
	Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( "BruteForce" );

4.class BOWTrainer

class BOWKmeansTrainer::public BOWTrainer:Kmeans算法训练

BOWKMeansTrainer ::BOWKmeansTrainer(int clusterCount, const TermCriteria& termcrit=TermCriteria(), int attempts=3, int flags=KMEANS_PP_CENTERS)

parameter same as Kmeans

代码实现:                                                                                                                    

1.画特征点。

2.特征点Kmeans聚类,每一种颜色代表一个类别。

#include "opencv2/highgui/highgui.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/nonfree/nonfree.hpp"

#include <iostream>

using namespace cv;
using namespace std;

#define ClusterNum 10

void DrawAndMatchKeypoints(const Mat& Img1,const Mat& Img2,const vector<KeyPoint>& Keypoints1,
	const vector<KeyPoint>& Keypoints2,const Mat& Descriptors1,const Mat& Descriptors2)
{
	Mat keyP1,keyP2;
	drawKeypoints(Img1,Keypoints1,keyP1,Scalar::all(-1),0);
	drawKeypoints(Img2,Keypoints2,keyP2,Scalar::all(-1),0);
	putText(keyP1, "drawKeyPoints", cvPoint(10,30), FONT_HERSHEY_SIMPLEX, 1 ,Scalar :: all(-1));
	putText(keyP2, "drawKeyPoints", cvPoint(10,30), FONT_HERSHEY_SIMPLEX, 1 ,Scalar :: all(-1));
	imshow("img1 keyPoints",keyP1);
	imshow("img2 keyPoints",keyP2);

	Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( "BruteForce" );
	vector<DMatch> matches;
	descriptorMatcher->match( Descriptors1, Descriptors2, matches );
	Mat show;
	drawMatches(Img1,Keypoints1,Img2,Keypoints2,matches,show,Scalar::all(-1),CV_RGB(255,255,255),Mat(),4);
	putText(show, "drawMatchKeyPoints", cvPoint(10,30), FONT_HERSHEY_SIMPLEX, 1 ,Scalar :: all(-1));
	imshow("match",show);
}

//测试OpenCV:class BOWTrainer
void BOWKeams(const Mat& img, const vector<KeyPoint>& Keypoints,
	const Mat& Descriptors, Mat& centers)
{
	//BOW的kmeans算法聚类;
	BOWKMeansTrainer bowK(ClusterNum,
		cvTermCriteria (CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1),3,2);
	centers = bowK.cluster(Descriptors);
	cout<<endl<<"< cluster num: "<<centers.rows<<" >"<<endl;

	Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( "BruteForce" );
	vector<DMatch> matches;
	descriptorMatcher->match(Descriptors,centers,matches);//const Mat& queryDescriptors, const Mat& trainDescriptors第一个参数是待分类节点,第二个参数是聚类中心;
	Mat demoCluster;
	img.copyTo(demoCluster);

	//为每一类keyPoint定义一种颜色
	Scalar color[]={CV_RGB(255,255,255),
     CV_RGB(255,0,0),CV_RGB(0,255,0),CV_RGB(0,0,255),
     CV_RGB(255,255,0),CV_RGB(255,0,255),CV_RGB(0,255,255),
     CV_RGB(123,123,0),CV_RGB(0,123,123),CV_RGB(123,0,123)};

	for (vector<DMatch>::iterator iter=matches.begin();iter!=matches.end();iter++)
	{
		cout<<"< descriptorsIdx:"<<iter->queryIdx<<"  centersIdx:"<<iter->trainIdx
			<<" distincs:"<<iter->distance<<" >"<<endl;
		Point center= Keypoints[iter->queryIdx].pt;
		circle(demoCluster,center,2,color[iter->trainIdx],-1);
	}
	putText(demoCluster, "KeyPoints Clustering: 一种颜色代表一种类型",
		cvPoint(10,30), FONT_HERSHEY_SIMPLEX, 1 ,Scalar :: all(-1));
	imshow("KeyPoints Clusrtering",demoCluster);

}

int main()
{
	cv::initModule_nonfree();//使用SIFT/SURF create之前,必须先initModule_<modulename>(); 

	cout << "< Creating detector, descriptor extractor and descriptor matcher ...";
	Ptr<FeatureDetector> detector = FeatureDetector::create( "SIFT" );

	Ptr<DescriptorExtractor> descriptorExtractor = DescriptorExtractor::create( "SIFT" );

	Ptr<DescriptorMatcher> descriptorMatcher = DescriptorMatcher::create( "BruteForce" );

	cout << ">" << endl;

	if( detector.empty() || descriptorExtractor.empty() )
	{
		cout << "Can not create detector or descriptor exstractor or descriptor matcher of given types" << endl;
		return -1;
	}
	cout << endl << "< Reading images..." << endl;
	Mat img1 = imread("D:/demo0.jpg");
	Mat img2 = imread("D:/demo1.jpg");
	cout<<endl<<">"<<endl;

	//detect keypoints;
	cout << endl << "< Extracting keypoints from images..." << endl;
	vector<KeyPoint> keypoints1,keypoints2;
	detector->detect( img1, keypoints1 );
	detector->detect( img2, keypoints2 );
	cout <<"img1:"<< keypoints1.size() << " points  img2:" <<keypoints2.size()
		<< " points" << endl << ">" << endl;

	//compute descriptors for keypoints;
	cout << "< Computing descriptors for keypoints from images..." << endl;
	Mat descriptors1,descriptors2;
	descriptorExtractor->compute( img1, keypoints1, descriptors1 );
	descriptorExtractor->compute( img2, keypoints2, descriptors2 );

	cout<<endl<<"< Descriptoers Size: "<<descriptors2.size()<<" >"<<endl;
	cout<<endl<<"descriptor‘s col: "<<descriptors2.cols<<endl
		<<"descriptor‘s row: "<<descriptors2.rows<<endl;
	cout << ">" << endl;

	//Draw And Match img1,img2 keypoints
	//匹配的过程是对特征点的descriptors进行match;
	DrawAndMatchKeypoints(img1,img2,keypoints1,keypoints2,descriptors1,descriptors2);

	Mat center;
	//对img1提取特征点,并聚类
	//测试OpenCV:class BOWTrainer
	BOWKeams(img1,keypoints1,descriptors1,center);

	waitKey();

}

通过Qt实现DrawKeypoints:

void Qt_test1::on_DrawKeypoints_clicked()
{
	//initModule_nonfree();
	Ptr<FeatureDetector> detector = FeatureDetector::create( "FAST" );
	vector<KeyPoint> keypoints;
	detector->detect( src, keypoints );

	Mat DrawKeyP;
	drawKeypoints(src,keypoints,DrawKeyP,Scalar::all(-1),0);
	putText(DrawKeyP, "drawKeyPoints", cvPoint(10,30),
		FONT_HERSHEY_SIMPLEX, 0.5 ,Scalar :: all(255));
	cvtColor(DrawKeyP, image, CV_RGB2RGBA);
	QImage img = QImage((const unsigned char*)(image.data),
		image.cols, image.rows, QImage::Format_RGB32);
	QLabel *label = new QLabel(this);
	label->move(50, 50);//图像在窗口中所处的位置;
	label->setPixmap(QPixmap::fromImage(img));
	label->resize(label->pixmap()->size());
	label->show();
}

由于initModule_nonfree()总是出错,无法对SIFT与SURF特征点提取,

而且无法实现聚类因为运行/BOW的kmeans算法聚类:BOWKMeansTrainer bowK(ClusterNum, cvTermCriteria (CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 10, 0.1),3,2);总是出错,不知道咋解决~~~~~(>_<)~~~~ 需要继续学习

时间: 2024-10-06 18:05:29

学习OpenCV——BOW特征提取函数(特征点篇)的相关文章

学习OpenCV——粒子滤波(网上两篇文章总结)

粒子滤波的理论实在是太美妙了,用一组不同权重的随机状态来逼近复杂的概率密度函数.其再非线性.非高斯系统中具有优良的特性.opencv给出了一个实现,但是没有给出范例,学习过程中发现网络上也找不到.learning opencv一书中有介绍,但距离直接使用还是有些距离.在经过一番坎坷后,终于可以用了,希望对你有帮助. 本文中给出的例子跟 我的另一篇博文是同一个应用例子,都是对二维坐标进行平滑.预测 使用方法: 1.创建并初始化 const int stateNum=4;//状态数 const in

《学习opencv》笔记——关于一些绘图的函数

绘图函数 (1)直线cvLine函数 其结构 void cvLine(//画直线 CvArr* array,//画布图像 CvPoint pt1,//起始点 CvPoint pt2,//终点 CvScalar color,//颜色 int thickness = 1,//宽度 int connectivity = 8//反走样 ); 实例代码 #include <cv.h> #include <highgui.h> #include <stdio.h> int main

【从零学习openCV】IOS7人脸识别实战

前言 接着上篇<IOS7下的人脸检測>,我们顺藤摸瓜的学习怎样在IOS7下用openCV的进行人脸识别,实际上非常easy,因为人脸检測部分已经完毕,剩下的无非调用openCV的方法对採集到的人脸样本进行训练,终于得到一个能够预測人脸的模型.可是当中的原理可谓是博大精深,因为快临最近末考试了,没时间去琢磨当中详细的细节,这次就先写个大概的demo,下次更新文章就得到6月20号之后了. 原理: 从OpenCV2.4之后,openCV增加了新的类FaceRecognizer,我们能够使用它便捷地进

【OpenCV入门教程之十七】OpenCV重映射 &amp; SURF特征点检测合辑

本系列文章由@浅墨_毛星云 出品,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/30974513 作者:毛星云(浅墨)    微博:http://weibo.com/u/1723155442 知乎:http://www.zhihu.com/people/mao-xing-yun 邮箱: [email protected] 写作当前博文时配套使用的OpenCV版本: 2.4.9 本篇文章中,我们一起探讨了OpenCV中

【从零学习openCV】IOS7根据人脸检测

前言: 人脸检測与识别一直是计算机视觉领域一大热门研究方向,并且也从安全监控等工业级的应用扩展到了手机移动端的app.总之随着人脸识别技术获得突破,其应用前景和市场价值都是不可估量的,眼下在学习openCV,自然不能放过这个领域.于是略微了解了下openCV下人脸检測的一些原理.为之后的人脸识别等研究做个小小的铺垫. 原理: 人脸检測属于目标检測(object detection) 的一部分,主要涉及两个方面 先对要检測的目标对象进行概率统计,从而知道待检測对象的一些特征,建立起目标检測模型.

【OpenCV入门指南】第十三篇 人脸检测

[OpenCV入门指南]第十三篇 人脸检测 本篇介绍图像处理与模式识别中最热门的一个领域--人脸检测(人脸识别).人脸检测可以说是学术界的宠儿,在不少EI,SCI高级别论文都能看到它的身影.甚至很多高校学生的毕业设计都会涉及到人脸检测.当然人脸检测的巨大实用价值也让很多公司纷纷关注,很多公司都拥有这方面的专利或是开发商业产品出售. 在OpenCV中,人脸检测也是其热门应用之一.在OpenCV的特征检测专题就详细介绍了人脸检测的原理--通过Haar特征来识别是否为人脸.Haar特征检测原理与Haa

【OpenCV入门指南】第七篇 线段检测与圆检测

[OpenCV入门指南]第七篇 线段检测与圆检测 在<[OpenCV入门指南]第五篇轮廓检测上>与<[OpenCV入门指南]第六篇轮廓检测下>讲解了OpenCV的轮廓检测.本篇将讲解在OpenCV中使用线段检测与圆检测. 线段检测与圆检测主要运用Hough变换,Hough变换是一种利用图像的全局特征将特定形状的边缘连接起来,形成连续平滑边缘的一种方法.它通过将源图像上的点影射到用于累加的参数空间,实现对已知解析式曲线进行识别. 在OpenCV编程中,线段检测和圆检测已经封装成函数了

OpenCV之cv2函数 2

1.主要函数 1. cv2.imread():读入图片,共两个参数,第一个参数为要读入的图片文件名,第二个参数为如何读取图片,包括 cv2.IMREAD_COLOR:读入一副彩色图片:cv2.IMREAD_GRAYSCALE:以灰度模式读入图片:cv2.IMREAD_UNCHANGED:读入一幅图片,并包括其alpha通道. PS:调用opencv,就算图像的路径是错的,OpenCV 也不会提醒你的,但是当你使用命 令print(img)时得到的结果是None. 2.cv2.imshow():创

C++学习笔记--从虚函数说开去

虚函数与纯虚函数: 虚函数:在某基类中声明为virtual并在一个或多个派生类中被重新定义的成员函数,virtual  函数返回类型  函数名(参数表){函数体;} ,实现多态性,通过指向派生类的基类指针或引用,访问派生类中同名覆盖成员函数.注意虚函数在基类中是有定义的,即便定义是空. 纯虚函数:在基类中是没有定义的,必须由派生类重定义实现,否则不能由对象进行调用. 看下面的例子: #include<iostream> using namespace std; class Cshape { p