用初次訓練的SVM+HOG分類器在負樣本原圖上檢測HardExample

masikkk發表於2013-11-14

難例(或叫做難樣本,Hard Example,Hard Negative,Hard Instance)是指利用第一次訓練的分類器在負樣本原圖(肯定沒有人體)上進行行人檢測時所有檢測到的矩形框,這些矩形框區域很明顯都是誤報,把這些誤報的矩形框儲存為圖片,加入到初始的負樣本集合中,重新進行SVM的訓練,可顯著減少誤報。這種方法叫做自舉法(Bootstrap),自舉法首先使用初始負樣本集來訓練一個模型,然後收集被這個初始模型錯誤分類的負樣本來形成一個負樣本難例集。用此負樣本難例集訓練新的模型,此過程可以重複多次。

比如典型的誤報如下:



上圖中將樹幹誤認為是人體,這些就是Hard Example,將這些矩形框儲存為64*128的圖片檔案,加入到負樣本集合中。

也就是說,難例就是分錯類的負樣本,將難例加入負樣本集合進行二次訓練就是告訴分類器:“這些是你上次分錯類的,要吸取教訓,改正錯誤”

初次訓練SVM+HOG分類器見:自己訓練SVM分類器進行HOG行人檢測

Navneet Dalal在CVPR2005上的HOG原論文翻譯見:http://blog.csdn.net/masibuaa/article/details/14056807


#include <iostream>
#include <fstream>
#include <string>
#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>

using namespace std;
using namespace cv;

int hardExampleCount = 0; //hard example計數

int main()
{
	Mat src;
	char saveName[256];//剪裁出來的hard example圖片的檔名
	string ImgName;
	ifstream fin_detector("HOGDetectorForOpenCV_2400PosINRIA_12000Neg.txt");//開啟自己訓練的SVM檢測器檔案
	ifstream fin_imgList("INRIANegativeImageList.txt");//開啟原始負樣本圖片檔案列表
	//ifstream fin_imgList("subset.txt");

	//從檔案中讀入自己訓練的SVM引數
	float temp;
	vector<float> myDetector;//3781維的檢測器引數
	while(!fin_detector.eof())
	{
		fin_detector >> temp;
		myDetector.push_back(temp);//放入檢測器陣列
	}
	cout<<"檢測子維數:"<<myDetector.size()<<endl;

	//namedWindow("src",0);
	HOGDescriptor hog;//HOG特徵檢測器
	hog.setSVMDetector(myDetector);//設定檢測器引數為自己訓練的SVM引數

	//一行一行讀取檔案列表
	while(getline(fin_imgList,ImgName))
	{
		cout<<"處理:"<<ImgName<<endl;
		string fullName = "D:\\DataSet\\INRIAPerson\\INRIAPerson\\Train\\neg\\" + ImgName;//加上路徑名
		src = imread(fullName);//讀取圖片
		Mat img = src.clone();//複製原圖

		vector<Rect> found;//矩形框陣列
		//對負樣本原圖進行多尺度檢測,檢測出的都是誤報
		hog.detectMultiScale(src, found, 0, Size(8,8), Size(32,32), 1.05, 2);

		//遍歷從影象中檢測出來的矩形框,得到hard example
		for(int i=0; i < found.size(); i++)
		{
			//檢測出來的很多矩形框都超出了影象邊界,將這些矩形框都強制規範在影象邊界內部
			Rect r = found[i];
			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;

			//將矩形框儲存為圖片,就是Hard Example
			Mat hardExampleImg = src(r);//從原圖上擷取矩形框大小的圖片
			resize(hardExampleImg,hardExampleImg,Size(64,128));//將剪裁出來的圖片縮放為64*128大小
			sprintf(saveName,"hardexample%09d.jpg",hardExampleCount++);//生成hard example圖片的檔名
			imwrite(saveName, hardExampleImg);//儲存檔案


			//畫矩形框,因為hog檢測出的矩形框比實際人體框要稍微大些,所以這裡需要做一些調整
			//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(img, r.tl(), r.br(), Scalar(0,255,0), 3);

		}
		//imwrite(ImgName,img);
		//imshow("src",src);
		//waitKey(100);//注意:imshow之後一定要加waitKey,否則無法顯示影象

	}

	system("pause");
}


原始碼下載,環境為VS2010 + OpenCV2.4.4

http://download.csdn.net/detail/masikkk/6549325

參考

用初次訓練的SVM+HOG分類器在負樣本原圖上檢測HardExample


相關文章