博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Opencv学习之路—Opencv下基于HOG特征的KNN算法分类训练
阅读量:5965 次
发布时间:2019-06-19

本文共 7483 字,大约阅读时间需要 24 分钟。

在计算机视觉研究当中,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
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 = 1; i <= img.rows - 17; i = i + 8){ for (int j = 1; j <= img.cols - 17; j = j + 8){ Cut_to_Cell(i, j); } }}void HOG::Cut_to_Cell(int pixel_x, int pixel_y){ for (int i = pixel_x, m = 0; m < 2; i = i + 8, m++){ for (int j = pixel_y, n = 0; n < 2; j = j + 8, 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[10][10]; //我们一般默认cell为8*8的像素大小,但是为了储存周边店的像素,需要多加两个像素储存点的位置; float gradient_M[9][9]; //保存梯度的幅值; float gradient_Angle[9][9]; //保存像素梯度的方向; float gradient_h[9][9]; float gradient_v[9][9]; float bin[9]; //存放一个Cell当中的bins值; pixel_x = x; pixel_y = y; //为了计算方便,我们将每个Cell的像素先提取出来,存放在pixel[][]当中; for (int i = pixel_x - 1, m = 0; i < pixel_x + 9; i++, m++){ uchar *data = img.ptr
(i); for (int j = pixel_y - 1, n = 0; j < pixel_y + 9; j++, n++){ pixel[m][n] = data[j]; } } //计算每个像素的梯度幅值和梯度角度; for (int i = 1; i<9; i++){ for (int j = 1; j<9; j++){ gradient_h[i][j] = pixel[i + 1][j] - pixel[i - 1][j]; gradient_v[i][j] = pixel[i][j + 1] - pixel[i][j - 1]; 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]) * 180; } } //根据每个像素的幅值进行维度的区分分类; for (int i = 0; i<9; i++){ bin[i] = 0; } for (int i = 1; i<9; i++){ for (int j = 1; j<9; j++){ if ((gradient_Angle[i][j] >= 0 && gradient_Angle[i][j]<20) || (gradient_Angle[i][j] >= 180 && gradient_Angle[i][j]<200)){ bin[0] = bin[0] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 20 && gradient_Angle[i][j]<40) || (gradient_Angle[i][j] >= 200 && gradient_Angle[i][j]<220)){ bin[1] = bin[1] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 40 && gradient_Angle[i][j]<60) || (gradient_Angle[i][j] >= 220 && gradient_Angle[i][j]<240)){ bin[2] = bin[2] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 60 && gradient_Angle[i][j]<80) || (gradient_Angle[i][j] >= 240 && gradient_Angle[i][j]<260)){ bin[3] = bin[3] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 80 && gradient_Angle[i][j]<100) || (gradient_Angle[i][j] >= 260 && gradient_Angle[i][j]<280)){ bin[4] = bin[4] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 100 && gradient_Angle[i][j]<120) || (gradient_Angle[i][j] >= 280 && gradient_Angle[i][j]<300)){ bin[5] = bin[5] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 120 && gradient_Angle[i][j]<140) || (gradient_Angle[i][j] >= 300 && gradient_Angle[i][j]<320)){ bin[6] = bin[6] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 140 && gradient_Angle[i][j]<160) || (gradient_Angle[i][j] >= 320 && gradient_Angle[i][j]<340)){ bin[7] = bin[7] + gradient_M[i][j]; } if ((gradient_Angle[i][j] >= 160 && gradient_Angle[i][j] <= 180) || (gradient_Angle[i][j] >= 340 && gradient_Angle[i][j] <= 360)){ bin[8] = bin[8] + gradient_M[i][j]; } } } //归一化; float sum_bin = 0; for (int i = 0; i<9; i++){ sum_bin = sum_bin + bin[i]; } for (int i = 0; i<9; i++){ bin[i] = bin[i] / sum_bin; if (bin[i]>0.2){ bin[i] = 0.2; } } sum_bin = 0; for (int i = 0; i<9; i++){ sum_bin = sum_bin + bin[i]; } for (int i = 0; i<9; i++){ bin[i] = bin[i] / sum_bin; } //返回bin[]的值到bins向量当中; for (int i = 0; i < 9; i++){ bins.push_back(bin[i]); }}

写完了HOG算法,下面就开始写KNN 分类器了。KNN算法很容易理解,就是在一个元素周围选取最邻近的K个元素,然后分析这k个元素当中,哪一类占的比例最大,那么这个元素就属于该类。

同样Opencv当中也有KNN算法,为类CvKNearest(),直接调用便可以进行训练,具体地可以查阅相关文档。

class KNN{private:    vector < vector < float >> datatrain;    vector
dataclass; CvKNearest *knn;public: KNN(); //对从HOG算法传递出来的数据进行整合处理,src表示一张图的HOG特征数组,classfile表示这张图所代表的分类; void Data_integration(vector
src, int classfile); void KNN_Train(); //将HOG得到的数据进行相关处理,然后进行KNN训练; int KNN_Test(vector
src); //将KNN训练好之后,传入一个HOG特征值,返回一个分类;};KNN::KNN(){ knn=new CvKNearest();}void KNN::Data_integration(vector
src, int classfile){ datatrain.push_back(src); dataclass.push_back(classfile);}void KNN::KNN_Train(){ CvMat *DataTrain=cvCreateMat(390,900,CV_32FC1); CvMat *DataClass=cvCreateMat(390,1,CV_32FC1); for(int i=0;i<390;i++){ cvmSet(DataClass,i,0,dataclass[i]); for(int j=0;j<900;j++){ cvmSet(DataTrain,i,j,datatrain[i][j]); } } knn->train(DataTrain,DataClass,0,false,30,false);}int KNN::KNN_Test(vector
src){ CvMat *DataSample = cvCreateMat(1, 900, CV_32FC1); for (int i = 0; i < 900; i++){ cvmSet(DataSample,0,i,src[i]); } int k; k = (int)knn->find_nearest(DataSample, 30); return k;}

