本文基于OpenCV官方文档和源码
工具:Win10+VS2015+OpenCV3.2+OpenCV官方文档
SVM
SVM:支持向量机(Support Vector Machine),多用于分类任务。
有关支持向量机的学习可以参阅周志华老师《机器学习》一书的第6章,介绍得非常精简到位。OpenCV里面的线性SVM
对于实践类知识的学习,我更倾向于直接看例程,然后遇到不懂的就查阅官方文档。所以在此直接上代码:
#include <opencv2/core.hpp>
#include <opencv2/imgproc.hpp>
#include <opencv2/imgcodecs.hpp>
#include <opencv2/highgui.hpp>
#include <opencv2/ml.hpp>
using namespace cv;
using namespace cv::ml;
int main()
{
// 创建用于可视化的图像
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
// 第一步,设置训练数据:标签,数据点
int labels[4] = { 1, -1, -1, -1 }; //定义样本标签
float trainingData[4][2] = { { 501, 10 },{ 255, 10 },{ 501, 255 },{ 10, 501 } }; //定义样本点
Mat trainingDataMat(4, 2, CV_32FC1, trainingData); //样本点
Mat labelsMat(4, 1, CV_32SC1, labels); //样本标签
// 训练SVM
// 第二步,SVM参数初始化
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC); //设置类型C_SVC,允许处理不完美情况,即不是线性可分的情况下也会给个结果,即使这个结果不好
svm->setKernel(SVM::LINEAR); //设置核函数类型,LINEAR:线性
//设置训练终止调剂,三个参数分别为:终止类型,最大迭代次数,精度
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));
// 第三步,SVM训练
// train()函数包含三个参数:samples,layout,responses,只有samples是必须要设置的参数
// 只设置第一个参数,训练会采用无监督学习算法;如果设置后两个参数,则采用有监督学习算法训练
svm->train(trainingDataMat, ROW_SAMPLE, labelsMat);
// 第四步,显示由SVM决策出的分类区域
Vec3b green(0, 255, 0), blue(255, 0, 0);
for (int i = 0; i < image.rows; ++i) //决策每个点的类别
for (int j = 0; j < image.cols; ++j)
{
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
float response = svm->predict(sampleMat); //得到预测的类别结果
if (response == 1)
image.at<Vec3b>(i, j) = green;
else if (response == -1)
image.at<Vec3b>(i, j) = blue;
}
// 第五步,显示训练样本点,就是以样本坐标为中心画实心圆圈
int thickness = -1;
int lineType = 8;
circle(image, Point(501, 10), 5, Scalar(0, 0, 0), thickness, lineType);
circle(image, Point(255, 10), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(501, 255), 5, Scalar(255, 255, 255), thickness, lineType);
circle(image, Point(10, 501), 5, Scalar(255, 255, 255), thickness, lineType);
// 第六步,显示支持向量
// 支持向量:距离划分超平面最近的训练样本点
thickness = 2;
lineType = 8;
Mat sv = svm->getUncompressedSupportVectors(); //得到支持向量,返回float类型的Mat
for (int i = 0; i < sv.rows; ++i)
{
const float* v = sv.ptr<float>(i);
circle(image, Point((int)v[0], (int)v[1]), 6, Scalar(128, 128, 128), thickness, lineType);
}
//第七步,图像保存与显示
imwrite("result.png", image);
imshow("SVM Simple Example", image);
waitKey(0);
return 0;
}
3 运行结果