#include <iostream>
#include <opencv2/opencv.hpp>  //头文件
#include <stdio.h>  
#include <time.h>  
#include <opencv2/core/core.hpp>  
#include <opencv2/highgui/highgui.hpp>  
#include <opencv2/ml/ml.hpp>  
#include <io.h> //查找文件相关函数

using namespace cv::ml;
using namespace cv;  //包含cv命名空间
using namespace std;

void getFiles(string path, vector<string>& files);
//void getBubble(Mat& trainingImages, vector<int>& trainingLabels);
//void getNoBubble(Mat& trainingImages, vector<int>& trainingLabels);
//获取正样本
void getPositive(Mat& trainingImages, vector<int>& trainingLabels);
//获取负样本
void getNegative(Mat& trainingImages, vector<int>& trainingLabels);
Mat detector_HOG(Mat image)
{
    HOGDescriptor *hog = new HOGDescriptor(cvSize(64, 64), cvSize(16, 16), cvSize(8, 8), cvSize(8, 8), 9);

    Mat featureMat;
    vector<float> descriptors;
    hog->compute(image, descriptors, Size(1, 1));
    featureMat = Mat::zeros(1, descriptors.size(), CV_32FC1);

    for (int j = 0; j < descriptors.size(); j++)
    {
        featureMat.at<float>(0, j) = descriptors[j];
    }
    return featureMat;
}

int main() {

    Mat classes;
    Mat trainingData;
    Mat trainingImages;

    vector<int> trainingLabels;
    getPositive(trainingImages, trainingLabels);
    getNegative(trainingImages, trainingLabels);

    Mat(trainingImages).copyTo(trainingData);
    trainingData.convertTo(trainingData, CV_32FC1);
    Mat(trainingLabels).copyTo(classes);

    // 创建分类器并设置参数
    Ptr<SVM> SVM_params = SVM::create();
    SVM_params->setType(SVM::C_SVC);
    SVM_params->setKernel(SVM::LINEAR);  //核函数

    SVM_params->setDegree(0);
    SVM_params->setGamma(1);
    SVM_params->setCoef0(0);
    SVM_params->setC(1);
    SVM_params->setNu(0);
    SVM_params->setP(0);
    SVM_params->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000, 0.01));
    cout << "start" << endl;

    Ptr<TrainData> tData = TrainData::create(trainingData, ROW_SAMPLE, classes);

    // 训练分类器
    clock_t start, end;
    start = clock();
    SVM_params->train(tData);
    end = clock();

    cout << (float)(end - start) / CLOCKS_PER_SEC << "s" << endl;
    //保存模型
    SVM_params->save("svm_hog_726_2.xml"); //svm模型存放路径
    cout << "训练好了!!!" << endl;
    getchar();
    return 0;

}


void getFiles(string path, vector<string>& 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 getPositive(Mat& trainingImages, vector<int>& trainingLabels)
{

    string filePath = ".\\1";; //正样本路径
    vector<string> files;
    getFiles(filePath, files);

    int number = files.size();
    for (int i = 0; i < number; i++)
    {
        Mat  image = imread(files[i], 0);//读入灰度图
        Mat SrcImage;
        equalizeHist(image, SrcImage);//直方图均衡
        resize(image, image, Size(64, 64));

        Mat  hogFeactureMat = detector_HOG(image);

        if (!hogFeactureMat.empty()) {
            trainingImages.push_back(hogFeactureMat);
            trainingLabels.push_back(1);
        }

        
    }

    cout << "positive  ok" << endl;
}
//获取负样本
void getNegative(Mat& trainingImages, vector<int>& trainingLabels)
{

    string filePath = ".\\0"; //负样本路径
    vector<string> files;
    getFiles(filePath, files);
    int number = files.size();
    for (int i = 0; i < number; i++)
    {
        Mat  image = imread(files[i], 0);
        equalizeHist(image, image);
        resize(image, image, Size(64, 64));

        Mat  hogFeactureMat = detector_HOG(image);
        if (!hogFeactureMat.empty()) {
            trainingImages.push_back(hogFeactureMat);
            trainingLabels.push_back(0);
        }
        cout << "remain   " << (number - i) << "    count:  " << i << endl;
    }

    cout << "negative  ok" << endl;

}