学习OpenCV——SVM

学习SVM,首先通过http://zh.wikipedia.org/wiki/SVM

再通过博客http://blog.csdn.net/yang_xian521/article/details/6969904

OpenCV开发SVM算法是基于LibSVM软件包开发的,LibSVM是台湾大学林智仁(Lin Chih-Jen)等开发设计的一个简单、易于使用和快速有效的SVM模式识别与回归的软件包。用OpenCV使用SVM算法的大概流程是

1)设置训练样本集

需要两组数据,一组是数据的类别,一组是数据的向量信息。

2)设置SVM参数

利用CvSVMParams类实现类内的成员变量svm_type表示SVM类型:

CvSVM::C_SVC  C-SVC

CvSVM::NU_SVC v-SVC

CvSVM::ONE_CLASS 一类SVM

CvSVM::EPS_SVR e-SVR

CvSVM::NU_SVR v-SVR

成员变量kernel_type表示核函数的类型:

CvSVM::LINEAR 线性:u‘v

CvSVM::POLY 多项式:(r*u'v + coef0)^degree

CvSVM::RBF RBF函数:exp(-r|u-v|^2)

CvSVM::SIGMOID sigmoid函数:tanh(r*u'v + coef0)

成员变量degree针对多项式核函数degree的设置,gamma针对多项式/rbf/sigmoid核函数的设置,coef0针对多项式/sigmoid核函数的设置,Cvalue为损失函数,在C-SVC、e-SVR、v-SVR中有效,nu设置v-SVC、一类SVM和v-SVR参数,p为设置e-SVR中损失函数的值,class_weightsC_SVC的权重,term_crit为SVM训练过程的终止条件。其中默认值degree = 0,gamma = 1,coef0 = 0,Cvalue = 1,nu = 0,p = 0,class_weights = 0

3)训练SVM

调用CvSVM::train函数建立SVM模型,第一个参数为训练数据,第二个参数为分类结果,最后一个参数即CvSVMParams

4)用这个SVM进行分类

调用函数CvSVM::predict实现分类

5)获得支持向量

除了分类,也可以得到SVM的支持向量,调用函数CvSVM::get_support_vector_count获得支持向量的个数,CvSVM::get_support_vector获得对应的索引编号的支持向量。

实现代码如下:运行步骤

	// step 1:
	float labels[4] = {1.0, -1.0, -1.0, -1.0};
	Mat labelsMat(3, 1, CV_32FC1, labels);
	
	float trainingData[4][2] = { {501, 10}, {255, 10}, {501, 255}, {10, 501} };
	Mat trainingDataMat(3, 2, CV_32FC1, trainingData);

	// step 2:
	CvSVMParams params;
	params.svm_type = CvSVM::C_SVC;
	params.kernel_type = CvSVM::LINEAR;
	params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 100, 1e-6);
	
	// step 3:
	CvSVM SVM;
	SVM.train(trainingDataMat, labelsMat, Mat(), Mat(), params);
	
	// step 4:
	Vec3b green(0, 255, 0), blue(255, 0, 0);
	for (int i=0; i<image.rows; i++)
	{
		for (int j=0; j<image.cols; j++)
		{
			Mat sampleMat = (Mat_<float>(1,2) << i,j);
			float response = SVM.predict(sampleMat);

			if (fabs(response-1.0) < 0.0001)
			{
				image.at<Vec3b>(j, i) = green;
			}
			else if (fabs(response+1.0) < 0.001)
			{
				image.at<Vec3b>(j, i) = blue;
			}
		}
	}

	// step 5:
	int c = SVM.get_support_vector_count();

	for (int i=0; i<c; i++)
	{
		const float* v = SVM.get_support_vector(i);
	}

实验代码1:颜色分类

//利用SVM解决2维空间向量的3级分类问题    
#include "stdafx.h"    
#include "cv.h"    
#include "highgui.h"        
#include <ML.H>    
#include <TIME.H>    
   
#include <CTYPE.H>    
  
