HOG+SVM 行人檢測

任務:做一個簡單的分類模型 用HOG+SVM 行人檢測 網上自己找開源代碼 這個代碼CPU可以訓練 掌握數據集制作的過程 訓練的過程 先不深究算法原理

一、基本介紹

基本思路就是從數據集讀入正負樣本,提取HOG特征,送入SVM訓練。
對數據集的處理包括負樣本的提取,正樣本的縮放,以及難例的獲取。

二、成果展示

剛開始樣本數量比較少且沒有加入難例訓練時,訓練效果不是很好。




增加了一些數據后,識別效果up!



加入難例訓練之后,效果更好了


三、基本原理

行人檢測: HOG + SVM
HOG:一種用來進行物體檢測的特征描述子。HOG特征通過計算和統計圖像局部區域的梯度方向直方圖來構成特征.
SVM: (Support Vector Machine)指的是支持向量機,是常見的一種判別方法。在行人檢測中可以用作區分行人和非行人的分類器。

hog的使用:https://blog.csdn.net/zhazhiqiang/article/details/21047207
沒有深究原理,大概知道要干嘛,以后懂原理再來補充吧

四、問題總結

1.opencv的安裝,自己的vs是2019版本的,搜教程剛開始沒有注意版本,新版本去掉了一個文件,自己怎么也找不到。還要注意每次使用opencv時要注意增加屬性頁。
2.hog.compute()引發異常,這個bug在網上搜了許多,包括沒有附加依賴項,釋放hog各種各樣的說法,都不對。還是要仔細分析自己的代碼,這個其實是負樣本的讀取路徑問題。
3.Result = -1 * alphamat * svecsmat;引發異常,這個是因為矩陣相乘,但是維度不匹配,所以報錯。
再往上可以推到double rho = svm->getDecisionFunction(0, alphamat, svindex);這句引起了alpha的問題,網上有建議是代碼樣本數量和實際讀取的樣本數量不一樣。重新檢查了正負樣本數,還是沒有解決。
直接搜不到了,就去看別人的代碼,偶然看到一條注釋解決了問題!


4.還有一個小知識點:如何獲取文件夾內文件名保存到txt文件中

五、代碼展示

運行環境:win+opencv3.4.6
運行過程:
1.運行neg.cpp 剪裁負樣本的圖片
2.運行train.cpp 進行HOG的提取和SVM的訓練
3.運行hardexample.cpp訓練hardneg
4.運行train.cpp 生成最終的SVM模型

neg.cpp:對負樣本進行處理,對每張原始負樣本圖片隨機切十張,得到訓練負樣本。

#include <iostream>
#include <iostream>
#include <fstream>
#include <stdlib.h> //srand()和rand()函數
#include <time.h> //time()函數
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>


#define INRIANegativeImageList "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/sample_neg.txt" //原始負樣本圖片文件列表
int cropNegNum = 12140;

using namespace std;
using namespace cv;

int CropImageCount = 0; //裁剪出來的負樣本圖片個數

void neg()
//int main()
{
    Mat src;
    string ImgName;
    char saveName[600];//裁剪出來的負樣本圖片文件名
    ifstream fin(INRIANegativeImageList);//打開原始負樣本圖片文件列表

    int num = 0;
    ofstream fout("D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/sample_new_neg.txt", ios::trunc);
    
    for (int j = 0; j < cropNegNum && getline(fin, ImgName); j++)
    {
        cout << "處理:" << ImgName << endl;
        ImgName = "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/neg/" + ImgName;

        src = imread(ImgName, 1);

        //圖片大小應該能至少包含一個64*128的窗口
        if (src.cols >= 64 && src.rows >= 128)
        {
            srand(time(NULL));//設置隨機數種子
            for (int i = 0; i < 10; i++)
            {
                int x = (rand() % (src.cols - 64)); //左上角x坐標
                int y = (rand() % (src.rows - 128)); //左上角y坐標
                //cout<<x<<","<<y<<endl;
                Mat imgROI = src(Rect(x, y, 64, 128));
                //Rect rect(400,400,300,300);
                // Mat image_cut = Mat(img, rect);
                sprintf_s(saveName, "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/new_neg/noperson%06d.jpg", ++CropImageCount);//生成裁剪出的負樣本圖片的文件名
                imwrite(saveName, imgROI);//保存文件

                //保存裁剪得到的圖片名稱到txt文件,換行分隔
                //fout << "noperson" << j * 10 + i << endl;
            }
        }
    }
    fout.close();
    cout << "總共裁剪出" << CropImageCount << "張圖片" << endl;

}

