OpenCV - SVM算法原理实现以及SVM图像分割

支持向量机的原理这里也就不阐述了,我也不太会。我大概的理解就是和KNN一样是个分类器,可以想象以下,两类样本点可以用很多条线分开,但是那一条是最优呢?支持向量机中利用支持向量(可能是样本中的几个点,具体怎么取这个向量不需要我们考虑),然后计算支持向量到分割线的距离,距离最大的那条分界线那就是最优分类了。所以SVM中用的是间隔最大化思想。


参数设置

支持向量机只有一成为一个很强的算法,是因为它能够适应各种情况,也因如此参数设置比KNN要多很多。OpenCV中给出接口:

SVM中有不同的内核,不同的内核计算公式中有不同的参数,所以要根据所选内核来调整参数;

一般用linear线性内核,poly多项式内核,rbf 基于径向的函数

关于核的:https://blog.csdn.net/qq_30263737/article/details/83338958

enum KernelTypes {
        /** Returned by SVM::getKernelType in case when custom kernel has been set */
        CUSTOM=-1,
        /** Linear kernel. No mapping is done, linear discrimination (or regression) is
        done in the original feature space. It is the fastest option. \f$K(x_i, x_j) = x_i^T x_j\f$. */
        LINEAR=0,
        /** Polynomial kernel:
        \f$K(x_i, x_j) = (\gamma x_i^T x_j + coef0)^{degree}, \gamma > 0\f$. */
        POLY=1,
        /** Radial basis function (RBF), a good choice in most cases.
        \f$K(x_i, x_j) = e^{-\gamma ||x_i - x_j||^2}, \gamma > 0\f$. */
        RBF=2,
        /** Sigmoid kernel: \f$K(x_i, x_j) = \tanh(\gamma x_i^T x_j + coef0)\f$. */
        SIGMOID=3,
        /** Exponential Chi2 kernel, similar to the RBF kernel:
        \f$K(x_i, x_j) = e^{-\gamma \chi^2(x_i,x_j)}, \chi^2(x_i,x_j) = (x_i-x_j)^2/(x_i+x_j), \gamma > 0\f$. */
        CHI2=4,
        /** Histogram intersection kernel. A fast kernel. \f$K(x_i, x_j) = min(x_i,x_j)\f$. */
        INTER=5
    };

对应参数:

degree:内核函数(POLY)的参数degree。

gamma:内核函数(POLY/ RBF/ SIGMOID)的参数

coef0:内核函数(POLY/ SIGMOID)的参数coef0。

关于svm类型的:

C_SVC是默认类型:C类支撑向量分类机。 n类分组 (n≥2),容许用异常值处罚因子C进行不完全分类。

    enum Types {
      
        C_SVC=100,
      
        NU_SVC=101,
       
        ONE_CLASS=102,
       
        EPS_SVR=103,
       
        NU_SVR=104
    };

对应参数:

Cvalue:SVM类型(C_SVC/ EPS_SVR/ NU_SVR)的参数C。

nu:SVM类型(NU_SVC/ ONE_CLASS/ NU_SVR)的参数 。

p:SVM类型(EPS_SVR)的参数。

class_weights:C_SVC中的可选权重,赋给指定的类,乘以C今后变成 。所以这些权重影响不合类此外错误分类处罚项。权重越大,某一类此外误分类数据的处罚项就越大。

term_crit:SVM的迭代练习过程的中断前提,解决项目组受束缚二次最优题目。您可以指定的公差和/或最大迭代次数。


// SVM.cpp : 此文件包含 "main" 函数。程序执行将在此处开始并结束。
//

#include "pch.h"
#include 
#include 


using namespace cv;
using namespace cv::ml;

int train_sample_nums = 200;

int main()
{
	/******************数据集制作***************************/
	Mat trainData(train_sample_nums, 2, CV_32FC1);
	Mat trainClassess(train_sample_nums, 1, CV_32SC1);               //注意标签的格式,有符号

	//创建可视化图像
	Mat img(500, 500, CV_8UC3, Scalar::all(0));
	//样本点
	Mat sample(1, 2, CV_32FC1);

	Mat trainData1, trainData2, trainClasses1, trainClasses2;

	RNG rng = RNG(-1);
	//生成均值为(200,200),方差为(40,40)的随机数据
	trainData1 = trainData.rowRange(0, train_sample_nums / 2);
	rng.fill(trainData1, CV_RAND_NORMAL, Scalar(100, 100), Scalar(40, 40));
	trainData2 = trainData.rowRange(train_sample_nums / 2, train_sample_nums);
	rng.fill(trainData2, CV_RAND_NORMAL, Scalar(300, 300), Scalar(40, 40));

	//trainClasses1和trainClassess的前100行绑定
	trainClasses1 = trainClassess.rowRange(0, train_sample_nums / 2);
	trainClasses1 = Scalar::all(1);
	trainClasses2 = trainClassess.rowRange(train_sample_nums / 2, train_sample_nums);
	trainClasses2 = Scalar::all(-1);

	/*****************训练********************/
	cv::Ptr svm = cv::ml::SVM::create();
	svm->setType(cv::ml::SVM::C_SVC);
	svm->setC(1.0);
	
	svm->setKernel(cv::ml::SVM::POLY);
	svm->setGamma(1.0);
	svm->setDegree(2.0);
	svm->setCoef0(0.0);
	
	svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER, 500, 1e-6));// cv::ml::SVM::setTermCriteria(CV_TERMCRIT_ITER, 500, 1e-6);	

	cv::Ptr TrainData = TrainData::create(trainData, SampleTypes::ROW_SAMPLE, trainClassess);
	//svm->train(trainData, cv::ml::ROW_SAMPLE, trainClassess);
	svm->train(TrainData);

	for (int i = 0; i < img.rows; ++i)
	{
		for (int j = 0; j < img.cols; ++j)
		{
			Mat sampleMat = (Mat_(1, 2) << i, j);
			float response = svm->predict(sampleMat);
			if (response == 1)
			{
				img.at(i, j) = Vec3b(0, 160, 0);
			}
			else if (response == -1)
			{
				img.at(i, j) = Vec3b(0, 0, 160);
			}
		}
	}

	for (int i = 0; i < train_sample_nums / 2; i++)
	{
		Point pt;
		pt.x = round(trainData1.at(i, 0));
		pt.y = round(trainData1.at(i, 1));
		circle(img, pt, 1, Scalar(0, 255, 255));

		pt.x = round(trainData2.at(i, 0));
		pt.y = round(trainData2.at(i, 1));
		circle(img, pt, 1, Scalar(255, 255, 0));
	}

	int thickness = 1;
	int lineType = 8;
	Mat image(img);
	Mat sv = svm->getSupportVectors();
	for (int i = 0; i < sv.rows; i++)
	{
		const float* v = sv.ptr(i);
		circle(image, cv::Point((int)v[0], (int)v[1]), 6, Scalar(255, 0, 0), thickness, lineType);
	}

	imshow("img", img);
	imshow("image", image);
	waitKey(0);
}

SVM图像分割:待填坑

你可能感兴趣的:(OpenCV)