关闭

【OpenCV3.3】SVM与字符分类示例

标签: opencvc++svm
9109人阅读 评论(0) 收藏 举报
分类:

        SVM,全称Support Vector Machine,即支持向量机,是机器学习中常用的分类器(同样支持向量回归),属监督式学习的一种。

        在二值分类中,SVM通过寻找一个 决策最优分类超平面 来尽可能地将两类样本分开(最大分类间隔)并作为分类的判据,以期得到较强的泛化能力,我们所指的训练(train)主要就是寻找这个超平面。如果你看过相关推导,会发现原本复杂的问题被一步步等价,引入拉格朗日继而巧妙的转到凸优化及对偶问题的求解上,数学的力量令人叹为观止。

        一般而言SVM是二值分类器,但是我们可以通过增加多个分类器来完成N分类,自然如何组织这些分类器也是一个优化问题。目前存在的多类判别方法有1-V-R、1-V-1、有向无环图(DAG-SVMS)、决策树方法、纠错输出编码法(ECOC)等。

        OpenCV的SVM实现基于LIBSVM v2.6,而目前 LIBSVM 的最新版本是3.22,所以如果你深度依赖于SVM,建议使用LIBSVM,相比OpenCV其无论从更新频度还是支持范围都有较大优势,值得注意的是两者还是有些细微差别,不能无缝迁移。

        下面是一个SVM字符分类示例:

#include "stdafx.h"
#define DATA_DIR "D:\\OpenCV\\bin\\toy_data\\"

//-------------------------------------------------------------------------

INT WINAPI WinMain(_In_ HINSTANCE, _In_opt_ HINSTANCE, _In_ LPSTR, _In_ INT)
{
	cv::ipp::setUseIPP(true);

	// 如果SVM模型数据svm.txt存在,则从文件读取;否则加载训练数据进行训练
	cv::Ptr<cv::ml::SVM> &&svm = cv::ml::SVM::create();
	cv::FileStorage cf(DATA_DIR "svm.txt", cv::FileStorage::READ);
	if (cf.isOpened()) {
//		svm = svm->load(DIR "svm.txt");
		svm->read(cf.getFirstTopLevelNode());
		cf.release();
	} else {
		// 加载训练数据,DATA_DIR目录下所有的 [0-9][a-z].png
		cv::Mat sample;
		cv::Mat label(cv::Size(0, 0), CV_32SC1); // 注意这里和2.x区别,3.x必须使用CV_32S,原因后面会说
		char filename[] = { DATA_DIR "$$.png" };
		char *varchar = strchr(filename, '$');
		for (char num = '0'; num <= '9'; ++num) {
			varchar[0] = num;
			for (char alpha = 'a'; alpha < 'z'; ++alpha) {
				varchar[1] = alpha;

				cv::Mat &&img = cv::imread(filename, cv::IMREAD_GRAYSCALE);
				if (img.dims > 0) {
					// 归一化, 一般认为能加快参数优化时的收敛速度、平衡模型权重等
					cv::normalize(img, img, 1., 0., cv::NormTypes::NORM_MINMAX, CV_32FC1);
					// 但如果你的数据量级本身相差不大,也可以不归一化直接convertTo即可
					//img.convertTo(img, CV_32FC1);
					sample.push_back(img.reshape(0, 1));
					label.push_back<int>(num); // 注意push_back有模版重载,可能意外改变Mat类型
				} //if
			} //for
		} //for
		cv::Ptr<cv::ml::TrainData> &&trainDataSet = cv::ml::TrainData::create(sample, cv::ml::ROW_SAMPLE, label);

		// 设置参数,仅作为示例
// 		svm->setType(cv::ml::SVM::C_SVC);
// 		svm->setKernel(cv::ml::SVM::LINEAR);
// 		svm->setC(0.01);
// 		svm->setTermCriteria(cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 1000, FLT_EPSILON));
// 		svm->train(trainDataSet);

		// 有时候会出现过拟合、欠拟合现象,排除训练数据影响的情况下一般就是参数问题了,可以使用trainAuto来进行参数优化
		svm->trainAuto(trainDataSet);
		// 如果想让部分参数不进行优化,可以使用*cv::ml::ParamGrid::create(0, 0, 0)代替相应Grid默认值,如下不对C进行优化:
		//svm->trainAuto(trainDataSet, 10, *cv::ml::ParamGrid::create(0, 0, 0));

		svm->save(DATA_DIR "svm.txt");
	} //if

	cv::Mat &&tk = cv::imread(DATA_DIR "9b.png", cv::IMREAD_GRAYSCALE); 
	cv::normalize(tk, tk, 1., 0., cv::NormTypes::NORM_MINMAX, CV_32FC1);
//	tk.convertTo(tk, CV_32FC1);

	float r  = svm->predict(tk.reshape(0, 1));
	char c[] = { static_cast<char>(r), 0 };
	OutputDebugStringA(c);

	return 0;
}

        上述程序运行后会在IDE调试窗口输出9。我的部分训练数据如下(来自MSPAINT,每个样本都是8x8的二值图像):

        代码中提到标签类型在3.x版本应该使用CV_32S(OpenCV 2.x版本使用CV_32F),否则会产生错误,文档没有提及原因,但看了模块源码,似乎是有意的`bug`:当模型使用C_SVC或NU_SVC,并且标签、样本数量一致时 ,label使用CV_32FC1会出现错误,原因是C_SVC会使用TrainData::getTrainNormCatResponses,而normCatResponses是空的(未被初始化),因为\modules\ml\src\data.cpp第320行