train.h

#ifndef PEDESTRIAN_DETECTION_DETECTION_H
#define PEDESTRIAN_DETECTION_DETECTION_H

//訓練開關
#define TRAIN false//是否進行訓練,true表示重新訓練,false表示讀取xml文件中的SVM模型
#define CENTRAL_CROP true //true:訓練時,對96*160的INRIA正樣本圖片剪裁出中間的64*128大小人體
#define HARDNEG true //是否使用hardneg,true表示使用

//樣本數量
#define PosSamNO 2416  //原始正樣本數          2416 , 3542
#define NegSamNO 5980 // 剪裁后的負樣本數    6070
#define cropNegNum 600  //原始負樣本數
#define HardExampleNO 3004// hardneg的樣本數量   //10896 不用難例時要設置為0  4081 //
#define AugPosSamNO 0 //Aug positive num#pragma once

//正樣本圖片的文件名列表
#define PosSamListFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/pos1.txt"
//負樣本圖片的文件名列表
#define NegSamListFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/sample_new_neg.txt"
//hard負樣本圖片的文件列表
#define NegHardListFile  "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/hard_neg.txt"
//訓練的HOG特征,svm分類時使用
#define SvmListFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/data/SVM_HOG8.xml"
//訓練的HOG特征,resultMat結果
#define HogDetectorListFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/data/HOGDetectorForOpenCV7.txt"

//讀入的pos圖片路徑
#define PosImageFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/pos/"
//讀入的neg圖片路徑
#define NegImageFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/new_neg/"
//讀入的hardneg圖片路徑
#define HardNegImageFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/hard_neg/"

#endif //PEDESTRIAN_DETECTION_DETECTION_H

train.h

#include <iostream>
#include <fstream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/ml/ml.hpp>
#include <windows.h>
#include "train.h"


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


