前言

项目有一个模块需要将不同类别的图片进行分类,共有三个类别,使用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

2.opencv中SVM的那些事儿

 

SVM实现分类识别及参数调优(一)的更多相关文章

  1. 【机器学习基础】SVM实现分类识别及参数调优(二)

    前言 实现分类可以使用SVM方法,但是需要人工调参,具体过程请参考here,这个比较麻烦,小鹅不喜欢麻烦,正好看到SVM可以自动调优,甚好! 注意 1.reshape的使用: https://docs ...

  2. 从信用卡欺诈模型看不平衡数据分类(1)数据层面:使用过采样是主流,过采样通常使用smote,或者少数使用数据复制。过采样后模型选择RF、xgboost、神经网络能够取得非常不错的效果。(2)模型层面:使用模型集成,样本不做处理,将各个模型进行特征选择、参数调优后进行集成,通常也能够取得不错的结果。(3)其他方法:偶尔可以使用异常检测技术,IF为主

    总结:不平衡数据的分类,(1)数据层面:使用过采样是主流,过采样通常使用smote,或者少数使用数据复制.过采样后模型选择RF.xgboost.神经网络能够取得非常不错的效果.(2)模型层面:使用模型 ...

  3. Bayesian Optimization使用Hyperopt进行参数调优

    超参数优化 Bayesian Optimization使用Hyperopt进行参数调优 1. 前言 本文将介绍一种快速有效的方法用于实现机器学习模型的调参.有两种常用的调参方法:网格搜索和随机搜索.每 ...

  4. 【转】XGBoost参数调优完全指南(附Python代码)

    xgboost入门非常经典的材料,虽然读起来比较吃力,但是会有很大的帮助: 英文原文链接:https://www.analyticsvidhya.com/blog/2016/03/complete-g ...

  5. 【深度学习篇】--神经网络中的调优一,超参数调优和Early_Stopping

    一.前述 调优对于模型训练速度,准确率方面至关重要,所以本文对神经网络中的调优做一个总结. 二.神经网络超参数调优 1.适当调整隐藏层数对于许多问题,你可以开始只用一个隐藏层,就可以获得不错的结果,比 ...

  6. XGBoost参数调优完全指南

    简介 如果你的预测模型表现得有些不尽如人意,那就用XGBoost吧.XGBoost算法现在已经成为很多数据工程师的重要武器.它是一种十分精致的算法,可以处理各种不规则的数据.构造一个使用XGBoost ...

  7. xgboost 参数调优指南

    一.XGBoost的优势 XGBoost算法可以给预测模型带来能力的提升.当我对它的表现有更多了解的时候,当我对它的高准确率背后的原理有更多了解的时候,我发现它具有很多优势: 1 正则化 标准GBDT ...

  8. XGBoost模型的参数调优

    XGBoost算法在实际运行的过程中,可以通过以下要点进行参数调优: (1)添加正则项: 在模型参数中添加正则项,或加大正则项的惩罚力度,即通过调整加权参数,从而避免模型出现过拟合的情况. (2)控制 ...

  9. 评价指标的局限性、ROC曲线、余弦距离、A/B测试、模型评估的方法、超参数调优、过拟合与欠拟合

    1.评价指标的局限性 问题1 准确性的局限性 准确率是分类问题中最简单也是最直观的评价指标,但存在明显的缺陷.比如,当负样本占99%时,分类器把所有样本都预测为负样本也可以获得99%的准确率.所以,当 ...

随机推荐

  1. 简单了解SQL(结构化查询语言)

    简单了解SQL(结构化查询语言) 年10月,美国国家标准学会对SQL进行规范后,以此作为关系式数据库管理系统的标准语言(ANSI X3. 135-1986),1987年得到国际标准组织的支持下成为国际 ...

  2. ADO.NET 批量插入

    在.Net1.1中无论是对于批量插入整个DataTable中的所有数据到数据库中,还是进行不同数据源之间的迁移,都不是很方便.而 在.Net2.0中,SQLClient命名空间下增加了几个新类帮助我们 ...

  3. Spring生态顶级项目说明

    1.Spring IO platform 说明:用于系统部署,是可集成的,构建现代化应用的版本平台 2.Spring Boot 说明:旨在简化创建产品级的 Spring 应用和服务,简化了配置文件,使 ...

  4. spring boot 开发 提交form表单出错

    提交表单时,字段有的没有值,springboot 会报错. org.springframework.validation.BindException: org.springframework.vali ...

  5. Java 8 Lambda实现原理分析

    PDF文档已上传Github  Github:https://github.com/zwjlpeng/Angrily_Learn_Java_8 为了支持函数式编程,Java 8引入了Lambda表达式 ...

  6. HDU 2569 彼岸

    彼岸 思路:动态规划.因为不能有连续三个不同的颜色,所以只要看最后三个就可以了. 设dp[n]为长度为n到达彼岸的方案数. ①当第n-2个颜色和第n-1个颜色相同时,第n个位置可以取任意一种颜色,dp ...

  7. [.NET开发] C# BigInteger 处理超大整型数字

    今天遇到一个要处理XSD中Integer的数值区间的计算的问题,Integer这个类型的值区间理论上是可没有边界的,假设目前的值是1.5E+10000, 这个数字已经达到double和Int64都无法 ...

  8. 20170731xlVba根据数据表和模板表生成新表

    Public Sub SplitData() Dim Wb As Workbook Dim Sht As Worksheet Dim NewSht As Worksheet Dim arr As Va ...

  9. linux 检查补丁包是否安装 名称 版本 release号

    To determine whether the required packages are installed, enter commands similar to the following: # ...

  10. TABLE中动态设置poplist的值跟着当前行的某些列动态变化

    核心方法 OAAdvancedTableBean table = (OAAdvancedTableBean)webBean.findChildRecursive("TimeEntryTbl& ...