【OpenCV学习记录】HOG+SVM叶片病斑识别
作者:互联网
1.从哪哪都不知道到会用
(1)找了官方的实例代码,因为本人代码阅读能力有限,因此将代码部分下载下来,边查边记就看懂了,再敲一遍(opencv2.x和opencv3.x有些用法不太一样要自己改一改)
链接 | |
---|---|
1 | 支持向量机线性可分数据的处理 |
2 | 支持向量机对线性不可分数据的处理 |
(2)找了一些应用的例子,打印,看懂,仿照着敲代码,就成啦
链接 | |
---|---|
1 | 以整个图像为特征的手写数字SVM识别 |
2 | 小狮子识别 |
3 | 车标识别 |
4 | 视频识别 |
2.准备数据
(1)准备了50幅病斑的图片然后通过旋转翻转等操作扩充到480幅(可以大小不一样,因为代码部分会重置图片大小)
(2)准备了120幅正常叶子的图片,扩充到480幅(可以大小不一样,因为代码部分会重置图片大小)
(3)生成样本描述文件,方便读取
- 将病斑图像与正常叶子图像信息写在同一TXT文件中,一行路径,一行标签
怎么生成这个文件呐,用法术呀
3.训练SVM
咋训练*~*
当然是敲代码喽
(1)用了如此多的头文件和命名空间咱也不知道哪个没用,反正都用上没出错
#include"stdafx.h"//这个是VS一定要让我用的
#include"SVM_CucumberRotShiBie.h"//这个是我这个.cpp的.h
#include<iostream>//输入输出
#include<fstream>//文件流
//下面这几个你们试试哪个用不上告诉我呀
#include<opencv2/opencv.hpp>
#include<opencv2/core/core.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/ml/ml.hpp>
//这个都用得上
using namespace std;
using namespace cv;
using namespace ml;
(2)然后定义了一些路径和关键数值
int DescriptorDim=900;//Hog训练结果维数,通过descriptors.size()得到
string address = "img_SVM/train/decribeTxt.txt";//描述文件路径
string address_result = "img_SVM/train/SVM_HOG.xml";//训练结果存储路径
string address_classification = "img_SVM/test/124.jpg";//测试图像路径
(3)这是我没什么用,但是又不能少的主函数
int cucumberRotShiBie() {
//1.准备数据
//2.生成描述文件
//3.训练SVM
trainingSVM();
//4.测试
SvmHogClassification();
//完
return 0;
}
(4)训练
int trainingSVM() {
cout << "------------------准备数据---------------------" << endl;
cout << "-----------------------------------------------" << endl;
//读取描述文件内容
vector<string> imgPath;//图像路径容器
vector<int> imgCatg;//图像类别容器
int nLine = 0;
string buf;
ifstream svm_data(address);
if (!svm_data) {
int a = 0; cin >> a;
return -1;
}
unsigned long n;
while (svm_data) {
if (getline(svm_data,buf)) {
nLine++;
if (nLine % 2 == 0) {
imgCatg.push_back(atoi(buf.c_str()));//图像类型
}
else {
imgPath.push_back(buf);//图像路径
}
}
}
svm_data.close();
///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
//设置HOG检测器参数
HOGDescriptor hog(Size(48, 48), Size(16, 16), Size(8, 8), Size(8, 8), 9);
//训练数据、标志设置
Mat data_mat, res_mat;
int imgNum = nLine / 2;//图像数量,训练数据x维数
Size data_mat_size(DescriptorDim, imgNum);//训练数据size !!!size(列,行)!!!
Size res_mat_size(1, imgNum);//标志size
data_mat=Mat::zeros(data_mat_size, CV_32FC1);
res_mat = Mat::zeros(res_mat_size, CV_32SC1);
//统一图像尺寸的参数
string s;//图像路径
Size ssize(48, 48);
Mat src;
Mat dst(ssize, CV_8UC3);
///////////////////////////////////////////////////////////////////////////////////
cout << "-----------------处理HOG特征-------------------" << endl;
cout << "-----------------------------------------------" << endl;
for (int i = 0; i <imgNum; i++) {
//获取图像
s = imgPath[i].c_str();
src = imread(s);
if (src.empty()) {
cout << "no image:" << s << endl;
return -1;
}
cout << "处理:" << s << endl;
//统一图像尺寸
resize(src, dst,ssize);
//存放HOG特征计算结果
vector<float>descriptors;
//计算HOG特征
hog.compute(dst, descriptors, Size(1, 1),Size(0,0));
//cout <<"size:"<< descriptors.size() << endl;//Hog特征维数
//
for (int j = 0;j<descriptors.size();j++) {
data_mat.at<float>(i, j) = descriptors[j];
}
res_mat.at<float>(i, 0) = imgCatg[i];
}
/////////////////////////////////////////////////////////////////////////////////////
cout << "-------------------训练SVM---------------------" << endl;
cout << "-----------------------------------------------" << endl;
//设置参数
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::Types::C_SVC);
svm->setKernel(SVM::KernelTypes::LINEAR);
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
Ptr<TrainData>td = TrainData::create(data_mat, SampleTypes::ROW_SAMPLE, res_mat);
svm->train(td);
svm->save(address_result);
cout << "完!" << endl;
return 0;
}
(5)检测,输出的结果就是当前检测图像的标签
int SvmHogClassification() {
//获取检测图像
Mat src = imread(address_classification);
if (src.empty()) {
cout << "no image!" << endl;
return -1;
}
//计算检测图像的HOG特征
HOGDescriptor hog(Size(48, 48), Size(16, 16), Size(8, 8), Size(8, 8), 9);
//统一图像尺寸的参数
Size ssize(48, 48);
Mat dst(ssize, CV_8UC3);
//统一图像尺寸
resize(src, dst, ssize);
//存放HOG特征计算结果
vector<float>descriptors;
//计算HOG特征
hog.compute(dst, descriptors, Size(1, 1), Size(0, 0));
//转换计算结果格式
Mat endImg = Mat::zeros(1, descriptors.size(), CV_32FC1);
for (int i = 0; i < descriptors.size(); i++) {
endImg.at<float>(0, i) = descriptors[i];
}
//SVM分类
Ptr<SVM> svm = SVM::load(address_result);
if (svm->empty()) {
cout << "no load!" << endl;
return -1;
}
float res = svm->predict(endImg);
cout << res << endl;
return 0;
}
4.总结
(1)敲线性不可分的官方代码时输出结果应该是那几个点被圈圈圈起来,但是那个圈却出现在原点附近
然后我就查啊查发现这不是BUG是什么我忘了
要改核函数这里
Ptr<SVM> params=SVM::create();
params->setType(SVM::C_SVC);
params->setC(0.1);
params->setKernel(SVM::POLY);//!!!!
params->setDegree(1.0);//!!!!!
params->setTermCriteria(TermCriteria(CV_TERMCRIT_ITER, (int)1e7, 1e-6));
就好啦!
(2)我没有调参数,我没有调参数,我没有调参数
HOG的参数,,SVM的参数,,都没改
咱也不知道哪个数好,大家都说好,我就用了,待我那日调了参数,我再更新它
(3)训练的数据要有两及个以上的类型,不然它会应为你太过分就不干活啦,哈哈哈。
标签:HOG,svm,mat,OpenCV,SVM,size,data,Size 来源: https://blog.csdn.net/u014284965/article/details/100834594