int main()
{
    //void neg();

    //檢測窗口(64,128),塊尺寸(16,16),塊步長(8,8),cell尺寸(8,8),直方圖bin個數9
    HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
    int DescriptorDim;//HOG描述子的維數,由圖片大小、檢測窗口大小、塊大小、細胞單元中直方圖bin個數決定
    Ptr<SVM> svm = SVM::create();// 創建分類器

    if (TRAIN)//若TRAIN為true,重新訓練分類器
    {
        string ImgName;//圖片名(絕對路徑)
        //正樣本圖片的文件名列表
        ifstream finPos(PosSamListFile);
        // ifstream finNeg("../sample_neg.txt");
        //負樣本圖片的文件名列表
        ifstream finNeg(NegSamListFile);
        //HardExample負樣本的文件名列表
        ifstream finHardNeg(NegHardListFile);

        if (HARDNEG) {
            if (!finPos || !finNeg || !finHardNeg) {
                cout << "Pos/Neg/hardNeg imglist reading failed..." << endl;
                return 1;
            }
        }
        else {
            if (!finPos || !finNeg)
            {
                cout << "Pos/Neg/hardNeg imglist reading failed..." << endl;
                return 1;
            }
        }

        Mat sampleFeatureMat;
        Mat sampleLabelMat;

        //loading original positive examples...
        for (int num = 0; num < PosSamNO && getline(finPos, ImgName); num++)
        {
            cout << "Now processing original positive image: " << ImgName << endl;
            //cout << "pos num" << num << endl;
            ImgName = PosImageFile + ImgName;

            Mat src = imread(ImgName, 1);//讀取圖片

            if (CENTRAL_CROP)//true:訓練時,對96*160的INRIA正樣本圖片剪裁出中間的64*128大小人體
                if (src.cols >= 96 && src.rows >= 160)
                    //resize(src, src, Size(64, 128));
                    src = src(Rect(16, 16, 64, 128));
                else cout << "error" << endl; //測試

            vector<float> descriptors;//HOG描述子向量
            hog.compute(src, descriptors, Size(8, 8));//計算HOG描述子,檢測窗口移動步長(8,8)
            //cout<<"描述子維數:"<<descriptors.size()<<endl;

            //處理第一個樣本時初始化特征向量矩陣和類別矩陣,因為只有知道了特征向量的維數才能初始化特征向量矩陣
            if (num == 0)
            {
                DescriptorDim = descriptors.size();//HOG描述子的維數
                //初始化所有訓練樣本的特征向量組成的矩陣,行數等于所有樣本的個數,列數等于HOG描述子維數sampleFeatureMat
                sampleFeatureMat = Mat::zeros(PosSamNO + AugPosSamNO + NegSamNO + HardExampleNO, DescriptorDim, CV_32FC1);//CV_32FC1:CvMat數據結構參數
                //初始化訓練樣本的類別向量,行數等于所有樣本的個數,列數等于1;1表示有人,0表示無人
                sampleLabelMat = Mat::zeros(PosSamNO + AugPosSamNO + NegSamNO + HardExampleNO, 1, CV_32SC1);//sampleLabelMat的數據類型必須為有符號整數型
            }

            //將計算好的HOG描述子復制到樣本特征矩陣sampleFeatureMat
            for (int i = 0; i < DescriptorDim; i++)
                sampleFeatureMat.at<float>(num, i) = descriptors[i];//第num個樣本的特征向量中的第i個元素
            sampleLabelMat.at<int>(num, 0) = 1;//正樣本類別為1,有人
        }
        finPos.close();

       
        //依次讀取負樣本圖片,生成HOG描述子
        for (int num = 0; num < NegSamNO && getline(finNeg, ImgName); num++)
        {
            cout << "Now processing original negative image: " << ImgName << endl;
            //cout << "neg num" << num << endl;
            //ImgName = "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/new_neg/" + ImgName;
            //加上負樣本的路徑名
            ImgName = NegImageFile + ImgName;
            Mat src = imread(ImgName, 1);//讀取圖片

            vector<float> descriptors;//HOG描述子向量
            hog.compute(src, descriptors, Size(8, 8));//計算HOG描述子,檢測窗口移動步長(8,8)
            //cout << "描述子維數:" << descriptors.size() << endl;

            //將計算好的HOG描述子復制到樣本特征矩陣sampleFeatureMat
            for (int i = 0; i < DescriptorDim; i++)
                sampleFeatureMat.at<float>(num + PosSamNO + AugPosSamNO, i) = descriptors[i];//第PosSamNO+num個樣本的特征向量中的第i個元素
            sampleLabelMat.at<int>(num + PosSamNO + AugPosSamNO, 0) = -1;//負樣本類別為-1,無人


        }
        finNeg.close();
        
        //依次讀取HardExample負樣本圖片,生成HOG描述子
        if (HARDNEG) {
            for (int num = 0; num < HardExampleNO && getline(finHardNeg, ImgName); num++)
            {
                cout << "Now processing original hard negative image: " << ImgName << endl;
                // ImgName = "../normalized_images/train/neg/" + ImgName;
                //加上負樣本的路徑名
                ImgName = HardNegImageFile + ImgName;
                Mat src = imread(ImgName);//讀取圖片

                vector<float> descriptors;//HOG描述子向量
                hog.compute(src, descriptors, Size(8, 8));//計算HOG描述子,檢測窗口移動步長(8,8)
                //cout<<"描述子維數:"<<descriptors.size()<<endl;

                //將計算好的HOG描述子復制到樣本特征矩陣sampleFeatureMat
                for (int i = 0; i < DescriptorDim; i++)
                    sampleFeatureMat.at<float>(num + PosSamNO + NegSamNO + AugPosSamNO, i) = descriptors[i];//第PosSamNO+num個樣本的特征向量中的第i個元素
                sampleLabelMat.at<int>(num + PosSamNO + NegSamNO + AugPosSamNO, 0) = -1;//負樣本類別為-1,無人

            }
        }
        finHardNeg.close();

        //指定svm種類
        svm->setType(SVM::C_SVC);
        //CvSVM::C_SVC : C類支持向量分類機。 n類分組  (n≥2),允許用異常值懲罰因子C進行不完全分類。

        //CvSVM::NU_SVC : 類支持向量分類機。n類似然不完全分類的分類器。
        // 參數為取代C(其值在區間【0,1】中,nu越大,決策邊界越平滑)

        //CvSVM::ONE_CLASS : 單分類器,所有的訓練數據提取自同一個類里,
        // 然后SVM建立了一個分界線以分割該類在特征空間中所占區域和其它類在特征空間中所占區域。

        //CvSVM::EPS_SVR : 類支持向量回歸機。
        // 訓練集中的特征向量和擬合出來的超平面的距離需要小于p。異常值懲罰因子C被采用

        //CvSVM::NU_SVR : 類支持向量回歸機。 代替了p。

        svm->setC(0.01);//懲罰因子

        svm->setGamma(1.0);//gamma參數

        //C是懲罰系數,即對誤差的寬容度。
        // c越高,說明越不能容忍出現誤差,容易過擬合。
        // C越小,容易欠擬合。C過大或過小,泛化能力變差

        svm->setKernel(SVM::LINEAR);//設置核函數
        // LINEAR:線性核函數;

        // POLY:多項式核函數;
        /// -d用來設置多項式核函數的最高此項次數;默認值是3
        /// -r用來設置核函數中的coef0,也就是公式中的第二個r,默認值是0。
        // 一般選擇1-11:1 3 5 7 9 11,也可以選擇2,4,6…

        // RBF:徑向機核函數【高斯核函數】;
        /// -g用來設置核函數中的gamma參數設置,默認值是1/k(k是類別數)
        //gamma是選擇RBF函數作為kernel后,該函數自帶的一個參數。
        // 隱含地決定了數據映射到新的特征空間后的分布,
        // gamma越大,支持向量越少,gamma值越小,支持向量越多。
        // 支持向量的個數影響訓練與預測的速度。

        // SIGMOID:神經元的非線性作用函數核函數;
        /// -g用來設置核函數中的gamma參數設置,默認值是1/k(k是類別數)
        /// -r用來設置核函數中的coef0,也就是公式中的第二個r,默認值是0

        // PRECOMPUTED:用戶自定義核函數

        //SVM的迭代訓練過程的中止條件
        svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER, 50000, FLT_EPSILON));

        cout << "Starting training..." << endl;
        //svm->train(trainingDataMat, cv::ml::SampleTypes::ROW_SAMPLE, labelsMat);
        svm->train(sampleFeatureMat, ROW_SAMPLE, sampleLabelMat);

        // svm ->trainAuto(); //svm自動優化參數
        cout << "Finishing training..." << endl;

        //儲存 SVM 分類器
        svm->save(SvmListFile);

        //SVM的改進算法
        //J.Platt的SMO算法、
        //T.Joachims的SVM、
        //C.J.C.Burges等的PCGC、
        //張學工的CSVM
        //以及O.L.Mangasarian等的SOR算法

    }
    else 
    {
     svm = SVM::load(SvmListFile);
    }
    cout << "loaded SVM_HOG.xml file" << endl;
    int svdim = svm->getVarCount();//特征向量的維數,即HOG描述子的維數
    //支持向量的個數
    Mat svecsmat = svm->getSupportVectors();//svecsmat元素的數據類型為float
    int numofsv = svecsmat.rows;

    //alphamat和svindex必須初始化,否則getDecisionFunction()函數會報錯
    Mat alphamat = Mat::zeros(numofsv, svdim, CV_32F);
    //Mat alphamat = Mat::zeros(1, numofsv, CV_64F);
    Mat svindex = Mat::zeros(1, numofsv, CV_64F);

    Mat Result= Mat::zeros(1, svdim, CV_32FC1);
    double rho = svm->getDecisionFunction(0, alphamat, svindex);
    
    

    cout << "the value of rho is  " << rho << endl;
    alphamat.convertTo(alphamat, CV_32F);//將alphamat元素的數據類型重新轉成CV_32F
    cout << "the value of alphamat is  " << alphamat << endl;
    cout << "the size of alphamat is  " << alphamat.size() << endl;
    cout << "the size of svecsmat is  " << svecsmat.size() << endl;
    //cout << svecsmat << endl;

    //計算-(alphaMat * supportVectorMat),結果放到resultMat中
    Result = -1 * alphamat * svecsmat;//float

    cout << "the value of svdim is  " << svdim << endl;

    //得到最終的setSVMDetector(const vector<float>& detector)參數中可用的檢測子
    vector<float> vec;
    //將resultMat中的數據復制到數組vec中
    for (int i = 0; i < svdim; ++i)
    {
        vec.push_back(Result.at<float>(0, i));
    }
    vec.push_back(rho);

    cout << "going to write the HOGDetectorForOpenCV.txt file" << endl;

    //保存HOG特征到HOGDetectorForOpenCV.txt
    ofstream fout(HogDetectorListFile);
    for (int i = 0; i < vec.size(); ++i)
    {
        fout << vec[i] << endl;
    }
    fout.close();//關閉文件

    /*********************************Testing**************************************************/
    HOGDescriptor hog_test;
    hog_test.setSVMDetector(vec);
    cout << "all is ok" << endl;

    Mat src = imread("D:/Pedestrain_Detection-master/Pedestrain_Detection-master/data/Test3.jpg");
    vector<Rect> found, found_filtered;
    hog_test.detectMultiScale(src, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);

    cout << "found.size : " << found.size() << endl;

    //找出所有沒有嵌套的矩形框r,并放入found_filtered中,如果有嵌套的話,則取外面最大的那個矩形框放入found_filtered中
    for (int i = 0; i < found.size(); i++)
    {
        Rect r = found[i];
        int j = 0;
        for (; j < found.size(); j++)
            if (j != i && (r & found[j]) == r)
                break;
        if (j == found.size())
            found_filtered.push_back(r);
    }

    //畫矩形框,因為hog檢測出的矩形框比實際人體框要稍微大些,所以這里需要做一些調整
    for (int i = 0; i < found_filtered.size(); i++)
    {
        Rect r = found_filtered[i];
        r.x += cvRound(r.width * 0.1);
        r.width = cvRound(r.width * 0.8);
        r.y += cvRound(r.height * 0.07);
        r.height = cvRound(r.height * 0.8);
        rectangle(src, r.tl(), r.br(), Scalar(0, 255, 0), 3);
    }

    imwrite("ImgProcessed.jpg", src);
    namedWindow("src", 0);
    imshow("src", src);
    waitKey(0);

    return 0;  
}

