支持向量机简介
支持向量机(Support Vector Machine,SVM)是一种二分类模型,目标时寻找一个标准(成为超平面)对样本数据进行分割,分割的原则是确保分类最优化(类别之间的间隔最大)。当数据集较小时,使用支持向量机进行分类非常有效。
在对原始数据分类的过程中,可能无法使用线性方法实现分割。支持向量机在分类时,把无法线性分割的数据映射到高维空间,然后再高维空间占到分类最优的线性分类器。
分类器
在已有数据中,找到距离分类器最近的点,确保他们离分类器尽可能的远。在这儿,离分类器最近的点到分类器的距离成为间隔(margin),都希望间隔尽可能地大,这样分类器在处理数据时,就会更准确。离分类器最近的那些点叫做支持向量(support vector),正是这些支持向量决定了分类器所在的位置。
支持向量机在处理数据时,如果在低维空间内无法完成分类,就自动将数据映射到高维空间,使其尽可能线性,简单而讲,就是对当前数据进行函数映射操作。
概念总结
支持向量机可以处理任何维度的数据,在不同的维度下,支持向量机都会尽可能寻找类似于二维空间中的直线分类器。
“支持向量”是离分类器最近的那些点,这些点位于最大“间隔上”。通常情况分类仅靠这些点完成,而与其他点无关。
“机器”指得是分类器。
综上所述,支持向量机是一种基于关键点的算法分类。
手写数字识别案例代码
本案例中训练数据机验证数据所选图像均从百度搜索,侵犯立删
//支持向量机手写数字识别案例
Mat trainData = new Mat(0, 0, MatType.CV_32FC1);
Mat trainLabel = new Mat(0, 0, MatType.CV_32SC1);
Mat validData = new Mat(0, 0, MatType.CV_32FC1);
float[] validActual;
const int boundWidth = 100, boundHeight = 100;
string trainPath = @"D:\Jay.Lee\Study\imgs\KNEARTESTIMG\numberSubImgs\numberSubImgs";
string validPath = @"D:\Jay.Lee\Study\imgs\KNEARTESTIMG\test.png";
//训练数据集收集
//训练数据标签集收集
for(int i = 0; i < 10; i++)
{
for(int j = 0; j < 32; j++)
{
//图像获取
Mat temp = new Mat(trainPath + $"{
i}_{
j}.png", ImreadModes.Grayscale);
temp = temp.Threshold(0, 255, ThresholdTypes.Otsu);
//数据转成单行
temp = temp.Reshape(0, 1).Normalize(0,1,NormTypes.MinMax);
//数据转型float
temp.ConvertTo(temp, MatType.CV_32FC1);
//数据添加到训练数据集中
trainData.PushBack(temp);
//数据对应标签添加到训练数据标签中
trainLabel.PushBack(Mat.Ones(1, 1, MatType.CV_32SC1) * i);
}
}
//验证数据集收集
//验证数据实际值
//验证图像获取
Mat validImg =new Mat(validPath);
//验证图像取反
Mat validCp =255- validImg.CvtColor(ColorConversionCodes.BGR2GRAY);
//验证图像取二值
validCp = validCp.Threshold(0, 255, ThresholdTypes.Otsu);
//验证图像找轮廓对应子图
validCp.FindContours(out Point[][] vCnts, out HierarchyIndex[] hiers, RetrievalModes.External, ContourApproximationModes.ApproxSimple);
vCnts = vCnts.ToList().Where(cnt => Cv2.ContourArea(cnt) > 5 && Cv2.ArcLength(cnt, false) > 5).OrderBy(cnt => Cv2.BoundingRect(cnt).X).ToArray();
int validNums = vCnts.Length;
validActual = new float[] {
0, 5, 2, 2, 1, 8, 5, 9 };
for(int i = 0; i < validNums; i++)
{
//获取手写数字边界矩形
Mat temp = validCp[Cv2.BoundingRect(vCnts[i])];
//验证数据转单行
temp = temp.Resize(new Size(boundWidth,boundHeight)).Normalize(0, 1, NormTypes.MinMax).Reshape(0, 1);
//验证数据转float
temp.ConvertTo(temp, MatType.CV_32FC1);
//验证数据转到总验证数据集中
validData.PushBack(temp);
}
//支持向量机创建&&训练&&验证
using (var svm = OpenCvSharp.ML.SVM.Create())
{
//支持向量机核算法类型选择-poly
svm.KernelType = OpenCvSharp.ML.SVM.KernelTypes.Poly;
svm.Degree = 0.7;
//支持向量机训练
svm.Train(trainData, OpenCvSharp.ML.SampleTypes.RowSample, trainLabel);
Mat svmResult = new Mat();
//支持向量机验证机结果获取
svm.Predict(validData, svmResult);
//验证结果&实际值显示
for(int i = 0; i < svmResult.Rows; i++)
{
string annotation = $"VV:{
((float*)svmResult.Ptr(i))[0]}" +
$" AV:{
validActual[i]}";
Rect boundRect = Cv2.BoundingRect(vCnts[i]);
Point position = new Point(boundRect.X, boundRect.Y);
validImg.PutText(annotation, position, HersheyFonts.HersheySimplex, 0.5, Scalar.Red, thickness: 2);
}
Cv2.ImShow("validResult", validImg);
Cv2.WaitKey();
}
训练数据集(上述代码中未体现子图分割部分,同时还添加了一些excel中部分格式的数字图像数据)
验证数据图像
验证数据结果显示
总结
此次通过支持向量机对手写数字识别案例,对比之前通过knn近邻对手写数字识别进行对比发现,相对knn近邻算法,支持向量机在相同训练数据量情况下,所验证出的结果准确率较高一些。