opencv::ml系列,支持向量机基础1.1

线性不可分情况下的支持向量机测试

本部分设置了线性不可分的训练集情况,采用不同类型的支持向量机核进行测试,由于opencv3的ml模块支持trainAuto,可以不必预先对核函数参数进行确定,大大提高了可用性。

代码如下

bool rbfSVMExample() {
	//支持向量机设置
	cv::Ptr<SVM> rbfSVM=SVM::create();
	rbfSVM->setType(SVM::C_SVC);
	rbfSVM->setKernel(SVM::RBF);
	//rbfSVM->setGamma(5);//设置rbf核参数
	//rbfSVM->setC(100);//设置惩罚因子

	rbfSVM->setTermCriteria(TermCriteria(TermCriteria::COUNT + TermCriteria::EPS,(int)1e7, 1e-6));
	//训练数据集
	const int width = 512, height = 512;
	int samplesNum = 100;//样本数
	float tPercent = 0.2;//正样本比例
	int tSampleNum = int(samplesNum * tPercent);
	Mat trainData(2 * samplesNum, 2, CV_32FC1);//32FC1
	Mat labelData(2 * samplesNum, 1, CV_32SC1);//32SC1
	RNG rng(unsigned(time(NULL)));//以当前系统时间为种子点,设置随机数生成器rng
	Mat trainClass = trainData.rowRange(0, tSampleNum);//ROI操作,左闭右开区间
	Mat c = trainClass.colRange(0, 1);
	rng.fill(c, RNG::UNIFORM, Scalar(width/3), Scalar(width*2/3));//采用均匀分布填充,范围为1/3-2/3宽度
	c = trainClass.colRange(1, 2);//坐标y
	rng.fill(c, RNG::UNIFORM, Scalar(height/3), Scalar(height*2/3));
	labelData.rowRange(0, tSampleNum).setTo(1);//将labelData的对应范围设置1
	//类2进行同样的处理
	trainClass = trainData.rowRange(tSampleNum,(samplesNum-tSampleNum)*1/4+tSampleNum);
	c = trainClass.colRange(0, 1);
	rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(width*2/3));
	c = trainClass.colRange(1, 2);
	rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(height*1/3));
	labelData.rowRange(tSampleNum, (samplesNum - tSampleNum) * 1 / 4 + tSampleNum).setTo(2);
	trainClass = trainData.rowRange((samplesNum-tSampleNum)*1/4+tSampleNum,(samplesNum - tSampleNum) * 2 / 4 + tSampleNum);
	c = trainClass.colRange(0, 1);
	rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(width * 1 / 3));
	c = trainClass.colRange(1, 2);
	rng.fill(c, RNG::UNIFORM, Scalar(height * 1 / 3), Scalar(height));
	labelData.rowRange((samplesNum - tSampleNum) * 1 / 4 + tSampleNum, (samplesNum - tSampleNum) * 2 / 4 + tSampleNum).setTo(2);
	trainClass = trainData.rowRange((samplesNum-tSampleNum)*2/4+tSampleNum,(samplesNum - tSampleNum) * 3 / 4 + tSampleNum);
	c = trainClass.colRange(0, 1);
	rng.fill(c, RNG::UNIFORM, Scalar(width * 1 / 3), Scalar(width));
	c = trainClass.colRange(1, 2);
	rng.fill(c, RNG::UNIFORM, Scalar(height * 2 / 3), Scalar(height));
	labelData.rowRange((samplesNum - tSampleNum) * 2 / 4 + tSampleNum, (samplesNum - tSampleNum) * 3 / 4 + tSampleNum).setTo(2);
	trainClass = trainData.rowRange((samplesNum-tSampleNum)*3/4+tSampleNum, samplesNum);
	c = trainClass.colRange(0, 1);
	rng.fill(c, RNG::UNIFORM, Scalar(width * 2 / 3), Scalar(width));
	c = trainClass.colRange(1, 2);
	rng.fill(c, RNG::UNIFORM, Scalar(1), Scalar(height * 2 / 3));
	labelData.rowRange((samplesNum-tSampleNum)*3/4+tSampleNum,samplesNum).setTo(2);

	//整理样本
	Ptr<TrainData> tData = TrainData::create(trainData, ROW_SAMPLE, labelData);

	//训练SVM
	cout << "开始训练" << endl;
	rbfSVM->trainAuto(tData);//自动确定rbf模型参数
	cout << "结束训练" << endl;
		cout << "C" <<rbfSVM->getC()<< endl;
			cout << "Gamma" <<rbfSVM->getGamma()<< endl;
	//显示训练分区
	Vec3b green1(0, 100, 0), blue1(100, 0, 0);
	Mat imgShow = Mat::zeros(height, width, CV_8UC3);
	for (int i = 0; i < imgShow.rows; ++i)    // 遍历画布上的每个点
	{//妙啊
		for (int j = 0; j < imgShow.cols; ++j)
		{
			cv::Mat SampleMat = (cv::Mat_<float>(1, 2) << j, i);//遍历并预测所有像素点
			auto Response = rbfSVM->predict(SampleMat);
			if (Response == 1)
			{
				imgShow.at<cv::Vec3b>(i, j) = green1;
			}
			else if (Response==2)
			{
				imgShow.at<cv::Vec3b>(i, j) = blue1;
			}
			//SVM默认将类别分为+1和-1
		}
	}
	// 在画布上画上训练数据所表示的点
	int Thinckness = -1;
	float px, py;
	for (int i = 0; i < tSampleNum; i++) {
		px = trainData.at<float>(i, 0);
		py = trainData.at<float>(i, 1);
		circle(imgShow, Point((int)px, (int)py),2,Scalar(0,255,0));
	}
	for (int i = tSampleNum; i < samplesNum; i++) {
		px = trainData.at<float>(i, 0);
		py = trainData.at<float>(i, 1);
		circle(imgShow, Point((int)px, (int)py), 2, Scalar(255, 0, 0));
	}

	Thinckness = 2;
	//显示支持向量,rbf模式下好像显示不了...不显示支持向量了?
	Mat supportVectors = rbfSVM->getUncompressedSupportVectors();//获取未压缩支持向量
	for (int i = 0; i < supportVectors.rows; i++) {//注意是<rows
		auto vecTmp = supportVectors.ptr<float>(i);//读取supportVectors Mat中第i个数据坐标,数据类型为float(?),因为样本label给的是32FC1,也就是32bit的float,channel1,所以支持向量也是float格式
		//??auto换成float*反而变卡了
		cv::circle(imgShow, Point(static_cast<int>(vecTmp[0]), static_cast<int>(vecTmp[1])), 6, Scalar(128, 128, 128), Thinckness);
	}
	cv::imshow("svmExample", imgShow);
	cv::waitKey();

	return true;
}

trainAuto()

貌似trainAuto只能正确地得出LINEAR、RBF和INTER,POLY要预先设定参数,SIGMOID也不行,CHI2不能进行分类

在这里插入图片描述
3. Poly核不能直接trainAuto出来;
4. INTER核
在这里插入图片描述

多类型分类

对应修改对应测试样本集标签序号即可;

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值