hardexample.cpp :難例訓練

#include <iostream>
#include <fstream>
#include <opencv2/opencv.hpp>
#include <stdio.h>
//#include "dataset.h"
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/ml/ml.hpp>
#include <opencv2/objdetect/objdetect.hpp>
#include <opencv2/imgproc/imgproc.hpp>

#include<iomanip>

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

int HardExampleCount = 1;
#define cropHardNegNum 10896

#define NegFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/sample_neg.txt"
#define HardFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/img_dir/hard_neg.txt"
#define SvmLoadFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/data/SVM_HOG8.xml"
#define NegImageFile "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/neg/"

class MySVM : public  ml::SVM
{
public:
    //獲得SVM的決策函數中的alpha數組
    double get_svm_rho()
    {
        return this->getDecisionFunction(0, svm_alpha, svm_svidx);
    }

    //獲得SVM的決策函數中的rho參數,即偏移量

    vector<float> svm_alpha;
    vector<float> svm_svidx;
    float  svm_rho;

};

int hard(int argc, char** argv)
{
    Mat src;
    string ImgName;

    char saveName[600];//找出來的HardExample圖片文件名
    //打開原始負樣本圖片文件列表
    ifstream fin(NegFile);

    ofstream fout(HardFile, ios::trunc);//加路徑
   // int num = 1;
    //檢測窗口(64,128),塊尺寸(16,16),塊步長(8,8),cell尺寸(8,8),直方圖bin個數9
    //HOGDescriptor hog(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);//HOG檢測器,用來計算HOG描述子的
    int DescriptorDim;//HOG描述子的維數,由圖片大小、檢測窗口大小、塊大小、細胞單元中直方圖bin個數決定
    ///MySVM svm;//SVM分類器
   // Ptr<SVM> svm = SVM::create();// 創建分類器
    ///svm = svm::load("SVM_HOG.xml");
    //svm ->save("/Users/macbookpro/CLionProjects/pedestrian_detection/data/SVM_HOG7.xml");

    Ptr<SVM> svm = Algorithm::load<SVM>(SvmLoadFile);
    
    /*************************************************************************************************
      線性SVM訓練完成后得到的XML文件里面,有一個數組,叫做support vector,還有一個數組,叫做alpha,有一個浮點數,叫做rho;
      將alpha矩陣同support vector相乘,注意,alpha*supportVector,將得到一個列向量。之后,再該列向量的最后添加一個元素rho。
      如此,變得到了一個分類器,利用該分類器,直接替換opencv中行人檢測默認的那個分類器(cv::HOGDescriptor::setSVMDetector()),
      就可以利用你的訓練樣本訓練出來的分類器進行行人檢測了。
      ***************************************************************************************************/
    DescriptorDim = svm->getVarCount();//特征向量的維數,即HOG描述子的維數
    Mat supportVector = svm->getSupportVectors();//支持向量的個數
    int supportVectorNum = supportVector.rows;
    //cout<<"支持向量個數:"<<supportVectorNum<<endl;

    vector<float> svm_alpha;
    vector<float> svm_svidx;
    float  svm_rho;
    svm_rho = svm->getDecisionFunction(0, svm_alpha, svm_svidx);

    Mat alphaMat = Mat::zeros(1, supportVectorNum, CV_32FC1);//alpha向量,長度等于支持向量個數
    Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);//支持向量矩陣
    Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);//alpha向量乘以支持向量矩陣的結果

    //將支持向量的數據復制到supportVectorMat矩陣中

    supportVectorMat = supportVector;

    //將alpha向量的數據復制到alphaMat中
    ///double * pAlphaData = svm.get_alpha_vector();//返回SVM的決策函數中的alpha向量
    for (int i = 0; i < supportVectorNum; i++)
    {
        alphaMat.at<float>(0, i) = svm_alpha[i];
    }

    //計算-(alphaMat * supportVectorMat),結果放到resultMat中
    //gemm(alphaMat, supportVectorMat, -1, 0, 1, resultMat);
    resultMat = -1 * alphaMat * supportVectorMat;

    //得到最終的setSVMDetector(const vector<float>& detector)參數中可用的檢測子
    vector<float> myDetector;
    //將resultMat中的數據復制到數組myDetector中
    for (int i = 0; i < DescriptorDim; i++)
    {
        myDetector.push_back(resultMat.at<float>(0, i));
    }


    //最后添加偏移量rho,得到檢測子
   /// myDetector.push_back(svm.get_rho());
    myDetector.push_back(svm_rho);
    cout << "檢測子維數:" << myDetector.size() << endl;

    //設置HOGDescriptor的檢測子
    HOGDescriptor myHOG;
    myHOG.setSVMDetector(myDetector);

    //myHOG.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());

