OpenCV实战【2】HOG+SVM实现行人检测
目錄
- HOG是什么?
- HOG vs SIFT
- HOG步驟
- HOG在檢測行人中的方式
- Opencv實(shí)現(xiàn)
- HOGDescriptor的構(gòu)造函數(shù):
- 行人檢測HOG+SVM步驟
- 簡化版的HOG計(jì)算
HOG是什么?
方向梯度直方圖( Histogram of Oriented Gradient, HOG )特征是一種在計(jì)算機(jī)視覺和圖像處理中用來進(jìn)行物體檢測的特征描述子。它通過
計(jì)算和統(tǒng)計(jì)圖像局部區(qū)域的梯度方向直方圖來構(gòu)成特征。Hog特征結(jié)合SVM分類器已經(jīng)被廣泛應(yīng)用于圖像識別中。
HOG vs SIFT
SIFT :對特征點(diǎn)的描述方法
HOG :對一定區(qū)域的特征量的描述方法
1、可以表現(xiàn)較大的形狀
2、非常適合行人及車輛檢測
假設(shè)我們在智能駕駛中要檢測行人:
正樣本:
負(fù)樣本:
識別的本質(zhì)是要找到正樣本和負(fù)樣本最本質(zhì)的區(qū)別。例如行人在肩部具有橫向邊緣、兩臂具有豎向邊緣。而非行人樣本中的邊緣是雜亂無章的。因此可以通過構(gòu)建梯度的直方圖來檢測形狀。由于直方圖損失了空間信息,所以HOG將圖像分割為一個(gè)一個(gè)小的區(qū)域(聯(lián)系閾值處理中的分塊處理法),對小的區(qū)域分別構(gòu)建直方圖,然后拼接得到一個(gè)大的直方圖。
HOG的缺點(diǎn): 速度慢,實(shí)時(shí)性差;難以處理遮擋問題。
HOG特征不具有旋轉(zhuǎn)魯棒性,以及尺度魯棒性
HOG步驟
1、Gamma矯正(增強(qiáng)圖像的對比度)
2、計(jì)算梯度信息
3、以cell(一個(gè)像素塊)為單位計(jì)算梯度直方圖
4、以block(幾個(gè)cell為一個(gè)block)為單位,對特征量進(jìn)行歸一化
具體步驟:
一般來說對梯度方向進(jìn)行九等分量化。
一般以3* 3的像素組成一個(gè)cell,這樣每個(gè)cell就可以得到一個(gè)9維的直方圖。
每 3*3個(gè)cell組成一個(gè)block,在每個(gè)block進(jìn)行歸一化:
歸一化的目的:增強(qiáng)對亮度的魯棒性。
HOG在檢測行人中的方式
通常采用滑窗的方式:
計(jì)算滑窗中包含的像素的梯度直方圖,然后與行人模板中的直方圖進(jìn)行對比(如利用各種矩),當(dāng)兩者十分相似時(shí),我們就認(rèn)為這個(gè)區(qū)域是行人區(qū)域。
從而延生出的問題:
由于模板是固定大小的,因此只能檢測固定大小的行人。當(dāng)圖像中的行人尺寸發(fā)生變化時(shí),如何使用一個(gè)單一的模板檢測?
Opencv實(shí)現(xiàn)
OpenCV實(shí)現(xiàn)了兩種類型的基于HOG特征的行人檢測,分別是SVM和Cascade,OpenCV自帶的級聯(lián)分類器的文件的位置在“XX\opencv\sources\data\hogcascades”(OpenCV4.x版本可用)。
opencv自帶的人數(shù)檢測文件,所在位置在opencv的安裝目錄下(下面是我的安裝位置):
D:\Program Files\opencv\sources\samples\cpp
HOGDescriptor的構(gòu)造函數(shù):
CV_WRAP HOGDescriptor() : winSize(64,128), blockSize(16,16), blockStride(8,8),cellSize(8,8), nbins(9), derivAperture(1), winSigma(-1),histogramNormType(HOGDescriptor::L2Hys), L2HysThreshold(0.2), gammaCorrection(true),free_coef(-1.f), nlevels(HOGDescriptor::DEFAULT_NLEVELS), signedGradient(false){}窗口大小 winSize(64,128), 塊大小blockSize(16,16), 塊滑動(dòng)增量blockStride(8,8), 胞元大小cellSize(8,8), 梯度方向數(shù)nbins(9)。
上面這些都是HOGDescriptor的成員變量,括號里的數(shù)值是它們的默認(rèn)值,它們反應(yīng)了HOG描述子的參數(shù)。
HOGDescriptor中有兩種Detector分別是:getDaimlerPeopleDetector、getDefaultPeopleDetector
行人檢測HOG+SVM步驟
參考的代碼:
#include <opencv2/objdetect.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/videoio.hpp> #include <iostream> #include <iomanip>using namespace cv; using namespace std;class Detector {//enum Mode { Default, Daimler } m;enum { Default, Daimler };//定義枚舉類型int m;HOGDescriptor hog, hog_d; public:Detector(int a) : m(a), hog(), hog_d(Size(48, 96), Size(16, 16), Size(8, 8), Size(8, 8), 9)//構(gòu)造函數(shù),初始化對象時(shí)自動(dòng)調(diào)用,m,hog,hog_d是數(shù)據(jù)成員,后跟一個(gè)放在圓括號中的初始化形式{hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());hog_d.setSVMDetector(HOGDescriptor::getDaimlerPeopleDetector());}void toggleMode() { m = (m == Default ? Daimler : Default); }string modeName() const { return (m == Default ? "Default" : "Daimler"); }vector<Rect> detect(InputArray img){// 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).vector<Rect> found;if (m == Default)hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2, false);else if (m == Daimler)hog_d.detectMultiScale(img, found, 0.5, Size(8, 8), Size(32, 32), 1.05, 2, true);return found;}void adjustRect(Rect& r) const{// 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);} }; //修改參數(shù)區(qū)域 static const string keys = "{ help h | | print help message }" "{ camera c | 0 | capture video from camera (device index starting from 0) }" "{ video v | D:/opencv/opencv4.0/opencv4.0.0/sources/samples/data/vtest.avi| use video as input }";int main(int argc, char** argv) {CommandLineParser parser(argc, argv, keys); //keys:描述可接受的命令行參數(shù)的字符串parser.about("This sample demonstrates the use ot the HoG descriptor.");//設(shè)置相關(guān)信息。相關(guān)信息會(huì)在 printMessage 被調(diào)用時(shí)顯示。if (parser.has("help")){parser.printMessage();return 0;}int camera = parser.get<int>("camera");string file = parser.get<string>("video");if (!parser.check())//檢查解析錯(cuò)誤。當(dāng)錯(cuò)誤發(fā)生時(shí)返回true。錯(cuò)誤可能是轉(zhuǎn)換錯(cuò)誤、丟失參數(shù)等。{parser.printErrors();return 1;}VideoCapture cap;if (file.empty())cap.open(camera);elsecap.open(file.c_str());if (!cap.isOpened()){cout << "Can not open video stream: '" << (file.empty() ? "<camera>" : file) << "'" << endl;return 2;}cout << "Press 'q' or <ESC> to quit." << endl;cout << "Press <space> to toggle between Default and Daimler detector" << endl;//Default and Daimler detectorDetector detector(1); //初始化使用Daimler detectorMat frame;for (;;){cap >> frame;if (frame.empty()){cout << "Finished reading: empty frame" << endl;break;}int64 t = getTickCount();vector<Rect> found = detector.detect(frame);t = getTickCount() - t;// show the window{ostringstream buf;buf << "Mode: " << detector.modeName() << " ||| "<< "FPS: " << fixed << setprecision(1) << (getTickFrequency() / (double)t);putText(frame, buf.str(), Point(10, 30), FONT_HERSHEY_PLAIN, 2.0, Scalar(0, 0, 255), 2, LINE_AA);}for (vector<Rect>::iterator i = found.begin(); i != found.end(); ++i){Rect& r = *i;detector.adjustRect(r);rectangle(frame, r.tl(), r.br(), cv::Scalar(0, 255, 0), 2);}imshow("People detector", frame);// interact with userconst char key = (char)waitKey(30);if (key == 27 || key == 'q') // ESC{cout << "Exit requested" << endl;break;}else if (key == ' '){detector.toggleMode();}}return 0; }簡化后的對單張圖片的檢測
#include <opencv2/objdetect.hpp> #include <opencv2/highgui.hpp> #include <opencv2/imgproc.hpp> #include <opencv2/videoio.hpp> #include <iostream> #include <iomanip>using namespace cv; using namespace std;class Detector {//enum Mode { Default, Daimler } m;enum { Default, Daimler };//定義枚舉類型int m;HOGDescriptor hog, hog_d; public:Detector(int a) : m(a), hog(), hog_d(Size(48, 96), Size(16, 16), Size(8, 8), Size(8, 8), 9)//構(gòu)造函數(shù),初始化對象時(shí)自動(dòng)調(diào)用,m,hog,hog_d是數(shù)據(jù)成員,后跟一個(gè)放在圓括號中的初始化形式{hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector());hog_d.setSVMDetector(HOGDescriptor::getDaimlerPeopleDetector());}void toggleMode() { m = (m == Default ? Daimler : Default); }string modeName() const { return (m == Default ? "Default" : "Daimler"); }vector<Rect> detect(InputArray img){// 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).vector<Rect> found;if (m == Default)hog.detectMultiScale(img, found, 0, Size(8, 8), Size(32, 32), 1.05, 2, false);else if (m == Daimler)hog_d.detectMultiScale(img, found, 0.5, Size(8, 8), Size(32, 32), 1.05, 2, true);return found;}void adjustRect(Rect& r) const{// 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);} };int main(int argc, char** argv) {Detector detector(1); //初始化使用Daimler detectorMat img=imread("D:\\opencv_picture_test\\HOG行人檢測\\timg.jpg");vector<Rect> found = detector.detect(img);for (vector<Rect>::iterator i = found.begin(); i != found.end(); ++i){Rect& r = *i;detector.adjustRect(r); rectangle(img, r.tl(), r.br(), cv::Scalar(0, 255, 0), 2);}imshow("People detector", img);waitKey(0);return 0; }結(jié)果:
簡化版的HOG計(jì)算
需要用到的知識點(diǎn):
曼哈頓距離:
由于一般的建立數(shù)組的方法在【】中填變量是行不通的,這里我們采用動(dòng)態(tài)建立數(shù)組的方法。在程序返回前必須將內(nèi)存釋放
結(jié)果:
Reference:
OpenCV實(shí)戰(zhàn)4: HOG+SVM實(shí)現(xiàn)行人檢測
HOG detectMultiScale 參數(shù)分析
CommandLineParser類(命令行解析類)
C++語法:構(gòu)造函數(shù)以及析構(gòu)函數(shù)
《數(shù)字圖像處理PPT.李竹版》
總結(jié)
以上是生活随笔為你收集整理的OpenCV实战【2】HOG+SVM实现行人检测的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: “能屯复能跃”下一句是什么
- 下一篇: 地下城与勇士,好多人穿野猪套不打孔呢??