SVM实现分类识别及参数调优(一)
前言
项目有一个模块需要将不同类别的图片进行分类,共有三个类别,使用SVM实现分类。
实现步骤:
1.创建训练样本库;
2.训练、测试SVM模型;
3.SVM的数据要求;
实现系统:
windows_x64、opencv2.4.10、 VS2013
实现过程:
1.创建训练样本库;
1)将图片以包含类别的名称进行命名,比如0(1).jpg等等;
2)将所有已命名正确的训练样本保存在同一个文件夹中;
3)在训练样本库的文件夹目录下创建python源文件;
python代码:
- import sys
- import os
- import string
- import re
- if __name__=='__main__':
- print('Begin generate path and label.')
- path_file=open('train_path.txt','w')
- path='E:/carriage_recognition/redplate_detection/svm_train_test/data/train/model'
- pic_type='.png'
- pat=re.compile(r'^(\d+)')
- files=os.listdir(path)
- files_tmp=[]
- for i in files:
- if pic_type in i and not os.path.isdir(path+'/'+i):
- files_tmp.append(i)
- files=files_tmp
- for file in range(len(files)):
- ret=pat.match(files[file])
- path_file.write(path+'/'+files[file]+'\n')
- if file<len(files)-1:
- path_file.write(ret.group(1)+'\n')
- else:
- path_file.write(ret.group(1))
- path_file.close()
- print('finish......')
4)运行代码,即可,生成包含图片名称和类别的文本文件,用于SVM训练过程中读物图片获取相应的类别标签;
- E:/carriage_recognition/redplate_detection/svm_train_test/data/train/model/0 (1).png
- 0
- E:/carriage_recognition/redplate_detection/svm_train_test/data/train/model/0 (10).png
- 0
奇数行表示训练样本图片的路径名称;偶数行表示该图片的类别标签;
2.训练、测试SVM模型;
1)image.h,主要实现过程的代码;
- #include <fstream>
- #include <vector>
- #include<direct.h>
- #include <opencv2\core\core.hpp> //红牌事件检测头文件
- #include <opencv2\opencv.hpp>
- using namespace std;
- using namespace cv;
- #define ON_STUDY 0
- #define Num 3 //类别数目
- #define STANDARD_ROW 65
- #define STANDARD_COL 85
- #define STANDARD_ROW_CHOOSE 65
- #define STANDARD_COL_CHOOSE 85
- #define CHANELS 1
- class NumTrainData
- {
- public:
- NumTrainData()
- {
- memset(data, 0, sizeof(data));
- result = -1;
- }
- public:
- float data[CHANELS*STANDARD_COL_CHOOSE*STANDARD_ROW_CHOOSE];
- int result;
- };
- vector<string> img_path;//输入文件名变量
- vector<string> img_test_path;//输入文件名变量
- vector<int> img_catg;
- vector<int> img_test_catg;
- int nLine = 0;
- string buf;
- unsigned long n;
- vector<NumTrainData> buffer;
- int featureLen = CHANELS*STANDARD_COL_CHOOSE*STANDARD_ROW_CHOOSE;
- char* test_path = "./test_path.txt";
- char* train_path = "./train_path.txt";
- //存放输出结果
- char* save_path = "./SVM_DATA_train_0.5_0.2.xml";
- ofstream matrix_config("./fusion_matrix_0.5_0.2.txt"); //存放混淆矩阵
- string save_wrong_results = "./wrong_0.5_0.2"; //存放识别错误的结果
- void ReadTrainData()
- {
- ifstream svm_data(train_path);//训练样本图片的路径都写在这个txt文件中,使用python可以得到这个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,2,...,9),注意这里至少要有两个类别,否则会出错
- }
- else
- {
- img_path.push_back(buf);//图像路径
- }
- }
- }
- svm_data.close();//关闭文件
- }
- void ReadTestData()
- {
- ifstream svm_data(test_path);//训练样本图片的路径都写在这个txt文件中,使用python可以得到这个txt文件
- while (svm_data)//将训练样本文件依次读取进来
- {
- if (getline(svm_data, buf))
- {
- nLine++;
- if (nLine % 2 == 0)//注:奇数行是图片全路径,偶数行是标签
- {
- img_test_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错
- }
- else
- {
- img_test_path.push_back(buf);//图像路径
- }
- }
- }
- svm_data.close();//关闭文件
- }
- void LoadTrainData()
- {
- Mat src; //= Mat::zeros(rows, cols, CV_8UC1);
- Mat dst;
- NumTrainData rtd;
- cout << "Begin load training data...." << endl;
- for (int i = 0; i < img_path.size(); i++)
- {
- rtd.result = img_catg[i];
- int k = 0;
- if (CHANELS == 1) // gray image
- {
- src = imread(img_path[i].c_str(), 0);
- dst = src;
- Mat temp = Mat::zeros(STANDARD_ROW, STANDARD_COL, CV_8UC1);
- //尺寸归一化
- resize(dst, temp, temp.size());
- float m[CHANELS*STANDARD_COL_CHOOSE*STANDARD_ROW_CHOOSE];
- for (int i = 0; i<STANDARD_ROW; i++)
- {
- for (int j = 0; j<STANDARD_COL; j++)
- {
- rtd.data[i * STANDARD_COL + j] = temp.at<uchar>(i, j);
- }
- }
- }
- else if (CHANELS == 3) // 3-channel image
- {
- src = imread(img_path[i].c_str(), 1);
- dst = src;
- Mat temp = Mat::zeros(STANDARD_ROW, STANDARD_COL, CV_8UC1); //大小归一化
- resize(dst, temp, temp.size());
- //cout << temp.channels() << endl;
- for (int i = 0; i < STANDARD_ROW_CHOOSE; i++)
- {
- for (int j = 0; j < STANDARD_COL_CHOOSE; j++)
- {
- Vec3b& mp = temp.at<Vec3b>(i, j);
- float B = mp.val[0];
- //cout << "B=" << B << endl;
- float G = mp.val[1];
- //cout << "G=" << B << endl;
- float R = mp.val[2];
- //cout << "R=" << B << endl;
- rtd.data[k++] = B; //R
- rtd.data[k++] = G; //G
- rtd.data[k++] = R; //B
- }
- }
- }
- buffer.push_back(rtd);
- //cout << i << "th Image is loaded!" << endl;
- }
- cout << "Loading image finished!" << endl;
- }
- void SVMPredict()
- {
- int x = 0;
- //_mkdir(save_test_preprocess.c_str());
- _mkdir(save_wrong_results.c_str());
- int fusion_matrix[Num][Num] = { 0 };
- CvSVM svm;
- svm.load(save_path);
- Mat src,dst;
- Mat m = Mat::zeros(1, featureLen, CV_32FC1);
- NumTrainData rtd;
- int label = -1;
- int right = 0, error = 0;
- save_wrong_results += "/%d_true_%d_false_%d.png";
- //
- double ptrue_rtrue = 0;
- double ptrue = 0;
- double rtrue = 0;
- //
- for (int i = 0; i < img_test_path.size(); i++)
- {
- label = img_test_catg[i];
- rtd.result = label;
- if (CHANELS == 1)
- {
- src = imread(img_test_path[i].c_str(), 0);
- dst = src;
- Mat temp = Mat::zeros(STANDARD_ROW, STANDARD_COL, CV_8UC1); //大小归一化
- resize(dst, temp, temp.size());
- for (int i = 0; i<STANDARD_ROW; i++)
- {
- for (int j = 0; j<STANDARD_COL; j++)
- {
- m.at<float>(0, j + i * STANDARD_COL) = temp.at<uchar>(i, j);
- }
- }
- normalize(m, m);
- }
- else if (CHANELS == 3) // 3-channel image
- {
- src = imread(img_test_path[i].c_str(), 1);
- dst = src;
- Mat temp = Mat::zeros(STANDARD_ROW, STANDARD_COL, CV_8UC1); //大小归一化
- resize(dst, temp, temp.size());
- int k = 0;
- for (int i = 0; i < STANDARD_ROW_CHOOSE; i++)
- {
- for (int j = 0; j < STANDARD_COL_CHOOSE; j++)
- {
- Vec3b& mp = temp.at<Vec3b>(i, j);
- float B = mp.val[0];
- float G = mp.val[1];
- float R = mp.val[2];
- m.at<float>(0, k++) = B; //R
- m.at<float>(0, k++) = G; //G
- m.at<float>(0, k++) = R; //B
- }
- }
- }
- int ret = svm.predict(m);
- //if (ret == 3)
- // ret = 1;
- cout << "Picture->" << img_test_path[i].c_str() << " : \nTrue label is [" << label << "] Predicted label is [" << ret << "]" << endl;
- //
- //计算FSCORE指标各个参数
- if (label == 0 && ret == 0) ptrue_rtrue++;//识别为红牌且实际为红牌;
- if (ret == 0) ptrue++;//识别为红牌的个数
- if (label == 0) rtrue++;//实际为红牌的个数
- //
- //存储错误图片
- if (label != ret)
- {
- x++;
- char filename[200];
- src = imread(img_test_path[i].c_str(), 1);
- sprintf(filename, save_wrong_results.c_str(), x, label, ret);
- imwrite(filename, src);
- }
- //计算混淆矩阵
- //fusion_matrix[label][ret] = fusion_matrix[label][ret] + 1;
- }
- //
- //FSCORE
- std::cout << "count_all: " << img_test_path.size() << std::endl;
- std::cout << "ptrue_rtrue: " << ptrue_rtrue << std::endl;
- std::cout << "ptrue: " << ptrue << std::endl;
- std::cout << "rtrue: " << rtrue << std::endl;
- //precise
- double precise = 0;
- if (ptrue != 0)
- {
- precise = ptrue_rtrue / ptrue;
- std::cout << "precise: " << precise << std::endl;
- }
- else
- {
- std::cout << "precise: " << "NA" << std::endl;
- }
- //recall
- double recall = 0;
- if (rtrue != 0)
- {
- recall = ptrue_rtrue / rtrue;
- std::cout << "recall: " << recall << std::endl;
- }
- else
- {
- std::cout << "recall: " << "NA" << std::endl;
- }
- //FSCORE
- double FScore = 0;
- if (precise + recall != 0)
- {
- FScore = 2 * (precise * recall) / (precise + recall);
- std::cout << "FScore: " << FScore << std::endl;
- }
- else
- {
- std::cout << "FScore: " << "NA" << std::endl;
- }
- //
- //for (size_t i = 0; i < Num; i++)
- //{
- // for (size_t j = 0; j < Num; j++)
- // {
- // matrix_config << fusion_matrix[i][j] << " ";
- // }
- // matrix_config << endl;
- //}
- //matrix_config.close();
- cout << "Task finished!output_matix" << endl;
- getchar();
- }
- void SVMTrain(vector<NumTrainData>& trainData)
- {
- int testCount = trainData.size();
- Mat m = Mat::zeros(1, featureLen, CV_32FC1);
- Mat data = Mat::zeros(testCount, featureLen, CV_32FC1);
- //Mat res = Mat::zeros(testCount, 1, CV_32SC1);
- Mat res = Mat::zeros(testCount, 1, CV_32SC1);
- for (int i = 0; i< testCount; i++)
- {
- NumTrainData td = trainData.at(i);
- memcpy(m.data, td.data, featureLen * sizeof(float));
- normalize(m, m);
- memcpy(data.data + i*featureLen * sizeof(float), m.data, featureLen * sizeof(float));
- cout << td.result << endl;
- res.at<int>(i, 0) = td.result;
- }
- /////////////START SVM TRAINNING//////////////////
- //CvSVM svm = CvSVM();
- CvSVM svm;
- CvSVMParams param;
- CvTermCriteria criteria;
- criteria = cvTermCriteria(CV_TERMCRIT_EPS, 1000, FLT_EPSILON);
- param = CvSVMParams(CvSVM::C_SVC, CvSVM::RBF, 10.0, 0.5, 1.0, 0.2, 0.5, 0.1, NULL, criteria); //gamma=2;C=3
- cout << "Begin to train model using given train data.....\n Total training sample count is " << testCount << endl;
- svm.train(data, res, Mat(), Mat(), param);
- svm.save(save_path);
- cout << "Finish" << endl;
- }
2)主要函数说明;
2.1)SVMTrain函数主要实现模型的训练,其中训练参数使用RBF核,主要调整gamma和C这两个参数,固定一个参数调整另一个参数,最后确定模型参数分别为0.5/0.2;
2.2)SVMPredict函数主要实现对测试样本库的测试,并使用FScore指标测试SVM模型的性能;也可以使用混淆矩阵测试性能;
2.3)ReadTrainData/ ReadTestData函数分别用于获取训练和测试样本库图片的名称和类别标签;
2.4)LoadTrainData函数用于读取训练数据,并进行图像处理;
2.5)代码中使用整张图片的信息进行归一化之后作为特征;
3)主函数入口
- #include "image.h"
- int main(int argc, char *argv[])
- {
- #if (ON_STUDY)
- ReadTrainData();
- LoadTrainData();
- SVMTrain(buffer);
- #else
- ReadTestData();
- SVMPredict();
- #endif
- getchar();
- }
参数ON_STUDY表示选择进行训练或者测试的标志位;
3.SVM的数据要求;
需要说明的是就是SVM对于输入的数据类型是有要求的,即mTrainData(训练数据矩阵)以及mFlagPosNeg(标签矩阵)都必须为CV_32FC1类型(我的环境标签矩阵是CV_32SC1类型的),因此需要进行类型转换,而且必须保证转换完之后数值都不能大于1,这就给我们了两点启示:1)不能直接用下采样后的图像像素作为训练数据的输入,需要进行类型的归一化。2)类型转换时要使用normlize函数,保证其数值范围不大于1,而不能简单的使用Mat的成员函数coverto,只变类型不变数值范围。( 需要注意!)
问题:
该实现过程需要人工调整参数,比较繁琐,可以思考一下,是否还存在其他问题;
参考:
1.http://blog.csdn.net/firefight/article/details/6452188
完
SVM实现分类识别及参数调优(一)的更多相关文章
- 【机器学习基础】SVM实现分类识别及参数调优(二)
前言 实现分类可以使用SVM方法,但是需要人工调参,具体过程请参考here,这个比较麻烦,小鹅不喜欢麻烦,正好看到SVM可以自动调优,甚好! 注意 1.reshape的使用: https://docs ...
- 从信用卡欺诈模型看不平衡数据分类(1)数据层面:使用过采样是主流,过采样通常使用smote,或者少数使用数据复制。过采样后模型选择RF、xgboost、神经网络能够取得非常不错的效果。(2)模型层面:使用模型集成,样本不做处理,将各个模型进行特征选择、参数调优后进行集成,通常也能够取得不错的结果。(3)其他方法:偶尔可以使用异常检测技术,IF为主
总结:不平衡数据的分类,(1)数据层面:使用过采样是主流,过采样通常使用smote,或者少数使用数据复制.过采样后模型选择RF.xgboost.神经网络能够取得非常不错的效果.(2)模型层面:使用模型 ...
- Bayesian Optimization使用Hyperopt进行参数调优
超参数优化 Bayesian Optimization使用Hyperopt进行参数调优 1. 前言 本文将介绍一种快速有效的方法用于实现机器学习模型的调参.有两种常用的调参方法:网格搜索和随机搜索.每 ...
- 【转】XGBoost参数调优完全指南(附Python代码)
xgboost入门非常经典的材料,虽然读起来比较吃力,但是会有很大的帮助: 英文原文链接:https://www.analyticsvidhya.com/blog/2016/03/complete-g ...
- 【深度学习篇】--神经网络中的调优一,超参数调优和Early_Stopping
一.前述 调优对于模型训练速度,准确率方面至关重要,所以本文对神经网络中的调优做一个总结. 二.神经网络超参数调优 1.适当调整隐藏层数对于许多问题,你可以开始只用一个隐藏层,就可以获得不错的结果,比 ...
- XGBoost参数调优完全指南
简介 如果你的预测模型表现得有些不尽如人意,那就用XGBoost吧.XGBoost算法现在已经成为很多数据工程师的重要武器.它是一种十分精致的算法,可以处理各种不规则的数据.构造一个使用XGBoost ...
- xgboost 参数调优指南
一.XGBoost的优势 XGBoost算法可以给预测模型带来能力的提升.当我对它的表现有更多了解的时候,当我对它的高准确率背后的原理有更多了解的时候,我发现它具有很多优势: 1 正则化 标准GBDT ...
- XGBoost模型的参数调优
XGBoost算法在实际运行的过程中,可以通过以下要点进行参数调优: (1)添加正则项: 在模型参数中添加正则项,或加大正则项的惩罚力度,即通过调整加权参数,从而避免模型出现过拟合的情况. (2)控制 ...
- 评价指标的局限性、ROC曲线、余弦距离、A/B测试、模型评估的方法、超参数调优、过拟合与欠拟合
1.评价指标的局限性 问题1 准确性的局限性 准确率是分类问题中最简单也是最直观的评价指标,但存在明显的缺陷.比如,当负样本占99%时,分类器把所有样本都预测为负样本也可以获得99%的准确率.所以,当 ...
随机推荐
- Linq 常用方法解释
/// <summary> /// linq /// </summary> public class Linq { /// <summary> /// 测试 /// ...
- Linux访问windows共享(samba/smbclient/smbfs/cifs)
samba是一个实现不同操作系统之间文件共享和打印机共享的一种SMB协议的免费软件.●安装samba,samba-client和cifs-utils.x86_64此步将自动安装好相关依赖包:samba ...
- 开关灯问题 BulbSwitch
2018-06-17 11:54:51 开关电灯问题是一个比较经典的趣味数学题,本文中主要介绍其中的一些常见情况. 一.Bulb Switch 问题描述: 问题求解: 初始状态:off, off, o ...
- Liebig's Barrels CodeForces - 985C (贪心)
链接 大意:给定$nk$块木板, 要制作$n$个$k$块板的桶, 要求任意两桶容积差不超过$l$, 每个桶的容积为最短木板长, 输出$n$个桶的最大容积和 假设最短板长$m$, 显然最后桶的体积都在$ ...
- CentOS7系统更换YUM Repo源
CentOS7系统更换YUM Repo源 备份原镜像 sudo mv /etc/yum.repos.d/CentOS-Base.repo /etc/yum.repos.d/CentOS-Base.re ...
- 数据库故障诊断(Troubleshooting)之性能问题导致的数据库严重故障案例之一
好久不来这里写东西,今天有点时间,来这里写点最近遇到的事情.前段时间,某电信业务用户因某核心生产库最近多次宕机重启,多方人员介入无果后,给我发来了邮件,大概意思就是现在该问题已经造成了比较严重的后果, ...
- 用Maven创建第一个web项目
http://www.cnblogs.com/leiOOlei/p/3361633.html 一.创建项目 1.Eclipse中用Maven创建项目 上图中Next 2.继续Next 3.选maven ...
- 封装一个简单的原生js焦点轮播图插件
轮播图实现的效果为,鼠标移入左右箭头会出现,可以点击切换图片,下面的小圆点会跟随,可以循环播放(为了方便理解,没有补2张图做无缝轮播).本篇文章的主要目的是分享封装插件的思路. 轮播图我一开始是写成非 ...
- git and github问题集锦
本人遇到的:
- selenium(五)伪造浏览器
简介: 这个就比较好玩了,大家还记得以前的QQ小尾巴么?还有百度贴吧的小尾巴,就是那个来自***的iphone7,这个功能. 这个功能是基于浏览器的user-agent功能实现的. 还是httpbin ...