//  //保存檢測子參數到文件
//  ofstream fout("HOGDetectorForOpenCV.txt");
//  for(int i=0; i<myDetector.size(); i++)
//  {
//      fout<<myDetector[i]<<endl;
//  }

//  namedWindow("people detector", 1);

    while (getline(fin, ImgName))
    {
        cout << "處理:" << ImgName << endl;
        ImgName = NegImageFile + ImgName;
        src = imread(ImgName, 1);//讀取圖片

        Mat img = src.clone();//復制原圖

        vector<Rect> found, found_filtered;
        //double t = (double)getTickCount();
        // run the detector with default parameters. to get a higher hit-rate
        // (and more false alarms, respectively), decrease the hitThreshold and
        // groupThreshold (set groupThreshold to 0 to turn off the grouping completely).

        //對負樣本原圖進行多尺度檢測,檢測出的都是誤報
        myHOG.detectMultiScale(src, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
        //t = (double)getTickCount() - t;
        //printf("tdetection time = %gms\n", t*1000./cv::getTickFrequency());


        //遍歷從圖像中檢測出來的矩形框,得到hard example
        size_t i, j;
        for (i = 0; i < found.size(); i++)
        {
            Rect r = found[i];
            for (j = 0; j < found.size(); j++)
                if (j != i && (r & found[j]) == r)
                    break;
            if (j == found.size())
                found_filtered.push_back(r);
        }

        for (i = 0; i < found_filtered.size(); i++)
        {
            Rect r = found_filtered[i];
            // the HOG detector returns slightly larger rectangles than the real objects.
            // so we slightly shrink the rectangles to get a nicer output.
            //r.x += cvRound(r.width*0.1);
            //r.width = cvRound(r.width*0.8);
            //r.y += cvRound(r.height*0.07);
            //r.height = cvRound(r.height*0.8);

            //檢測出來的很多矩形框都超出了圖像邊界,將這些矩形框都強制規范在圖像邊界內部
            if (r.x < 0)
                r.x = 0;
            if (r.y < 0)
                r.y = 0;
            if (r.x + r.width > src.cols)
                r.width = src.cols - r.x;
            if (r.y + r.height > src.rows)
                r.height = src.rows - r.y;

            //從原圖上截取矩形框大小的圖片
            Mat imgROI = src(Rect(r.x, r.y, r.width, r.height));

            //將剪裁出來的圖片縮放為64*128大小
            resize(imgROI, imgROI, Size(64, 128));

            //生成hard example圖片的文件名
            sprintf_s(saveName, "D:/Pedestrain_Detection-master/Pedestrain_Detection-master/normalized_images/train/hard_neg/hardexample%06d.jpg", HardExampleCount);

            //保存文件
            imwrite(saveName, imgROI);

            //            //保存裁剪得到的圖片名稱到txt文件,換行分隔

            fout << "hardexample" << setw(6) << setfill('0') << HardExampleCount << ".jpg" << endl;

            //            //num++;
            HardExampleCount++;

            //rectangle(src, r.tl(), r.br(), cv::Scalar(0,255,0), 3);
        }
        //imshow("people detector", src);
        //waitKey(0);

    }
    fout.close();

    cout << "HardExampleCount: " << HardExampleCount - 1 << endl;

    return 0;
}

六、參考資料

代碼參考:https://github.com/fanxinglanyu/Pedestrain_Detection

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容