有个HOG 和 KNN,那现在就可以进行训练了。我有了13类车牌图片进行训练,每类30张。

在这里,有一个东西要注意一下,那就是批量读取图片。我采用了一个很笨的方法,那就是把每张图片的地址存在一个txt文档当中,然后先读取地址,然后在读取图片。这样的方法,在图片数量较少的情况下可以使用的,但是图片数量成千上百张,就很麻烦了。

int main(){    HOG Hog;    KNN Knn;    string Imageadress[390];    ifstream fin("train.txt");           //图片地址事先保存在train.txt文件当中;    for (int i = 0; i<390; i++){        getline(fin, Imageadress[i]);    //从文件当中一行一行读出地址,保存到Imgaeadree当中;    }    Mat Image[390];    for (int i = 0; i < 390; i++){        Image[i] = imread(Imageadress[i], 1);   //读入图片文件;    }    for (int i = 0; i < 390; i++){        int k = 0;        k = i / 30;             //通过整除30,来获得该图片属于哪个分类当中的;        Hog.GetImage(Image[i]);        Knn.Data_integration(Hog.bins, k);    }    Knn.KNN_Train();    //进行检测;    ifstream testin("test4.txt");    string testImageadress[70];    Mat testimg[70];    for(int i=0;i<70;i++)    {        getline(testin,testImageadress[i]);    }    for(int i=0;i<70;i++){        testimg[i]=imread(testImageadress[i],1);    }    int count=0;    for(int i=0;i<70;i++){        int k;        Hog.GetImage(testimg[i]);        k=Knn.KNN_Test(Hog.bins);        cout<
<

训练完毕之后,我又使用13类图片,每类70张,进行检测分类。

很不幸,识别结果不是很理想,奔驰等简单的车牌识别率很高,可以达到百分之百,但是复杂的车牌识别率就瞬间下来了,当中的原因,是因为HOG算法写得有问题啊,不够好,需要改进。

转载于:https://www.cnblogs.com/code-wangjun/p/5898188.html

你可能感兴趣的文章
ASP.NET MVC 入门8、ModelState与数据验证
查看>>
linux进程调度之 FIFO 和 RR 调度策略---SYSTEMTAP
查看>>
JSTL的相关使用
查看>>
ActiveMQ, RabbitMQ和ZeroMQ 选型关注点
查看>>
王垠:完全用Linux工作
查看>>
Understanding the Router
查看>>
红米3 Flyme5.1.9.5插桩适配长期不定时更新
查看>>
MySQL 5.6 for Windows 解压缩版配置安装(转)
查看>>
组件居中显示 安卓
查看>>
delete
查看>>
sql server生成不重复的时间字符串
查看>>
DataBase 之 数据库设计六大范式
查看>>
比特币钱包安全
查看>>
Lucene就是这么简单
查看>>
2015年第6届蓝桥杯Java B组省赛试题解析
查看>>
一个有味道的函数
查看>>
zookeeper在linux环境安装
查看>>
Python_异常和模块
查看>>
【386天】跃迁之路——程序员高效学习方法论探索系列(实验阶段143-2018.02.26)...
查看>>
Java数据类型分类
查看>>