學習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
相關文章
- 學習Opencv2.4.9(四)---SVM支援向量機OpenCV
- 學習SVM(一) SVM模型訓練與分類的OpenCV實現模型OpenCV
- opencv中SVMOpenCV
- OpenCV 與 SVMOpenCV
- opencv SVM 使用OpenCV
- 我的OpenCV學習筆記(六):使用支援向量機(SVM)OpenCV筆記
- opencv SVM的使用OpenCV
- opencv + SVM 程式碼OpenCV
- opencv svm分類OpenCV
- OpenCV的SVM用法OpenCV
- opencv SVM分類DemoOpenCV
- opencv中svm原始碼OpenCV原始碼
- OpenCV進階---介紹SVMOpenCV
- OpenCV中使用SVM簡介OpenCV
- opencv 學習OpenCV
- OpenCV學習OpenCV
- 學習SVM(五)理解線性SVM的鬆弛因子
- 學習SVM(四) 理解SVM中的支援向量(Support Vector)
- OPENCV SVM介紹和自帶例子OpenCV
- Opencv 用SVM訓練檢測器OpenCV
- opencv中的SVM影像分類(二)OpenCV
- opencv中的SVM影像分類(一)OpenCV
- OpenCV中的SVM引數優化OpenCV優化
- 學習OpenCV:hu矩OpenCV
- 學習OpenCV:骨架提取OpenCV
- 『sklearn學習』不同的 SVM 分類器
- OpenCV筆記(3)實現支援向量機(SVM)OpenCV筆記
- opencv學習之基礎OpenCV
- opencv學習筆記(一)OpenCV筆記
- OpenCV學習之旅 簡介OpenCV
- opencv-python學習之旅OpenCVPython
- opencv學習(三)——繪圖功能OpenCV繪圖
- 使用 SVM 和決策樹進行整合學習
- opencv python 基於SVM的手寫體識別OpenCVPython
- SVM多分類器的實現(Opencv3,C++)OpenCVC++
- 學習opencv 習題答案-第五章OpenCV
- opencv學習之邊緣檢測OpenCV
- 學習OpenCV:濾鏡系列(6)——風OpenCV