opencv3使用svm+hog训练数字

先暂时把opencv3的具有参考价值的文章放一下:
1、主要参考这个文章,但是他的是opencv2 文章名称: 使用 svm+hog 训练,检测手写数字:https://blog.csdn.net/weixin_37721518/article/details/74187127
2、这个是opencv3的,部分参考这个,也理解了一些参数如何修改https://blog.csdn.net/almost_miao/article/details/79115939
3、opencv3的https://blog.csdn.net/u014774106/article/details/60763660
4、https://blog.csdn.net/wang382758656/article/details/52723674
5、https://blog.csdn.net/rrrfff/article/details/76796341
6、http://www.cnblogs.com/tornadomeet/archive/2012/08/15/2640754.html
7、https://blog.csdn.net/u010869312/article/details/44927721
8】https://blog.csdn.net/iamzhangzhuping/article/details/51254567

我修改成功的训练代码

/**********************************************************************
2018.5.23:SVM训练  //在  配置SVM训练器参数CvSVMParams SVM_params;这里有问题
2018.5.25:1、因为例程是opencv2的,opencv3里的svm的一些声明格式有了些许变化,修改了
           2、批量读取图片出现错误,原来是一个参数变量出现错误,说明警告也可能造成致命错误
2018.05.31: 之前的svm训练只是二分类,而且特征提取是简单的像素值特征,现在训0-9的数字,且hog特征

***************************************************************/

#include "opencv2/opencv.hpp"  
#include <opencv2/objdetect/objdetect.hpp>  //hog特征的c文件
#include <opencv/cv.h>  
#include <iostream> 
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/imgproc/imgproc.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <io.h> //查找文件相关函数
#include <stdio.h>  
#include <time.h>  //测试程序运行时间
#include "windows.h"  
#include "fstream" 

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



