opencv::ml::svm,线性分类器示例
代码如下,该代码采用线性内核,根据示例的四个训练样本集训练分类器,并以此为基础将图像坐标各点作为待测试点
bool svmBasicExample() {
Ptr<SVM> svm = SVM::create();//
svm->setType(SVM::C_SVC);//类型,
svm->setKernel(SVM::LINEAR);//核函数类型,注意其他核函数需要对应地进行参数设置
//svm->setC(0.5);
//svm->setGamma(1);//Exp,RBF核参数
//算法终止条件,设置迭代终止条件
svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 100, 1e-6));//一般包括误差条件和迭代次数
//训练样本特征
float trainingData[4][2]{//4个2维样本
{501,10},{255,10},{501,255},{10,501}
};
Mat trainingDataMat(4, 2, CV_32FC1, trainingData);//样本数据必须存储为CV_32FC1类型,opencv3版本特点
//标签
int labels[4] = { 1.0,-1.0,-1.0,-1.0 };//opencv3的label从float调整为了int,否则会导致分类结果为无穷大
Mat labelMat(4, 1, CV_32SC1, labels);
//标签数据必须存储为CV_32SC1类型,opencv3从int转换
Ptr<TrainData> tData = TrainData::create(trainingDataMat, ROW_SAMPLE, labelMat);
//训练/保存/加载
svm->train(tData);//训练
//二维样本可显示
constexpr int width = 512, height = 512;//constexpr,编译阶段可求值表达式
cv::Mat imgShow = cv::Mat::zeros(height, width, CV_8UC3);
const cv::Vec3b Green(0, 255, 0), Blue(255, 0, 0);
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 = svm->predict(SampleMat);
//需要注意,如果label没有转化为int类型,会导致预测结果类型问题
if (Response == 1)
{
imgShow.at<cv::Vec3b>(i, j) = Green;
}
else if (Response == -1)
{
imgShow.at<cv::Vec3b>(i, j) = Blue;
}
//SVM默认将类别分为+1和-1
}
}
// 标记训练点
int Thinckness = -1;
cv::circle(imgShow, cv::Point(501, 10), 5, cv::Scalar(0, 0, 0), Thinckness);
cv::circle(imgShow, cv::Point(255, 10), 5, cv::Scalar(255, 255, 255), Thinckness);
cv::circle(imgShow, cv::Point(501, 255), 5, cv::Scalar(255, 255, 255), Thinckness);
cv::circle(imgShow, cv::Point(10, 501), 5, cv::Scalar(255, 255, 255), Thinckness);
Thinckness = 2;
//标记采用的支持向量
Mat supportVectors = svm->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格式
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;
}
部分函数补充说明:
setType参数:
enum Types {
C_SVC=100,//C_SVC,允许部分离群点,使用惩罚系数C进行约束;
NU_SVC=101,//C_SVC的替代,nu在0-1之间nu_svc比c_svc更难于优化,且运行时间无法与c_svc相比;
ONE_CLASS=102,//分布估计,单类样本最小超球面拟合
EPS_SVR=103,//支持向量回归
NU_SVR=104,//使用nu替代p
};
setKernel参数:
enum KernelTypes {
CUSTOM=-1,//若存在自定义核,则返回自定义核
LINEAR=0,//线性分类或回归
POLY=1,//多项式核
RBF=2,//RBF核,径向基函数高斯核,多数情况下最优
SIGMOID=3,//sigmoid核,
CHI2=4,//Chi2核,类似RBF核,
INTER=5,//直方图交叉核
};
svm->setGamma(1);//默认1,POLY/RBF/SIGMOID/CHI2
svm->setC(1);//设置惩罚因子C,C_SVC/SVR,默认0
svm->setDegree(0);//POLY核参数,默认0
svm->setCoef0(1);//sigmoid/poly
svm->setNu(0.5);//nu_SVC/nu_SVR/one_class
svm->setP(0);//EPS_SVR
迭代终止条件
class CV_EXPORTS TermCriteria
{
public:
enum Type,终止条件类型,COUNT计次/EPS迭代算法所要求的精度或参数的变化
{
COUNT=1,
MAX_ITER=COUNT, //同上
EPS=2 //!< the desired accuracy or change in parameters at which the iterative algorithm stops
};
//默认构造函数
TermCriteria();//TermCriteria(0,0,0)
/**
@param type The type of termination criteria, one of TermCriteria::Type
@param maxCount The maximum number of iterations or elements to compute.
@param epsilon The desired accuracy or change in parameters at which the iterative algorithm stops.
*/
TermCriteria(int type, int maxCount, double epsilon);
int type; //!< the type of termination criteria: COUNT, EPS or COUNT + EPS
int maxCount; //!< the maximum number of iterations/elements
double epsilon; //!< the desired accuracy
};