if( noutputvars == 1 )
    varType.at<uchar>(ninputvars) = (uchar)(responses.type() < CV_32F ? VAR_CATEGORICAL : VAR_ORDERED);
        此时CV_32F会导致打上VAR_ORDERED标志,从而在第406行跳过了preprocessCategorical对normCatResponses的处理
if( noutputvars > 0 && varType.at<uchar>(ninputvars) == VAR_CATEGORICAL )
{
    preprocessCategorical(responses, &normCatResponses, labels, &counters, sortbuf);
    Mat(labels).copyTo(classLabels);
    Mat(counters).copyTo(classCounters);
}
        从而导致断言data != NULL失败。




0
0
查看评论

OpenCV3.0或OpenCV3.1的SVM操作

OpenCV2.0 SVM代码及其分析OpenCV 在很久以前就集成了SVM的功能,现在OpenCV升级到了3.0和3.1了,很多人都不习惯了怎么调用OpenCV中的SVM功能了。在之前OpenCV的SVM调用一直有个案例:首先,给定几组训练数据,并且给了label所对应的值。然后经过训练之后,对图...
  • wfh2015
  • wfh2015
  • 2016-04-15 18:33
  • 9195

opencv3 SVM

#include #include #include using namespace cv; using namespace cv::ml; void main() { Mat img = Mat::zeros(Size(600, 600), CV_8UC3); int lables[8] =...
  • lcc_633
  • lcc_633
  • 2016-09-27 22:04
  • 595

【OpenCV3】HOG+SVM目标识别

SVM,即支持向量机,在结合相关特征描述子之后,在目标识别,如行人识别、汽车识别、人脸识别等领域中有着重要应用。opencv中提供了HOG特征描述子,这种特征提供支持SVM的接口。这不再进行原理性的介绍,直接介绍如何使用opencv进行SVM训练和检测。
  • guduruyu
  • guduruyu
  • 2017-04-15 15:45
  • 6651

SVM多分类器的实现(Opencv3,C++)

SVM多分类器的Opencv实现
  • zmdsjtu
  • zmdsjtu
  • 2016-12-13 15:44
  • 6501

模式识别之(一)SVM的opencv3.0实现

主要是opencv3对于svm的参数设置,以及mnist手写数据集的实现
  • xuan_zizizi
  • xuan_zizizi
  • 2017-05-02 20:39
  • 1842

opencv 学习之 SVM / ANN 图片分类(OPENCV3.2)

图片分类,VS2017 + OPENCV3.2 图片分两类,正负样本。最后一组测试。 速度较慢。可能图片太大。540*360.
  • u010477528
  • u010477528
  • 2017-09-06 10:34
  • 1165

在opencv3中利用SVM进行图像目标检测和分类

采用鼠标事件,手动选择样本点,包括目标样本和背景样本。组成训练数据进行训练 1、主函数 #include "stdafx.h" #include "opencv2/opencv.hpp" using namespace cv; using name...
  • roslei
  • roslei
  • 2017-03-02 11:02
  • 1111

OpenCv3.0+SVM的使用心得(一)

1.open cv3.0版本中没有了CvSVM类的定义,而是将其写入到一个document中,但是使用也并不复杂,代码示例如下:ml::SVM::Params params; params.svmType = ml::SVM::C_SVC; params.kernelType = ml::SVM::...
  • u010869312
  • u010869312
  • 2015-04-07 23:09
  • 13154

opencv3.0-支持向量机(svm)使用介绍

这篇文章翻译opencv官网关于opencv3.0 svm的使用介绍
  • wuliangj
  • wuliangj
  • 2016-08-13 17:46
  • 2836

OpenCV3.0 HOG+SVM行人检测器

介绍什么的请参考:利用Hog特征和SVM分类器进行行人检测我只说一下Opencv3.0里面,需要注意的地方。 本人接触OpenCV很短的时间,新手。OpenCV3.0相比2.X,接口更加清晰,还是有很大的改动的。 主要有几个需要注意的地方: 1. sampleLabelMat的数据类型必须为有...
  • iamzhangzhuping
  • iamzhangzhuping
  • 2016-04-26 21:49
  • 5173
    联系作者
    通过QQ与我联系(全天候7*24小时基本不在线)
    最新评论
    免责声明
    如果转载的文章侵犯了您的版权,请务必告知,我将立刻删除;
    博客所有文章允许转载,原创类不要求注明出处,随意就好;
    如果是转载的文章,建议直接转载原始来源,因为原作者极可能有更新