#include <IOSTREAM>    
using namespace std;   
int main(int argc, char **argv)   
{   
  int size = 400;         //图像的长度和宽度    
     const int s = 1000;          //试验点个数(可更改!!)    
     int i, j, sv_num;   
     IplImage *img;   
     CvSVM svm = CvSVM();    //★★★    
     CvSVMParams param;   
     CvTermCriteria criteria;//停止迭代的标准    
     CvRNG rng = cvRNG(time(NULL));   
     CvPoint pts[s];         //定义1000个点    
     float data[s*2];        //点的坐标    
     int res[s];             //点的所属类    
     CvMat data_mat, res_mat;   
     CvScalar rcolor;   
     const float *support;   
  // (1)图像区域的确保和初始化    
     img= cvCreateImage(cvSize(size, size), IPL_DEPTH_8U, 3);   
     cvZero(img);   
     //确保画像区域,并清0(用黑色作初始化处理)。    
    
     // (2)学习数据的生成    
     for (i= 0; i< s; i++) {   
         pts[i].x= cvRandInt(&rng) % size;   //用随机整数赋值    
         pts[i].y= cvRandInt(&rng) % size;   
         if (pts[i].y> 50 * cos(pts[i].x* CV_PI/ 100) + 200) {   
             cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(255, 0, 0));   
    cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(255, 0, 0));   
             res[i] = 1;   
         }   
         else {   
             if (pts[i].x> 200) {   
                 cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(0, 255, 0));   
                 cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(0, 255, 0));   
                 res[i] = 2;   
             }   
             else {   
                 cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), CV_RGB(0, 0, 255));   
                 cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), CV_RGB(0, 0, 255));   
                 res[i] = 3;   
             }   
         }   
     }   
     //生成2维随机训练数据,并将其值放在CvPoint数据类型的数组pts[ ]中。    
    
     // (3)学习数据的显示    
     cvNamedWindow("SVM", CV_WINDOW_AUTOSIZE);   
     cvShowImage("SVM", img);   
     cvWaitKey(0);   
    
     // (4)学习参数的生成    
     for (i= 0; i< s; i++) {   
         data[i* 2] = float (pts[i].x) / size;   
         data[i* 2 + 1] = float (pts[i].y) / size;   
     }   
     cvInitMatHeader(&data_mat, s, 2, CV_32FC1, data);   
     cvInitMatHeader(&res_mat, s, 1, CV_32SC1, res);   
     criteria= cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);   
     param= CvSVMParams (CvSVM::C_SVC, CvSVM::RBF, 10.0, 8.0, 1.0, 10.0, 0.5, 0.1, NULL, criteria);   
     /*  
         SVM种类:CvSVM::C_SVC  
         Kernel的种类:CvSVM::RBF  
         degree:10.0(此次不使用)  
         gamma:8.0  
         coef0:1.0(此次不使用)  
         C:10.0  
         nu:0.5(此次不使用)  
         p:0.1(此次不使用)  
   然后对训练数据正规化处理,并放在CvMat型的数组里。  
                                                             */   
    
    
     //☆☆☆☆☆☆☆☆☆(5)SVM学习☆☆☆☆☆☆☆☆☆☆☆☆    
     svm.train(&data_mat, &res_mat, NULL, NULL, param);//☆    
     //☆☆利用训练数据和确定的学习参数,进行SVM学习☆☆☆☆        
    
     // (6)学习结果的绘图    
     for (i= 0; i< size; i++) {   
         for (j= 0; j< size; j++) {   
             CvMat m;   
             float ret = 0.0;   
             float a[] = { float (j) / size, float (i) / size };   
             cvInitMatHeader(&m, 1, 2, CV_32FC1, a);   
             ret= svm.predict(&m);   
             switch ((int) ret) {   
                 case 1:   
                     rcolor= CV_RGB(100, 0, 0);   
                     break;   
                 case 2:   
                     rcolor= CV_RGB(0, 100, 0);   
                     break;   
                 case 3:   
                     rcolor= CV_RGB(0, 0, 100);   
                     break;   
             }   
             cvSet2D(img, i, j, rcolor);   
         }   
     }   
     //为了显示学习结果,通过输入图像区域的所有像素(特征向量)并进行分类。然后对输入像素用所属等级的颜色绘图。    
    
     // (7)训练数据的再绘制    
     for (i= 0; i< s; i++) {   
         CvScalar rcolor;   
         switch (res[i]) {   
             case 1:   
                 rcolor= CV_RGB(255, 0, 0);   
                 break;   
             case 2:   
                 rcolor= CV_RGB(0, 255, 0);   
                 break;   
             case 3:   
                 rcolor= CV_RGB(0, 0, 255);   
                 break;   
         }   
         cvLine(img, cvPoint(pts[i].x- 2, pts[i].y- 2), cvPoint(pts[i].x+ 2, pts[i].y+ 2), rcolor);   
         cvLine(img, cvPoint(pts[i].x+ 2, pts[i].y- 2), cvPoint(pts[i].x- 2, pts[i].y+ 2), rcolor);   
     }   
     //将训练数据在结果图像上重复的绘制出来。    
    
     // (8)支持向量的绘制    
     sv_num= svm.get_support_vector_count();   
     for (i= 0; i< sv_num; i++) {   
         support = svm.get_support_vector(i);   
         cvCircle(img, cvPoint((int) (support[0] * size), (int) (support[1] * size)), 5, CV_RGB(200, 200, 200));   
     }   
     //用白色的圆圈对支持向量作标记。    
    
     // (9)图像的显示     
     cvNamedWindow("SVM", CV_WINDOW_AUTOSIZE);   
     cvShowImage("SVM", img);   
     cvWaitKey(0);   
     cvDestroyWindow("SVM");   
     cvReleaseImage(&img);   
     return 0;   
     //显示实际处理结果的图像,直到某个键被按下为止。    
 } 

