機器學習中SVM+HOG實現對飲料瓶的識別

#include<opencv.hpp>
#include<iostream>
#include<highgui/highgui.hpp>
#include<ml/ml.hpp>
#include<string>
#include<fstream>
#include<vector>

using namespace std;
using namespace cv;

void main()
{
	VideoCapture cap("D:\\negtive.mp4");
	long totalFrameNumber = cap.get(CAP_PROP_FRAME_COUNT);
	cout << totalFrameNumber << endl;
	Mat frame;
	bool flags = true;
	long currentFrame = 0;

	while (flags)
	{
		cap.read(frame);

		stringstream str;
		str << currentFrame << ".jpg";
		imwrite("C:\\Users\\xx\\Desktop\\neg\\neg" + str.str(), frame);
		if (currentFrame >= totalFrameNumber)
		{
			flags = false;
		}
		currentFrame++;
	}
	system("pause");
}

利用cmd將圖片名字寫入txt文件中,這個與Linux命令相似,利用cd切換到當前目錄,cd 文件目錄。在輸入 dir /s/b > path.txt。則將圖片路徑寫入txt文件中。
當要進入其他盤時,可以win+R,打開運行窗口,再輸入cmd,進去之後輸入d:,這樣就進入了D盤了,就可以對D盤中的文件進行讀取了。
製作樣本時將樣本複製到word中製作標籤。選中jpg換成jpg^p1,ctrl+h表示替換全局的這個值,加個小三角表示將轉義字符,加p表示換行,在加入1表示後面追加1。這樣就成功的添加了標籤了。
接下來我們通過使用HOG對樣本進行分類,以及模型的訓練。

#include<opencv.hpp>
#include<iostream>
#include<highgui/highgui.hpp>
#include<ml/ml.hpp>
#include<string>
#include<fstream>
#include<vector>
#include<objdetect.hpp>
#include<stdlib.h>
#include<algorithm>

using namespace std;
using namespace cv;


int main(int argc, char** argv)
{
	int ImgWidght = 64;
	int ImgHeight = 128;
	vector<string> img_path;
	vector<int> img_catg;
	int nLine = 0;
	string buf;
	ifstream svm_data("D:\\traindatabase\\path.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)
			}
			else
			{
				img_path.push_back(buf);	//圖像路徑
			}
		}
	}
	svm_data.close();
	Mat data_mat, res_mat;
	int nImgNum = nLine / 2;
	data_mat = Mat::zeros(nImgNum, 3780, CV_32FC1);
	res_mat = Mat::zeros(nImgNum, 1, CV_32SC1);
	Mat src;
	Mat small;
	Mat trainImg = Mat(Size(ImgWidght, ImgHeight), 8, 3);
	for (string::size_type i = 0; i != img_path.size(); i++)
	{
		src = imread(img_path[i].c_str());
		if (src.empty())
		{
			cout << "can not load the image" << img_path[i] << endl;
			continue;
		}
		cout << "processing" << img_path[i].c_str() << endl;
		resize(src, small, Size(ImgWidght, ImgHeight), (0, 0), (0, 0), 1);
		cvtColor(small, small, COLOR_RGB2GRAY);
		HOGDescriptor *hog = new HOGDescriptor(Size(ImgWidght, ImgHeight), Size(16,16), Size(8, 8),Size(8,8), 9);
		vector<float>descriptors;
		hog->compute(small,descriptors, Size(1, 1), Size(0, 0));
		//cout << "HOG dimision is" << descriptors.size() << endl;
		n = 0;
		for (vector<float>::iterator iter=descriptors.begin();iter!=descriptors.end();iter++)
		{
			data_mat.at<float>(i, n) = *iter;
			n++;
		}
		res_mat.at<float>(i, 0) = img_catg[i];
		cout << "end processing " << img_path[i].c_str() << img_catg[i] << endl;
	}
	//cout << data_mat << endl;
	//cout << res_mat << endl;
	Ptr<ml::SVM>svm = ml::SVM::create();
	cout << "training" << endl;
	svm->setType(ml::SVM::C_SVC);
	svm->setKernel(ml::SVM::RBF);
	svm->setDegree(10.0);
	svm->setGamma(8.0);
	svm->setCoef0(1.0);
	svm->setC(10.0);
	svm->setNu(0.5);
	svm->setP(0);
	svm->setTermCriteria(TermCriteria(TermCriteria::MAX_ITER + TermCriteria::EPS, 1000,0.01));
	svm->train(data_mat,ml::ROW_SAMPLE,res_mat);
	cout << "End of training" << endl;
	svm->save("SVM_HOG.xml");
	