int main()
{

    ////检测窗口(128,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9  
    //HOGDescriptor hog(Size(128, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);

    ////HOG检测器,用来计算HOG描述子的  
    //int DescriptorDim;//HOG描述子的维数,由图片大小、检测窗口大小、块大小、细胞单元中直方图bin个数决定  

    //Mat sampleFeatureMat;//所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数  
    //Mat sampleLabelMat;//训练样本的类别向量,行数等于所有样本的个数,列数等于1;1表示有人,-1表示无人  
    Mat classes;
    vector<string> img_path;//输入文件名变量     
    vector<int> img_catg;
    int nLine = 0;
    string buf;

    ifstream svm_data("E:/OCR_Recognition/opencv_project/SVM_train_data/hb.txt");//训练样本图片的路径都写在这个txt文件中,使用bat批处理文件可以得到这个txt文件       
    unsigned long n;
    while (svm_data)//将训练样本文件依次读取进来      
    {
        if (getline(svm_data, buf))
        {
            nLine++;
            if (nLine % 2 == 0)//注:奇数行是图片全路径,偶数行是标签   
            {
                img_catg.push_back(atoi(buf.c_str()));//atoi将字符串转换成整型,标志(0,1,2,...,9),注意这里至少要有两个类别,否则会出错      
            }
            else
            {
                img_path.push_back(buf);//图像路径      
            }
        }
    }
    svm_data.close();//关闭文件      

    Mat data_mat, labels_mat;
   int  nImgNum = nLine / 2; //nImgNum是样本数量,只有文本行数的一半,另一半是标签    
   cout << " 共有样本个数为: " << nImgNum << endl;
    //data_mat为所有训练样本的特征向量组成的矩阵,行数等于所有样本的个数,列数等于HOG描述子维数
    data_mat =Mat::zeros(nImgNum, 324, CV_32FC1);  //行、列、类型;第二个参数,即矩阵的列是由下面的descriptors的大小决定的,可以由descriptors.size()得到,且对于不同大小的输入训练图片,这个值是不同的    

    //类型矩阵,存储每个样本的类型标志      
    //labels_mat为训练样本的类别向量,行数等于所有样本的个数,列数等于1;暂时,后面会修改,比如样本0,就为0,样本1就为1
    labels_mat = Mat::zeros(nImgNum, 1, CV_32SC1);


    Mat src;
    Mat trainImg = Mat(Size(28, 28), CV_8UC3);//需要分析的图片,这里默认设定图片是28*28大小,所以上面定义了324,如果要更改图片大小,可以先用debug查看一下descriptors是多少,然后设定好再运行      

    //处理HOG特征    
    for (string::size_type i = 0; i != img_path.size(); i++)
    {
        cout << " \n第 " << i << "  次循环\n" << endl;
        src = imread(img_path[i].c_str(),1);
        if (src.empty())
        {
            cout << " can not load the image: " << img_path[i].c_str() << endl;
            continue;
        }

        cout << " 处理: " << img_path[i].c_str() << endl;

        resize(src, trainImg, trainImg.size());


        //检测窗口(64,128),块尺寸(16,16),块步长(8,8),cell尺寸(8,8),直方图bin个数9  ,需要修改
        HOGDescriptor *hog = new HOGDescriptor(Size(28, 28), Size(14, 14), Size(7, 7), Size(7, 7), 9);
        vector<float>descriptors;//存放结果    为HOG描述子向量    
        hog->compute(trainImg, descriptors, Size(1, 1), Size(0, 0)); //Hog特征计算,检测窗口移动步长(1,1)     

        cout << "HOG描述子向量个数    : " << descriptors.size() << endl;

        n = 0;
      int    number = descriptors.size();
        //将计算好的HOG描述子复制到样本特征矩阵data_mat  
        for (int i = 0; i < number; i++)
        {

            data_mat.at<float>(i, n) = descriptors[i];//第1个样本的特征向量中的第n个元素  
            n++;
        }

        labels_mat.at<int>(i, 0) = img_catg[i];
        cout << " 处理完毕: " << img_path[i].c_str() << " " << img_catg[i] << endl;
    }

    Mat(labels_mat).copyTo(classes);


        // 创建分类器并设置参数
        Ptr<SVM> SVM_params = SVM::create();
        SVM_params->setType(SVM::C_SVC);
        SVM_params->setKernel(SVM::RBF);  //核函数,后期重点分析的地方  SVM::RBF为径向基(RBF)核函数(高斯核函数)

        SVM_params->setDegree(10.0);
        SVM_params->setGamma(0.09);
        SVM_params->setCoef0(1.0);
        SVM_params->setC(10.0);
        SVM_params->setNu(0.5);
        SVM_params->setP(1.0);
        SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));


        Mat labelMat1(labels_mat.rows, labels_mat.cols, CV_32SC1);
        for (int i = 0; i < labels_mat.rows; i++)
        {
            for (int j = 0; j < labels_mat.cols; j++)
            {
                labelMat1.at<int>(i, j) = labels_mat.at<float>(i, j);
            }
        }
                cout << "开始训练..." << endl;

                Ptr<TrainData> traindata = ml::TrainData::create(data_mat, ROW_SAMPLE, classes);
        // 训练分类器
        SVM_params->train(traindata);
        //保存模型
        SVM_params->save("svm.xml");
        cout << "训练好了!!!" << endl;

这段代码,我要说以下几个关键点
1、resize(src, trainImg, trainImg.size());需要把读取进来的图片调整尺寸大小,不然hog描述子向量需要重新修改一下,等于descriptors.size()

2、原来的函数 cvmSet(data_mat,i,n,*iter);在opencv3里没有,但是可以改成

      int    number = descriptors.size();
        //将计算好的HOG描述子复制到样本特征矩阵data_mat  
        for (int i = 0; i < number; i++)
        {

            data_mat.at<float>(i, n) = descriptors[i];//第i个样本的特征向量中的第n个元素  
            n++;
        }

关键要知道n和i所代表意思,n代表hog描述子的元素,i代表第几个样本

猜你喜欢

转载自blog.csdn.net/mao_hui_fei/article/details/80531261