实验代码2:用MIT人脸库检测,效果实在不好,检测结果全是人脸或者全都不是人脸。原因应该是图像检测没有做好应该用HoG等特征首先检测,在进行分类训练,不特征不明显,肯定分类效果并不好。

//
// File Name: pjSVM.cpp
// Author:   easyfov(easyfov@gmail.com)
// Company: Lida Optical and Electronic Co.,Ltd.
//http://apps.hi.baidu.com/share/detail/32719017
//

#include <cv.h>
#include <highgui.h>
#include <ml.h>

#include <iostream>
#include <fstream>
#include <string>
#include <vector>
using namespace std;

#define WIDTH 20
#define HEIGHT 20

int main( /*int argc, char** argv*/ )
{
	vector<string> img_path;
	vector<int> img_catg;
	int nLine = 0;
	string buf;
	ifstream svm_data( "E:/SVM_DATA.txt" );

	while( svm_data )
	{
		if( getline( svm_data, buf ) )
		{
			nLine ++;
			if( nLine % 2 == 0 )
			{
				 img_catg.push_back( atoi( buf.c_str() ) );//atoi将字符串转换成整型,标志(0,1)
			}
			else
			{
				img_path.push_back( buf );//图像路径
			}
		}
	}
	svm_data.close();//关闭文件

	CvMat *data_mat, *res_mat;
	int nImgNum = nLine / 2;			//读入样本数量
	样本矩阵,nImgNum:横坐标是样本数量, WIDTH * HEIGHT:样本特征向量,即图像大小
	data_mat = cvCreateMat( nImgNum, WIDTH * HEIGHT, CV_32FC1 );
	cvSetZero( data_mat );
	//类型矩阵,存储每个样本的类型标志
	res_mat = cvCreateMat( nImgNum, 1, CV_32FC1 );
	cvSetZero( res_mat );

	IplImage *srcImg, *sampleImg;
	float b;
	DWORD n;

	for( string::size_type i = 0; i != img_path.size(); i++ )
	{
	   srcImg = cvLoadImage( img_path[i].c_str(), CV_LOAD_IMAGE_GRAYSCALE );
	   if( srcImg == NULL )
	   {
			cout<<" can not load the image: "<<img_path[i].c_str()<<endl;
			continue;
	   }

	   cout<<" processing "<<img_path[i].c_str()<<endl;

	   sampleImg = cvCreateImage( cvSize( WIDTH, HEIGHT ), IPL_DEPTH_8U, 1 );//样本大小(WIDTH, HEIGHT)
	   cvResize( srcImg, sampleImg );//改变图像大小

	   cvSmooth( sampleImg, sampleImg );	//降噪
	   //生成训练数据
	   n = 0;
		for( int ii = 0; ii < sampleImg->height; ii++ )
		{
			for( int jj = 0; jj < sampleImg->width; jj++, n++ )
			{
				 b = (float)((int)((uchar)( sampleImg->imageData + sampleImg->widthStep * ii + jj )) / 255.0 );
				 cvmSet( data_mat, (int)i, n, b );
			}
	    }
		cvmSet( res_mat, i, 0, img_catg[i] );
	    cout<<" end processing "<<img_path[i].c_str()<<" "<<img_catg[i]<<endl;
	}


	CvSVM svm = CvSVM();
	CvSVMParams param;
	CvTermCriteria criteria;
	criteria = cvTermCriteria( CV_TERMCRIT_EPS, 1000, FLT_EPSILON );
	param = CvSVMParams( CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.09, 1.0, 10.0, 0.5, 1.0, NULL, criteria );
	 /*  
	        SVM种类:CvSVM::C_SVC  
	        Kernel的种类:CvSVM::RBF  
	        degree:10.0(此次不使用)  
	        gamma:8.0  
	        coef0:1.0(此次不使用)  
	        C:10.0  
	        nu:0.5(此次不使用)  
	        p:0.1(此次不使用)  
			然后对训练数据正规化处理,并放在CvMat型的数组里。  
	                                                            */   
	//☆☆☆☆☆☆☆☆☆(5)SVM学习☆☆☆☆☆☆☆☆☆☆☆☆    
	svm.train( data_mat, res_mat, NULL, NULL, param );
	//☆☆利用训练数据和确定的学习参数,进行SVM学习☆☆☆☆
	svm.save( "SVM_DATA.xml" );


	//检测样本
	IplImage *tst, *tst_tmp;
	vector<string> img_tst_path;
	ifstream img_tst( "E:/SVM_TEST.txt" );
	while( img_tst )
	{
		if( getline( img_tst, buf ) )
		{
			img_tst_path.push_back( buf );
	    }
	}
	img_tst.close();

	CvMat *tst_mat = cvCreateMat( 1, WIDTH*HEIGHT, CV_32FC1 );
	char line[512];
	ofstream predict_txt( "SVM_PREDICT.txt" );
	for( string::size_type j = 0; j != img_tst_path.size(); j++ )
	{
		tst = cvLoadImage( img_tst_path[j].c_str(), CV_LOAD_IMAGE_GRAYSCALE );
		if( tst == NULL )
		{
			 cout<<" can not load the image: "<<img_tst_path[j].c_str()<<endl;
			   continue;
   }
   tst_tmp = cvCreateImage( cvSize( WIDTH, HEIGHT ), IPL_DEPTH_8U, 1 );
   cvResize( tst, tst_tmp );
   cvSmooth( tst_tmp, tst_tmp );
   n = 0;
   for(int ii = 0; ii < tst_tmp->height; ii++ )
   {
	 for(int jj = 0; jj < tst_tmp->width; jj++, n++ )
	 {
		 b = (float)(((int)((uchar)tst_tmp->imageData+tst_tmp->widthStep*ii+jj))/255.0);
		 cvmSet( tst_mat, 0, n, (double)b );
	 }
   }

   int ret = svm.predict( tst_mat );
   sprintf( line, "%s %d\r\n", img_tst_path[j].c_str(), ret );
   predict_txt<<line;
}
predict_txt.close();

cvReleaseImage( &srcImg );
cvReleaseImage( &sampleImg );
cvReleaseImage( &tst );
cvReleaseImage( &tst_tmp );
cvReleaseMat( &data_mat );
cvReleaseMat( &res_mat );

return 0;
}