因爲這個樣本是第一行爲路徑,第二行爲標籤,因此通過這樣的方法可以將路徑轉化爲數組,將對應的每個標籤儲存到數組中,實現對飲料瓶的二分類。接下來就是對SVM的參數的設置,這些參數的說明可以查看官方文檔進行設置,最後將訓練好的xml文件保存到當前文件夾,並通過此模型來判斷物體是不是屬於飲料瓶。
接下來是SVM的預測。

	HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	int DescriptorDim;
	Ptr<ml::SVM>svm = ml::SVM::load("SVM_HOG.xml");
	DescriptorDim = svm->getVarCount();
	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);
	Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);
	Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);
	supportVectorMat = supportVector;
	//將alpha向量的數據複製到alphaMat中,返回SVM決策函數中的alpha向量
	for (int i = 0; i < supportVectorNum; i++)
	{
		alphaMat.at<float>(0, i) = svm_alpha[i];
	}
	//計算-(alphaMat*supportVectorMat),結果放在resultMat中。
	resultMat = -1 * alphaMat * supportVectorMat;
	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_rho);
	HOGDescriptor myHOG;
	myHOG.setSVMDetector(myDetector);
	Size s1(128, 128);
	Size s2(64, 64);
	myHOG.winSize = s1;
	myHOG.blockSize = s1;
	myHOG.blockStride = s1;
	myHOG.cellSize = s2;
	myHOG.nbins = 9;

	ofstream fout("HOGDetectorForOpenCv.txt");
	for (unsigned int i = 0; i < myDetector.size(); i++)
	{
		fout << myDetector[i] << endl;
	}
	Mat frame;
	Mat src1 = imread("D:\\predict\\3.jpg‪");
	resize(src1, frame, Size(64, 128), (0, 0), (0, 0), 1);
	vector<Rect>found,found_filtered;
	myHOG.detectMultiScale(frame, found, 0, Size(8, 8), Size(32, 32), 1.05, 2);
	cout << "找到的矩形框個數爲" << found.size() << endl;
	printf("找到%d個水瓶", found.size());
	//找出所有沒有嵌套的矩形框,並放入found_filtered中,如果有嵌套,取最外面的一個
	for (unsigned int i = 0; i < found.size(); i++)
	{
		Rect r = found[i];
		unsigned 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);
		}
	}
	//畫矩形框
	for (unsigned 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(frame, r.tl(), r.br(), Scalar(255, 0, 0), 5);
	}
	imshow("frame", frame);
	//imshow("src", src);
	waitKey(0);
	

使用訓練好的模型進行判斷,可以預測結果。
接下來是對結果的預測:

HOGDescriptor hog(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
	int DescriptorDim;
	Ptr<ml::SVM>svm = ml::SVM::load("SVM_HOG.xml");
	DescriptorDim = svm->getVarCount();
	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);
	Mat supportVectorMat = Mat::zeros(supportVectorNum, DescriptorDim, CV_32FC1);
	Mat resultMat = Mat::zeros(1, DescriptorDim, CV_32FC1);
	supportVectorMat = supportVector;
	//將alpha向量的數據複製到alphaMat中,返回SVM決策函數中的alpha向量
	for (int i = 0; i < supportVectorNum; i++)
	{
		alphaMat.at<float>(0, i) = svm_alpha[i];
	}
	//計算-(alphaMat*supportVectorMat),結果放在resultMat中。
	resultMat = -1 * alphaMat * supportVectorMat;
	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_rho);
	HOGDescriptor myHOG;
	myHOG.setSVMDetector(myDetector);
	Size s1(128, 128);
	Size s2(64, 64);
	myHOG.winSize = s1;
	myHOG.blockSize = s1;
	myHOG.blockStride = s1;
	myHOG.cellSize = s2;
	myHOG.nbins = 9;

	ofstream fout("HOGDetectorForOpenCv.txt");
	for (unsigned int i = 0; i < myDetector.size(); i++)
	{
		fout << myDetector[i] << endl;
	}
	Mat frame;
	Mat src = imread("D:\\predict\\2.jpg‪");
	resize(src, frame, Size(64, 128), (0, 0), (0, 0), 1);
	vector<Rect>found,found_filtered;
	myHOG.detectMultiScale(frame, found, 0, Size(16, 16), Size(16, 16), 1.05, 2);
	cout << "找到的矩形框個數爲" << found.size() << endl;
	printf("找到%d個水瓶", found.size());
	//找出所有沒有嵌套的矩形框,並放入found_filtered中,如果有嵌套,取最外面的一個
	for (unsigned int i = 0; i < found.size(); i++)
	{
		Rect r = found[i];
		unsigned 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);
		}
	}
	//畫矩形框
	for (unsigned 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(frame, r.tl(), r.br(), Scalar(255, 0, 0), 5);
	}
	imshow("frame", frame);
	//imshow("src", src);
	waitKey(0);

這就是SVM的簡單的識別,這段代碼仍然具有很多的錯誤,但是可以實現一些簡單的識別。也存在着精度和速度上的問題,沒有GPU的加速,而且HOG進行檢測時需要算很多,特徵向量有754個,因此帶來的計算問題還需要優化。特徵向量矩陣和分類使用的xml文件如果有需要的可以私信我,因爲文件比較大,在這就不方便發了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章