1. SVM:support vector machine支持向量机
2. 头文件:#inlcude “opencv/ml.hpp”
具体用法,见opencv官方注释;
3. svm可用于目标分类,简单实例如下:
目的:去掉图中背景,提取蔬菜区域。
#include <iostream>
#include <opencv2/opencv.hpp>
#pragma comment(lib,"opencv_world341.lib")
using namespace cv;
using namespace std;
using namespace cv::ml;
//正负样本转换标志
//当为true时,标注正样本点
//当为false时,标注负样本点
bool flag = true;
string wdname = "image";
Mat img, image;
Mat targetData, backData;
//鼠标左键标记样本点
//按c键切换正负样本,按esc键生成训练样本数据,按q键退出
void on_mouse(int event, int x, int y, int flags, void* ustc)
{
if (event == CV_EVENT_LBUTTONDOWN)
{
Point pt = Point(x, y);
Vec3b point = img.at<Vec3b>(y, x); //取出该坐标处的像素值
Mat tmp = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
if (flag)
{
targetData.push_back(tmp); //加入正样本矩阵
circle(img, pt, 2, Scalar(0, 255, 255), -1, 8);
}
else
{
backData.push_back(tmp); //加入负样本矩阵
circle(img, pt, 2, Scalar(255, 0, 0), -1, 8);
}
imshow(wdname, img);
}
}
//生成训练数据
void getTrainData(Mat& train_data, Mat& train_label)
{
int m = targetData.rows;
int n = backData.rows;
cout << "正样本数量::" << m << endl;
cout << "负样本数量:" << n << endl;
vconcat(targetData, backData, train_data); //合并所有的样本点,作为训练数据
train_label = Mat(m + n, 1, CV_32S, Scalar::all(1)); //初始化标注
for (int i = m; i < m + n; i++)
train_label.at<int>(i, 0) = -1;
}
//svm分类
void svm()
{
Mat train_data, train_label;
getTrainData(train_data, train_label); //获取鼠标选择的样本训练数据
// 设置参数
Ptr<SVM> svm = SVM::create();
svm->setType(SVM::C_SVC);
svm->setKernel(SVM::LINEAR);
//训练分类器
Ptr<TrainData> tData = TrainData::create(train_data, ROW_SAMPLE, train_label);
svm->train(tData);
Vec3b color(0, 0, 0);
//Show the decision regions given by the SVM
//遍历图像像素
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
Vec3b point = img.at<Vec3b>(i, j);
Mat sampleMat = (Mat_<float>(1, 3) << point[0], point[1], point[2]);
float response = svm->predict(sampleMat); //进行预测,返回1或-1,返回类型为float
if ((int)response != 1)
image.at<Vec3b>(i, j) = color; //将背景设置为黑色
}
imshow("SVM Simple Example", image);
waitKey(0);
}
int main()
{
img = imread("C:\\Users\\Administrator\\Desktop\\peppers.png");
img.copyTo(image);
namedWindow(wdname);
setMouseCallback(wdname, on_mouse, 0);
for (;;)
{
imshow("image", img);
int c = waitKey(0);
if ((c & 255) == 27)
{
cout << "Exiting ...\n";
break;
}
if ((char)c == 'c')
{
flag = false;//切换正负样本
}
if ((char)c == 'q')
{
destroyAllWindows();
break;
}
}
svm();
return 0;
}
步骤:
s1. 先点击鼠标左键标注正样本数据;
s2. 按c键切换,标注负样本数据;
s3. 按esc键,进行分类;
4. svm的使用方法
4.1 载入训练数据,生成训练模型
4.2 设置分类参数,生成分类器,传入测试集,进行预测
4.3 示例如下:
#include <opencv2/opencv.hpp>
#include <iostream>
#pragma comment(lib,"opencv_world341.lib")
using namespace cv;
using namespace cv::ml;
int main()
{
int width = 512, height = 512;
Mat image = Mat::zeros(height, width, CV_8UC3);
//s1.载入训练数据,生成训练模型
//训练数据
float trainingData[10][2] = { { 501, 150 },{ 255, 10 },{ 501, 255 },{ 10, 501 },{ 25, 80 },
{ 150, 300 },{ 77, 200 } ,{ 300, 300 } ,{ 45, 250 } ,{ 200, 200 } };
Mat trainingDataMat(10, 2, CV_32FC1, trainingData);
//训练标签,1 -1 两个标签
int labels[10] = { 1, -1, 1, 1, -1, 1, -1, 1, -1, -1 };
Mat labelsMat(10, 1, CV_32SC1, labels);//10行1列
//设置训练数据
Ptr<TrainData> tData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelsMat);
//显示训练数据
int thickness = -1;
int lineType = 8;
Scalar c1 = Scalar::all(0); //标记为1的显示成黑点
Scalar c2 = Scalar::all(255); //标记成-1的显示成白点
for (int i = 0; i < labelsMat.rows; i++)
{
const float* v = trainingDataMat.ptr<float>(i);
Point pt = Point((int)v[0], (int)v[1]);
if (labels[i] == 1)
circle(image, pt, 5, Scalar(0,255,0), -1, 8);
else
circle(image, pt, 5, Scalar(255,0,0), -1, 8);
}
imshow("train data", image);
waitKey(0);
//s2. 生成分类器,设置分类参数,输入测试数据进行预测
// 创建分类器并设置参数
Ptr<SVM> model = SVM::create();
model->setType(SVM::C_SVC);
model->setKernel(SVM::LINEAR); //核函数
// 训练分类器
model->train(tData);
Vec3b green(0, 255, 0), blue(255, 0, 0);
// Show the decision regions given by the SVM
for (int i = 0; i < image.rows; ++i)
for (int j = 0; j < image.cols; ++j)
{
//测试数据,点位(x,y)
Mat sampleMat = (Mat_<float>(1, 2) << j, i);
//进行预测,返回1或-1
float response = model->predict(sampleMat);
if (response == 1)
image.at<Vec3b>(i, j) = green;
else if (response == -1)
image.at<Vec3b>(i, j) = blue;
}
imshow("SVM test", image);
waitKey(0);
}
参考文章
1. https://www.cnblogs.com/denny402/p/5020551.html
2. https://www.cnblogs.com/denny402/p/5019233.html
3. https://docs.opencv.org/3.4.1/d1/d2d/classcv_1_1ml_1_1SVM.html opencv官方文档