opencv C++ SVM模型训练与分类实现

最近想学习一下分类算法的内容,恰好opencv有SVM的函数,故先从这个下手。找了许多资料,发现要么是opencv2、3的,要么就没有具体实现代码,学习还是把代码与原理一起结合来看比较好。

其中,我主要参考的是这一篇文章:

opencv C++ SVM模型训练与分类实现

步骤一样.

一、数据准备

首先找到opencv库自带的digits图片,我的电脑上路径在:D:\app\opencv4.5.1\opencv\opencv\sources\samples\data\digits.png

然后在D盘建立如下文件夹:

opencv C++ SVM模型训练与分类实现

只需新建命名就好了,不用往里面放东西。接下来建立vs2019项目工程,新建源文件

opencv C++ SVM模型训练与分类实现

复制如下代码:

#include
#include
#include
#include
#include
#include
#include
#include
//#include
#include

using namespace std;
using namespace cv;

int main()
{
    char ad[128] = { 0 };
    int  filename = 0, filenum = 0;
    Mat img = imread("digits.png");
    Mat gray;
    cvtColor(img, gray, COLOR_BGR2GRAY);
    int b = 20;
    int m = gray.rows / b;   //原图为1000*2000
    int n = gray.cols / b;   //裁剪为5000个20*20的小图块

    for (int i = 0; i < m; i++)
    {
        int offsetRow = i * b;  //行上的偏移量
        if (i % 5 == 0 && i != 0)
        {
            filename++;
            filenum = 0;
        }
        for (int j = 0; j < n; j++)
        {
            int offsetCol = j * b; //列上的偏移量
            sprintf_s(ad, "D:\\data\\%d\\%d.jpg", filename, filenum++);
            //截取20*20的小块
            Mat tmp;
            gray(Range(offsetRow, offsetRow + b), Range(offsetCol, offsetCol + b)).copyTo(tmp);
            imwrite(ad, tmp);
        }
    }
    return 0;

}

运行结束后,在刚刚新建的文件夹中,0、1文件夹内各有500张分割好的图片。

opencv C++ SVM模型训练与分类实现

最后在test_image、train_image分别新建0、1文件夹。

把data\0中的0-399复制到data\test_image\0,399-499复制到data\train_image\0;

把data\1中的0-399复制到data\test_image\1,399-499复制到data\train_image\1。第一步完成。

--D&#xFF1A;
  --data
    --0
    --1
    --train_image
      --0&#xFF08;400&#x5F20;&#xFF09;
      --1&#xFF08;400&#x5F20;&#xFF09;
    --test_image
      --0&#xFF08;100&#x5F20;&#xFF09;
      --1&#xFF08;100&#x5F20;&#xFF09;

二、模型训练

再新建一个源文件:SVM模型训练.cpp,将第一步的SVM数据准备文件从项目中移除。

opencv C++ SVM模型训练与分类实现

复制上如下代码,其中最主要的就是opencv4中的SVM函数改变很大,配置参数上与原文完全不同

#include
#include
#include

#include
#include
#include
#include
#include "opencv2/imgcodecs.hpp"
#include
#include
#include

using namespace std;
using namespace cv;
using namespace cv::ml;

void getFiles(string path, vector& files);
void get_1(Mat& trainingImages, vector& trainingLabels);
void get_0(Mat& trainingImages, vector& trainingLabels);

int main()
{
    //获取训练数据
    Mat classes;
    Mat trainingData;
    Mat trainingImages;
    vector trainingLabels;
    get_1(trainingImages, trainingLabels);
    //waitKey(2000);
    get_0(trainingImages, trainingLabels);
    Mat(trainingImages).copyTo(trainingData);
    trainingData.convertTo(trainingData, CV_32FC1);
    Mat(trainingLabels).copyTo(classes);
    //配置SVM训练器参数
    Ptr svm = SVM::create();
    svm->setType(SVM::C_SVC);
    svm->setKernel(SVM::LINEAR);
    svm->setDegree(0);
    svm->setGamma(1);
    svm->setCoef0(0);
    svm->setC(1);
    svm->setNu(0);
    svm->setP(0);
    svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 1000, 0.01));
    //训练
    svm->train(trainingData, ROW_SAMPLE, classes );
    //保存模型
    svm->save("svm.xml");

    cout << "训练好了!!!" << endl;

    getchar();
    return 0;
}
void getFiles(string path, vector& files)
{
    long long  hFile = 0;
    struct _finddata_t fileinfo;
    string p;
    if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
    {
        do
        {
            if ((fileinfo.attrib & _A_SUBDIR))
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                    getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
            }
            else
            {
                files.push_back(p.assign(path).append("\\").append(fileinfo.name));
            }
        } while (_findnext(hFile, &fileinfo) == 0);

        _findclose(hFile);
    }
}