其中

G:/program/pjSVM/face/1.png
0
G:/program/pjSVM/face/2.png
0
G:/program/pjSVM/face/3.png
0
G:/program/pjSVM/face/4.png
0
G:/program/pjSVM/face/5.png
0
G:/program/pjSVM/face/6.png
0
G:/program/pjSVM/face/7.png
0
G:/program/pjSVM/face/8.png
0
G:/program/pjSVM/face/9.png
0
G:/program/pjSVM/face/10.png
0
G:/program/pjSVM/face/11.png
0
G:/program/pjSVM/face/12.png
0
G:/program/pjSVM/face/13.png
0
G:/program/pjSVM/face/14.png
0
G:/program/pjSVM/face/15.png
1
G:/program/pjSVM/face/16.png
1
G:/program/pjSVM/face/17.png
1
G:/program/pjSVM/face/18.png
1
G:/program/pjSVM/face/19.png
1
G:/program/pjSVM/face/20.png
1
G:/program/pjSVM/face/21.png
1
G:/program/pjSVM/face/22.png
1
G:/program/pjSVM/face/23.png
1
G:/program/pjSVM/face/24.png
1
G:/program/pjSVM/face/25.png
1
G:/program/pjSVM/face/26.png
1
G:/program/pjSVM/face/27.png
1
G:/program/pjSVM/face/28.png
1
G:/program/pjSVM/face/29.png
1
G:/program/pjSVM/face/30.png

1

SVM_TEST.txt中内容如下:

G:/program/pjSVM/try_face/5.png
G:/program/pjSVM/try_face/9.png
G:/program/pjSVM/try_face/11.png
G:/program/pjSVM/try_face/15.png
G:/program/pjSVM/try_face/2.png
G:/program/pjSVM/try_face/30.png
G:/program/pjSVM/try_face/17.png
G:/program/pjSVM/try_face/21.png
G:/program/pjSVM/try_face/24.png
G:/program/pjSVM/try_face/27.png

PS:txt操作简单方式:http://blog.csdn.net/lytwell/article/details/6029503


 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值