前言
svm训练模型相当简单,难的是提取特征这一步,这里介绍了一个睁闭眼检测功能从提取特征到预测的全过程。
首先,需要准备数据,我这里有睁眼和闭眼的照片各3000张,传统的机器学习方法都需要提取特征,这里检测特征用到了三个,通过程序预先提取出来了;接下来是模型的训练和预测过程。
提取特征:左右开眼率(上下眼皮的特征点距离)、黑色眼球的圆弧度(霍夫变换检测园)、眼球长宽比(人脸特征点)
特征提取出来:文件名+三个特征+标签(0睁眼、1闭眼)
然后把三个特征进行归一化,更有利于训练,并去掉了文件名(不需要)
模型训练(python)
这一步主要是把txt文本中的特征读取进来,每一张图片用一行三个特征表示;因此,n张图片转化成一个n行3列的特征矩阵,以及一个n行1列的label矩阵,然后使用svm训练
from numpy import *
import numpy as np
import cv2
import matplotlib.pyplot as plt
def loadDataSet(fileName):
dataMat = []
labelMat = []
with open(fileName) as fr:
for line in fr.readlines():
lineArr = line.strip().split(' ')
dataline = list(map(float, lineArr))
dataMat.append([float(dataline[0]), float(dataline[1]), float(dataline[2])])
labelMat.append([int(dataline[3])])
return dataMat, labelMat
#加载训练集
train_data,train_label = loadDataSet('new/img/train-20/right.txt') #1.加载一个txt数据集
train_data = mat(train_data)
train_data=np.array(train_data, dtype='float32')
train_label = mat(train_label)
#加载测试集
test_data,test_label = loadDataSet('new/img/train-20/test-right.txt') #1.加载一个txt数据集
test_data = mat(test_data)
test_data=np.array(test_data, dtype='float32')
test_label=mat(test_label)
# print(test_label.shape)
# 创建分类器
svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC) # SVM类型
svm.setKernel(cv2.ml.SVM_LINEAR) # 使用线性核
svm.setC(1e-5)
# 训练
ret = svm.train(train_data, cv2.ml.ROW_SAMPLE, train_label)
# svm.save('img/left.xml')
# 支持向量
vec = svm.getSupportVectors()
print("最终结果:",vec)
# 测试
(ret, res) = svm.predict(test_data)
# print(res)
# 准确率
n=0
lens=len(test_data)
for i in range(lens):
if res[i]==test_label[i]:
n=n+1
Accuracy=n/lens
print("准确度为:",Accuracy)
最后得到结果如下:
保存的模型:
加载模型预测:
使用svm = cv2.ml.SVM_load()即可加载一个训练好的模型,并且进行预测
# 创建分类器
svm = cv2.ml.SVM_create()
svm.setType(cv2.ml.SVM_C_SVC) # SVM类型
svm.setKernel(cv2.ml.SVM_LINEAR) # 使用线性核
svm.setC(1e-5)
svm = cv2.ml.SVM_load("new/img/train-30/svm-right.xml")
svm2 = cv2.ml.SVM_load("new/c++/svm-left.xml")
# 测试
(ret1, res1) = svm.predict(test_data)
(ret2, res2) = svm2.predict(test_data)
再贴个c++版本的svm代码:
#include<opencv2\opencv.hpp>
using namespace std;
using namespace cv;
using namespace cv::ml;
int main()
{
float train_data[2850][3];
int train_label[2850][1];
ifstream file1("D:/work/Test/Test2/test2--图像处理/svm--眼睛状态检测/c++/train_data.txt");
ifstream file2("D:/work/Test/Test2/test2--图像处理/svm--眼睛状态检测/c++/train_label.txt");
// 训练数据
for (int i = 0; i < 2850; i++)
{
for (int j = 0; j < 3; j++)
{
file1 >> train_data[i][j];
//cout << train_data[i][j] << " ";
}
//cout << endl;
}
// 训练标签
for (int i = 0; i < 2850; i++)
{
for (int j = 0; j < 1; j++)
{
file2 >> train_label[i][j];
//cout << train_label[i][j] << " ";
}
//cout << endl;
}
file1.close();
file2.close();
Mat dataMat(2850, 3, CV_32FC1, train_data);
Mat labelMat(2850, 1, CV_32SC1, train_label);
//训练的初始化
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
svm->setTermCriteria(cv::TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1500, 1e-5));
开始训练
svm->train(dataMat, ROW_SAMPLE, labelMat);
svm->save("D:/work/Test/Test2/test2--图像处理/svm--眼睛状态检测/c++/svm2.xml");
svm->load("svm.xml");
std::cout << "模型训练完毕!" << endl;
//Mat result; //返回结果
//float testData[2][3] = {
// { 0.814973, 15.1147, 0.431797 },
// { 1.514973, 18.1147, 0.436597 }
//}; //预测数据
//Mat test(2, 3, CV_32FC1, testData); //预测数据
//svm->predict(test, result); //进行预测
//std::cout << "分类结果为:" << endl;
//std::cout << result << endl;
把预测结果提取出来
//int len = test.rows;;
//for (int i = 0; i < len; i++)
//{
// int a = result.at<Point2f>(i, 0).x; // 把预测结果提取出来
// std::cout << a << endl;
//}
return 0;
}