使用svm + hog 实现图片分类器 (附源码)

一、前言

hog是一个基于梯度的直方图提取算法,最初用于行人检测,效果拔群。之后DPM的出现将行人(目标)检测的准确率产生了巨大的提升。HOG特征提取在opencv2.2+版本里面已经实现。我的另外一篇博客推荐了几个很好的关于理解hog特征的博客。

以下在推荐两个:

http://blog.csdn.net/raocong2010/archive/2011/03/11/6239431.aspx 

本文中介绍了opencv中HOGDescriptor构造函数各个参数的含义。


从另外我从http://blog.csdn.net/yangtrees/article/details/7471222 上找来了一段代码。即是使用HOG + SVM 进行图像分类。虽然没有太多注释,但逻辑还是很清楚的。我根据他的代码,把程序中的一些功能函数化了。具体有以下三个文件:

1. hog_svm.h (声明了一些函数)

2. hog_svm.cpp(函数具体实现, 主要内容都在这里)

3. main.cpp(测试程序)

注:在main函数中,trainNames.txt中保存着训练集图像的地址,trainLabels.txt中保存对应的训练集图像标签

testNames.txt中保存测试集图像的地址。


二、代码分析

1.hog_svm.h

#ifndef HOG_SVM_
#define HOG_SVM_

#include 
#include 
#include 

using namespace cv;
using namespace std;

namespace hog_svm {

	vector extractHOGFeature(const Mat & src);
	
	/*
	imgList 为包含所有训练图像路径的文本文件
	labelList是与它对应的图像的标签
	labelList中图像的标签由整型数字表示
	返回值为指向CvSVM的指针 (为啥不直接返回CvSVM对象,因为函数返回对象时需要调用复制构造函数,但CvSVM的复制构造函数是private的)
	*/
	CvSVM* getHOGSVM(string imgList, string labelList);
	
	/*
	这函数不用了,别看了
	imgPath 中存储所有图像的路径
	imgCatg中存储与图像所对应的标签
	dataMat是提取特征后的矩阵, resMat为图像的标签,两者都是每行对应一张图想
	void extractHOGFeature(const vector & imgPath, const vector & imgCatg,
		Mat & dataMat, Mat & resMat);
	*/

	//返回值为float类型
	float svmPredict(CvSVM * hogSvm, const Mat & image);
}



#endif

2.hog_svm.cpp

#include "hog_svm.h"
#include 
#include 
#include 
#include 
#include 


using namespace std;
using namespace cv;

const int hog_svm_ImageHeight = 256;
const int hog_svm_ImageWidth = 256;


vector hog_svm::extractHOGFeature(const Mat & src)
{
	Mat tempImg;
	resize(src, tempImg, Size(hog_svm_ImageWidth, hog_svm_ImageHeight));
	HOGDescriptor *hog = new HOGDescriptor(Size(hog_svm_ImageWidth, hog_svm_ImageHeight),
		Size(16, 16), cvSize(8, 8), cvSize(8, 8), 9);

	//存储特征计算结果
	vector descriptors;
	hog->compute(tempImg, descriptors, Size(1, 1), Size(0, 0));

	return descriptors;
}

//这个接口设计的不好
/*
void hog_svm::extractHOGFeature(const vector & imgPath, const vector & imgCatg,
	Mat & dataMat, Mat & resMat)
{
	Mat src, tempImg;
	resMat = Mat::zeros(imgPath.size(), 1, CV_32FC1);

	for (int i = 0; i < imgPath.size(); i++)
	{
		src = imread(imgPath[i], CV_LOAD_IMAGE_COLOR);
		resize(src, tempImg, Size(hog_svm_ImageWidth, hog_svm_ImageHeight));
		HOGDescriptor *hog = new HOGDescriptor(Size(hog_svm_ImageWidth, hog_svm_ImageHeight),
			Size(16, 16), cvSize(8, 8), cvSize(8, 8), 9);

		//存储特征计算结果
		vector descriptors;
		hog->compute(tempImg, descriptors, Size(1, 1), Size(0, 0));
		if (0 == i)
			dataMat = Mat::zeros(imgPath.size(), descriptors.size(), CV_32FC1);

		//存储计算后的特征值和标签
		for (int inn = 0; inn < descriptors.size(); inn++)
			dataMat.at(i, inn) = descriptors[inn];
		resMat.at(i, 0) = imgCatg[i];
	}//for int i
}
*/

CvSVM* hog_svm::getHOGSVM(string imgList, string labelList)
{
	///1.将图像路径和标签存储到向量中/
	ifstream imgListStream(imgList);
	ifstream labelListStream(labelList);

	vector imgPath;
	vector imgCatg;
	string imgItemPath;
	int imgItemCatg;

	while (imgListStream >> imgItemPath)
	{
		labelListStream >> imgItemCatg;
		imgPath.push_back(imgItemPath);
		imgCatg.push_back(imgItemCatg);
	}
	imgListStream.close();
	labelListStream.close();

	///2.对图像resize后,提取图像的HOG特征/
	Mat src, tempImg;
	Mat dataMat, resMat = Mat::zeros(imgPath.size(), 1, CV_32FC1);

	for (int i = 0; i < imgPath.size(); i++)
	{
		src = imread(imgPath[i], CV_LOAD_IMAGE_COLOR);

		//存储特征计算结果
		vector descriptors = extractHOGFeature(src);
		if (0 == i)
			dataMat = Mat::zeros(imgPath.size(), descriptors.size(), CV_32FC1);
		
		//存储计算后的特征值和标签
		for (int inn = 0; inn < descriptors.size(); inn++)
			dataMat.at(i, inn) = descriptors[inn];
		resMat.at(i, 0) = imgCatg[i];
	}//for int i


	///3,SVM参数设置//
	/*
	SVM种类:CvSVM:C_SVC 如果数据线性不可分的话就用这个
	Kernel种类:LINEAR (无核函数)
	*/
	CvSVM *hogSvm = new CvSVM();
	CvSVMParams params;
	params.svm_type = CvSVM::C_SVC;
	params.kernel_type = CvSVM::LINEAR;
	params.term_crit = cvTermCriteria(CV_TERMCRIT_ITER, 500, 1e-6);
	int featureLength = dataMat.cols;

	///4.训练SVM///
	hogSvm->train(dataMat, resMat, Mat(), Mat(), params);
	return hogSvm;
}


float hog_svm::svmPredict(CvSVM * hogSvm, const Mat & image)
{
	vector descriptors = extractHOGFeature(image);
	int featureLength = descriptors.size();

	Mat predictMat = Mat::zeros(1, featureLength, CV_32FC1);
	for (int i = 0; i < featureLength; i++)
		predictMat.at(0, i) = descriptors[i];

	return (hogSvm->predict(predictMat));
}


3.main.c

#include 
#include 
#include 

#include "hog_svm.h"
#include 
#include 

using namespace std;
using namespace cv;
using namespace hog_svm;

int main()
{
	CvSVM* svm = getHOGSVM("trainNames.txt", "trainLabels.txt");
	ifstream fin("testNames.txt");
	ofstream fout("predictRes.txt");
	string str;
	int kase = 0;
	while (fin >> str)
	{
		Mat image = imread(str, CV_LOAD_IMAGE_COLOR);
		float res = svmPredict(svm, image);
		fout << res << endl;
		cout << ++kase << " 个测试结束" << endl;
	}
	system("pause");
	return 0;
}


你可能感兴趣的:(数字图像处理)