void get_1(Mat& trainingImages, vector& trainingLabels)
{
    string filePath = "D:\\data\\train_image\\1";
    cout << "获取D:\\data\\1" << endl;
    vector files;
    getFiles(filePath, files);
    int number = files.size();
    for (int i = 0; i < number; i++)
    {
        Mat  SrcImage = imread(files[i].c_str());
        SrcImage = SrcImage.reshape(1, 1);
        trainingImages.push_back(SrcImage);
        trainingLabels.push_back(1);
    }
}
void get_0(Mat& trainingImages, vector& trainingLabels)
{
    string filePath = "D:\\data\\train_image\\0";
    cout << "获取D:\\data\\0" << endl;
    vector files;
    getFiles(filePath, files);
    int number = files.size();
    for (int i = 0; i < number; i++)
    {
        Mat  SrcImage = imread(files[i].c_str());
        SrcImage = SrcImage.reshape(1, 1);
        trainingImages.push_back(SrcImage);

        trainingLabels.push_back(0);
    }
}

训练完毕后,在这个解决方案文件夹下就生成了一个.xml文件,即是我们训练出来的模型。

训练时还可以选择自动训练,会自己寻找最优参数,效果也很好。

//训练
    svm->trainAuto(trainingData, ROW_SAMPLE, classes );

三、加载模型实现分类

opencv C++ SVM模型训练与分类实现

复制如下代码:

#include
#include
#include

#include
#include
#include
#include
#include "opencv2/imgcodecs.hpp"
#include
#include
#include

using namespace std;
using namespace cv;
using namespace cv::ml;

void getFiles(string path, vector& files);
int main()
{
    int result = 0;
    string filePath = "D:\\data\\test_image\\1";
    vector files;
    getFiles(filePath, files);
    int number = files.size();
    cout << number << endl;
    string modelpath = "svm.xml";
    cv::Ptr svm;
    svm = cv::Algorithm::load(modelpath);

    /*CvSVM svm;
    svm.clear();
    string modelpath = "svm.xml";
    FileStorage svm_fs(modelpath, FileStorage::READ);
    if (svm_fs.isOpened())
    {
        svm.load(modelpath.c_str());
    }*/
    for (int i = 0; i < number; i++)
    {
        Mat inMat = imread(files[i].c_str());
        Mat p = inMat.reshape(1, 1);
        p.convertTo(p, CV_32FC1);
        int response = (int)svm->predict(p);
        if (response == 1)//要预测1,如果用0来做测试集就改成response == 0
        {
            result++;
        }
        else
        {
            cout << files[i] << endl;
        }
    }
    cout << result << endl;
    getchar();
    return  0;
}
void getFiles(string path, vector& files)
{
    long long   hFile = 0;
    struct _finddata_t fileinfo;
    string p;
    if ((hFile = _findfirst(p.assign(path).append("\\*").c_str(), &fileinfo)) != -1)
    {
        do
        {
            if ((fileinfo.attrib & _A_SUBDIR))
            {
                if (strcmp(fileinfo.name, ".") != 0 && strcmp(fileinfo.name, "..") != 0)
                    getFiles(p.assign(path).append("\\").append(fileinfo.name), files);
            }
            else
            {
                files.push_back(p.assign(path).append("\\").append(fileinfo.name));
            }
        } while (_findnext(hFile, &fileinfo) == 0);
        _findclose(hFile);
    }
}

如果想要检测0的分类准确率就让第46行的response == 0。

opencv C++ SVM模型训练与分类实现

可以看到,100张1有99张被识别出来,有一张452没有识别成功。100张0都识别出来了。

Original: https://blog.csdn.net/lixiaoweia/article/details/125258913
Author: lixiaoweia
Title: opencv C++ SVM模型训练与分类实现

原创文章受到原创版权保护。转载请注明出处:https://www.johngo689.com/637667/

转载文章受原作者版权保护。转载请注明原作者出处!

(0)

大家都在看

亲爱的 Coder【最近整理,可免费获取】👉 最新必读书单  | 👏 面试题下载  | 🌎 免费的AI知识星球