Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练
在计算机视觉研究当中,HOG算法和LBP算法算是基础算法,但是却十分重要。后期很多图像特征提取的算法都是基于HOG和LBP,所以了解和掌握HOG,是学习计算机视觉的前提和基础。
HOG算法的原理很多资料都可以查到,简单来说,就是将图像分成一个cell,通过对每个cell的像素进行梯度处理,进而根据梯度方向和梯度幅度来得到cell的图像特征。随后,将每个cell的图像特征连接起来,得到一个BLock的特征,进而得到一张图片的特征。Opencv当中自带HOG算法,可以直接调用,进行图像的特征提取。但是作为一个初学者,自然应该自己手写一下HOG算法,这样能够更加透彻地去理解。
下面是我自己写的HOG,代码比较粗糙,为了适应下面的KNN分类器,HOG算法的接口设计为输入一张图片,返回一个vector向量。
class HOG{
private:
Mat img;
public:
vector<float>bins; //返回一个图片的HOG特征;
void GetImage(Mat src);
void Cut_to_Block(); //将图片分割成一个个Block;
void Cut_to_Cell(int pixel_x, int pixel_y); //将图片分割成一个个Cell;
void Cell_to_bin(int x, int y); //对每个Cell进行处理,得到每个Cell的bins;
}; void HOG::GetImage(Mat src){
bins.clear();
cvtColor(src, img, COLOR_RGB2GRAY);
Cut_to_Block();
} void HOG::Cut_to_Block(){
for (int i = ; i <= img.rows - ; i = i + ){
for (int j = ; j <= img.cols - ; j = j + ){
Cut_to_Cell(i, j);
}
}
} void HOG::Cut_to_Cell(int pixel_x, int pixel_y){
for (int i = pixel_x, m = ; m < ; i = i + , m++){
for (int j = pixel_y, n = ; n < ; j = j + , n++){
Cell_to_bin(i, j);
}
}
} void HOG::Cell_to_bin(int x, int y){
int pixel_x; //cell的像素的起始位置行坐标;
int pixel_y; //cell的像素的起始位置纵坐标;
float pixel[][]; //我们一般默认cell为8*8的像素大小,但是为了储存周边店的像素,需要多加两个像素储存点的位置;
float gradient_M[][]; //保存梯度的幅值;
float gradient_Angle[][]; //保存像素梯度的方向;
float gradient_h[][];
float gradient_v[][];
float bin[]; //存放一个Cell当中的bins值; pixel_x = x;
pixel_y = y; //为了计算方便,我们将每个Cell的像素先提取出来,存放在pixel[][]当中;
for (int i = pixel_x - , m = ; i < pixel_x + ; i++, m++){
uchar *data = img.ptr<uchar>(i);
for (int j = pixel_y - , n = ; j < pixel_y + ; j++, n++){
pixel[m][n] = data[j];
}
} //计算每个像素的梯度幅值和梯度角度;
for (int i = ; i<; i++){
for (int j = ; j<; j++){
gradient_h[i][j] = pixel[i + ][j] - pixel[i - ][j];
gradient_v[i][j] = pixel[i][j + ] - pixel[i][j - ];
gradient_M[i][j] = sqrt(gradient_h[i][j] * gradient_h[i][j] + gradient_v[i][j] * gradient_v[i][j]);
gradient_Angle[i][j] = atan2(gradient_h[i][j], gradient_v[i][j]) * ;
}
} //根据每个像素的幅值进行维度的区分分类;
for (int i = ; i<; i++){
bin[i] = ;
} for (int i = ; i<; i++){
for (int j = ; j<; j++){
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j]<) || (gradient_Angle[i][j] >= && gradient_Angle[i][j]<)){
bin[] = bin[] + gradient_M[i][j];
}
if ((gradient_Angle[i][j] >= && gradient_Angle[i][j] <= ) || (gradient_Angle[i][j] >= && gradient_Angle[i][j] <= )){
bin[] = bin[] + gradient_M[i][j];
}
}
} //归一化;
float sum_bin = ;
for (int i = ; i<; i++){
sum_bin = sum_bin + bin[i];
}
for (int i = ; i<; i++){
bin[i] = bin[i] / sum_bin;
if (bin[i]>0.2){
bin[i] = 0.2;
}
}
sum_bin = ;
for (int i = ; i<; i++){
sum_bin = sum_bin + bin[i];
}
for (int i = ; i<; i++){
bin[i] = bin[i] / sum_bin;
} //返回bin[]的值到bins向量当中;
for (int i = ; i < ; i++){
bins.push_back(bin[i]);
}
}
写完了HOG算法,下面就开始写KNN 分类器了。KNN算法很容易理解,就是在一个元素周围选取最邻近的K个元素,然后分析这k个元素当中,哪一类占的比例最大,那么这个元素就属于该类。
同样Opencv当中也有KNN算法,为类CvKNearest(),直接调用便可以进行训练,具体地可以查阅相关文档。
class KNN{
private:
vector < vector < float >> datatrain;
vector<int> dataclass;
CvKNearest *knn;
public:
KNN();
//对从HOG算法传递出来的数据进行整合处理,src表示一张图的HOG特征数组,classfile表示这张图所代表的分类;
void Data_integration(vector<float> src, int classfile);
void KNN_Train(); //将HOG得到的数据进行相关处理,然后进行KNN训练;
int KNN_Test(vector<float> src); //将KNN训练好之后,传入一个HOG特征值,返回一个分类;
}; KNN::KNN(){
knn=new CvKNearest();
} void KNN::Data_integration(vector<float> src, int classfile){
datatrain.push_back(src);
dataclass.push_back(classfile);
} void KNN::KNN_Train(){
CvMat *DataTrain=cvCreateMat(,,CV_32FC1);
CvMat *DataClass=cvCreateMat(,,CV_32FC1);
for(int i=;i<;i++){
cvmSet(DataClass,i,,dataclass[i]);
for(int j=;j<;j++){
cvmSet(DataTrain,i,j,datatrain[i][j]);
}
}
knn->train(DataTrain,DataClass,,false,,false);
} int KNN::KNN_Test(vector<float> src){
CvMat *DataSample = cvCreateMat(, , CV_32FC1);
for (int i = ; i < ; i++){
cvmSet(DataSample,,i,src[i]);
}
int k;
k = (int)knn->find_nearest(DataSample, );
return k;
}
有个HOG 和 KNN,那现在就可以进行训练了。我有了13类车牌图片进行训练,每类30张。
在这里,有一个东西要注意一下,那就是批量读取图片。我采用了一个很笨的方法,那就是把每张图片的地址存在一个txt文档当中,然后先读取地址,然后在读取图片。这样的方法,在图片数量较少的情况下可以使用的,但是图片数量成千上百张,就很麻烦了。
int main(){
HOG Hog;
KNN Knn;
string Imageadress[];
ifstream fin("train.txt"); //图片地址事先保存在train.txt文件当中;
for (int i = ; i<; i++){
getline(fin, Imageadress[i]); //从文件当中一行一行读出地址,保存到Imgaeadree当中;
} Mat Image[];
for (int i = ; i < ; i++){
Image[i] = imread(Imageadress[i], ); //读入图片文件;
} for (int i = ; i < ; i++){
int k = ;
k = i / ; //通过整除30,来获得该图片属于哪个分类当中的;
Hog.GetImage(Image[i]);
Knn.Data_integration(Hog.bins, k);
}
Knn.KNN_Train(); //进行检测;
ifstream testin("test4.txt");
string testImageadress[];
Mat testimg[];
for(int i=;i<;i++)
{
getline(testin,testImageadress[i]);
} for(int i=;i<;i++){
testimg[i]=imread(testImageadress[i],);
} int count=;
for(int i=;i<;i++){
int k;
Hog.GetImage(testimg[i]);
k=Knn.KNN_Test(Hog.bins);
cout<<k<<endl;
if(k!=){
count++;
}
}
cout<<"错误的数量:"<<count<<endl;
}
训练完毕之后,我又使用13类图片,每类70张,进行检测分类。
很不幸,识别结果不是很理想,奔驰等简单的车牌识别率很高,可以达到百分之百,但是复杂的车牌识别率就瞬间下来了,当中的原因,是因为HOG算法写得有问题啊,不够好,需要改进。
Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练的更多相关文章
- Opencv学习之路——自己编写的HOG算法
#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv ...
- opencv学习笔记(七)SVM+HOG
opencv学习笔记(七)SVM+HOG 一.简介 方向梯度直方图(Histogram of Oriented Gradient,HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子 ...
- OpenCV中基于HOG特征的行人检测
目前基于机器学习方法的行人检测的主流特征描述子之一是HOG(Histogram of Oriented Gradient, 方向梯度直方图).HOG特征是用于目标检测的特征描述子,它通过计算和统计图像 ...
- opencv学习之路(39)、PCA
一.PCA理论介绍 网上已经有许多介绍pca原理的博客,这里就不重复介绍了.详情可参考 http://blog.csdn.net/zhongkelee/article/details/44064401 ...
- Android开发学习之路--MAC下Android Studio开发环境搭建
自从毕业开始到现在还没有系统地学习android应用的开发,之前一直都是做些底层的驱动,以及linux上的c开发.虽然写过几个简单的app,也对android4.0.3的源代码做过部分的分析,也算入门 ...
- 基于HOG特征的Adaboost行人检测
原地址:http://blog.csdn.net/van_ruin/article/details/9166591 .方向梯度直方图(Histogramof Oriented Gradient, HO ...
- OpenCV 学习笔记 06 图像检索以及基于图像描述符的搜索
OpenCV 可以检测图像的主要特征,然后提取这些特征,使其成为图像描述符,这些图像特征可作为图像搜索的数据库:此外可以利用关键点将图像拼接 stitch 起来,组成一个更大的图像.如将各照片组成一个 ...
- opencv+树莓PI的基于HOG特征的行人检测
树莓PI远程控制摄像头请参考前文:http://www.cnblogs.com/yuliyang/p/3561209.html 参考:http://answers.opencv.org/questio ...
- Python下的OpenCV学习 01 —— 在Linux下安装OpenCV
一.OpenCV简要介绍 OpenCV是一个跨平台的计算机视觉库,可以运行在Windows.Linux.MacOS等操作系统上.OpenCV提供了众多语言的接口,其中就包含了Python,Python ...
随机推荐
- ES 2016+
ES2016(ES7)新增: Array.prototype.includes Exponentiation Operator 求冥运算 ES2017 (ES8)新增: ECMAScript® 201 ...
- 2015南阳CCPC L - Huatuo's Medicine 签到
L - Huatuo's Medicine Description Huatuo was a famous doctor. He use identical bottles to carry the ...
- Android 触摸提示音【转】
本文转载自:http://blog.csdn.net/Jin_HeZai/article/details/46791567 近期任务,涉及Android触摸提示音. 首先,定位源码目标.很显然的,在原 ...
- C#使用Quartz.NET详解
Quartz.NET是一个开源的作业调度框架,是OpenSymphony 的 Quartz API的.NET移植,它用C#写成,可用于winform和asp.net应用中.它提供了巨大的灵活性而不牺牲 ...
- Scikit-learn库中的数据预处理:独热编码(二)
在上一篇博客中介绍了数值型数据的预处理但是真实世界的数据集通常都含有分类型变量(categorical value)的特征.当我们讨论分类型数据时,我们不区分其取值是否有序.比如T恤尺寸是有序的,因为 ...
- B1297 [SCOI2009]迷路 矩阵
这个题我觉得很有必要写一篇博客.首先,我们需要知道,假如一个邻接矩阵只有0/1构成,那么它自己的n次方就是走n步之后的方案数.但这个题还有2~9咋办呢.我们观察发现,这个题只有10个点,而且边权< ...
- bzoj 1078 [SCOI2008]斜堆 —— 斜堆
题目:https://www.lydsy.com/JudgeOnline/problem.php?id=1078 考察斜堆的性质: 一个点如果没有左子树,也一定没有右子树: 看了这篇精美的博客:htt ...
- NET运用String的十八层境界
古往今来,文本处理一直是所有编程语言的最基础的功能,也是最核心最重要的功能.任何初学者,如果想学一门编程语言,都要面对大量的文本处理.而或许有一天,即使你成了大师级的人物,也不敢说自己驾驭文本处理的能 ...
- PCB SQL SERVER 邮箱配置与发邮件
一.开启SQL SERVER发邮件功能 --开启发邮件功能 reconfigure with override go reconfigure with override go 二.邮箱配置 1.代码创 ...
- [NOI1997] 积木游戏(dp)
COGS 261. [NOI1997] 积木游戏 http://www.cogs.pro/cogs/problem/problem.php?pid=261 ★★ 输入文件:buildinggame ...