三种特征分类器Haar、LBP和HOG

2024-06-19 09:38

本文主要是介绍三种特征分类器Haar、LBP和HOG,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

最常用到的三种特征分别为Haar特征、LBP特征及HOG特征,三种特征描述了三种不同的局部信息:

  1. Haar描述的是图像在局部范围内像素值明暗变换信息;

  2. LBP描述的是图像在局部范围内对应的纹理信息;

  3. HOG描述的则是图像在局部范围内对应的形状边缘梯度信息。

    三种特征在图像处理和机器学习领域都得到了广泛的应用,在此做一个总结,方便后面复习。

版本历程

1) Haar:因为之前从OpenCV1.0以来,一直都是只有用haar特征的级联分类器训练和检测(当时的检测函数称为cvHaarDetectObjects,训练得到的也是特征和node放在一起的xml),所以在之后当CascadeClassifier出现并统一三种特征到同一种机制和数据结构下时,没有放弃原来的C代码编写的haar检测,仍保留了原来的检测部分。另外,Haar在检测中无论是特征计算环节还是判断环节都是三种特征中最简洁的,但是笔者的经验中他的训练环节却往往是耗时最长的。

2) LBP:LBP在2.2中作为人脸检测的一种方法和Haar并列出现,他的单个点的检测方法(将在下面看到具体讨论)是三者中较为复杂的一个,所以当检测的点数相同时,如果不考虑特征计算时间,仅计算判断环节,他的时间是最长的。

3) HOG:在2.4.0中才开始出现在该类中的HOG检测,其实并不是OpenCV的新生力量,因为在较早的版本中HOG特征已经开始作为单独的行人检测模块出现。比较起来,虽然HOG在行人检测和这里的检测中同样是滑窗机制,但是一个是级联adaboost,另一个是SVM;而且HOG特征为了加入CascadeClassifier支持的特征行列改变了自身的特征计算方式:不再有相邻cell之间的影响,并且采用在Haar和LBP上都可行的积分图计算,放弃了曾经的HOGCache方式,虽然后者的加速性能远高于前者,而简单的HOG特征也使得他的分类效果有所下降(如果用SVM分类器对相同样本产生的两种HOG特征做分类,没有了相邻cell影响的计算方式下的HOG特征不那么容易完成分类)。这些是HOG为了加入CascadeClassifier而做出的牺牲,不过你肯定也想得到OpenCV保留了原有的HOG计算和检测机制。另外,HOG在特征计算环节是最耗时的,但他的判断环节和Haar一样的简洁。


1、Haar特征

    最容易接触到Haar特征地方应该就是opencv自带的人脸检测器,所采用的就是Haar特征结合Adaboost算法来实现的,利用Haar特征表征人脸在局部范围内像素值的明暗变化信息,结合积分图技巧加速训练一个级联的Adaboost分类器。Haar特征表示如图1所示。

                                                                             图1 Haar特征(摘自博客[1])

    计算过程就是黑色矩形区域内像素值之和减去白色矩形区域内像素值之和,计算过程其实很简单。但是,直接计算的话,针对每一个矩形区域,我们都需要做一次循环,计算区域内像素之和,对每个位置进行滑窗遍历进行Haar特征提取会使得计算量爆炸,因此,一般Haar特征会配合积分图技术一起来使用。

    积分图计算如图2所示,经过计算后,积分图中每个点对应值Inter(x,y)为对应蓝色矩形区域像素值之和。

                       

                                                                           图2 积分图计算示意图

    当需要提取Haar特征时,我们需要计算矩形块中像素值之和时,我们只需要将其四个顶点对应于积分图中的值拿出来,做一个求和操作即可,计算过程如图3所示。

                                   

                                                               图3 利用积分图提取Haar特征原理示意图

    图3中S1区域为要提取特征区域,I1,I2,I3,I4分别对应四个顶点位置对应于积分图中的值,由积分图计算过程不难发现:

                                                                                    I_{1}=S_{1}+S_{2}+S_{3}+S_{4}

                                                                                           I_{2}=S_{2}+S_{4}

                                                                                               I_{3}=S_{4}

                                                                                          I_{4}=S_{4} + S_{3}

    因此,S_{1}=I_{1}-I_{2}-I_{4}+I_{3},一个矩形区域内像素累加求和计算转变成了几个值的加减运算,大大的提升了算法执行效率。

2、LBP特征

    LBP特征对于传统的人脸识别而言,应该是十分有效的。LBP特征提取的思路就是,图像中某一个物体应该包含有多个像素,而且像素与像素之间位置关系应该是连续的,也即是说,在空间位置上有关联的像素信息也是有关联的,因此,可以考虑利用在空间位置上邻近的像素来对当前像素进行二进制编码,这也就是LBP。

    常见的LBP有LBP,CS-LBP,Uniform-LBP,圆形LBP和旋转不变LBP等。

    2.1 LBP、CS-LBP和Uniform-LBP

    其中,LBP、CS-LBP和Uniform-LBP都是基于当前像素的八邻域来计算的,八邻域示意图如图4所示。

                                                                          

                                                                                      图4 八邻域示意图

    LBP计算公式为:

                                                         LBP_{n_{c}}=\sum_{i=0}^{7}2^{i}*f(I_{i}-I_{c}),f(x)=\left\{\begin{matrix} 1 & x>0\\ 0 & elsewise \end{matrix}\right.

    然而原始的LBP存在以下几个问题:

    1) 固定邻域内的编码,对于尺度比较敏感,例如,人脸尺寸发生变化,人脸编码会出现误差;

    2) LBP特征的维度为2^{8}=256维,特征维度过高;

    3)对于光照、旋转等因素敏感。

    针对上述问题,CS-LBP利用中心对称的思想对局部纹理进行描述,其计算公式为:

                                                      CS-LBP_{n_{c}}=\sum_{i=0}^{3}2^{i}*f(I_{i}-I_{i+4}),f(x)=\left\{\begin{matrix} 1 & x>0\\ 0 & elsewise \end{matrix}\right.

     不难发现CS-LBP特征的维度为2^{4}=16维,相较于传统的LBP,大大地降低了特征维度,大大提升了计算效率。同时,这种对称计算的方式,能够在一定程度上应对光照、旋转等因素。

    Uniform-LBP翻译过来可以是等价模式,作者Ojala的灵感来自于,通过大量实验发现:在实际图像中,绝大多数LBP模式最多只包含两次从1到0或从0到1的跳变,因此,在实际应用中,我们只需要统计那些跳变次数在[0,2]之间的二进制模式(这些LBP也称之为等价模式,即Uniform-LBP),经过统计发现,满足这样的LBP总共只有58种,这样,256维的LBP就变成了58维的Uniform-LBP了。

    2.2 圆形LBP和旋转不变LBP

    不难发现,无论是LBP、CS-LBP还是Uniform-LBP都是固定邻域内的编码,对于尺度较为敏感,圆形LBP采用圆形邻域取代3方形邻域,并且可以通过调整半径,将3x3大小领域扩展到任意大小邻域,如图5所示。

                                                                            图5 圆形LBP计算示意图(摘自博客[2])

    对于未落在整数位置的点,可以采用双线性插值来获取,圆形LBP可以在一定程度上缓解尺度因素引起的变化,但是对于旋转因素较为敏感,因此,在圆形LBP的基础上,研究者提出了旋转不变LBP。

    旋转不变LBP对应旋转不变指的是,将圆形领域进行旋转LBP编码,将最小的LBP编码值作为当前像素点的编码值,这样,当物体发生旋转时,能够提取到的LBP编码值具备一定的旋转不变性,旋转不变LBP示意图如图6所示。

                                                                             图6 旋转不变LBP计算示意图

    这里贴一下CS-LBP+Histogram统计的代码:

// (ni - ni+4)* pow(2, i)
Mat CSLBP(const Mat & src, double * lbp_hist, Mat &out)
{Mat img;src.copyTo(img);uchar UTable[16];// 计算二进制表示,并通过查表的方式,获取其对应的等价模式下的值for (int i = 1; i < img.rows - 1; i++){for (int j = 1; j < img.cols - 1; j++){uchar code = 0;for (int m = 0; m < 4; m++){code |= (src.at<uchar>(i - 1, j - 1) >= src.at<uchar>(i + 1, j + 1)) << 0;code |= (src.at<uchar>(i, j - 1) >= src.at<uchar>(i, j + 1)) << 1;code |= (src.at<uchar>(i + 1, j - 1) >= src.at<uchar>(i - 1, j + 1)) << 2;code |= (src.at<uchar>(i + 1, j) >= src.at<uchar>(i - 1, j)) << 3;}img.at<uchar>(i, j) = code;}}out = img;for (int i = 1; i < img.rows - 1; i++){for (int j = 1; j < img.cols - 1; j++){UTable[img.at<uchar>(i, j)]++;}}// 查找最大值float max_hist_val = 0;for (int i = 0; i < 16; i++){if (max_hist_val < UTable[i]){max_hist_val = UTable[i];}}//cout << max_hist_val << endl;for (int i = 0; i < 16; i++){lbp_hist[i] = 1.0 * UTable[i] / max_hist_val;//cout << "lbp_hist: " << lbp_hist[i] << endl;}Mat LBP_hist = Mat::zeros(32, 17 * 2, CV_8U);Mat LBP_hist_color;cvtColor(LBP_hist, LBP_hist_color, COLOR_GRAY2BGR);for (int i = 0; i < 16; i++){//cout << 1 - UTable[i] << endl;rectangle(LBP_hist_color,Point(i * 2, 32),Point((i + 1) * 2, int((1 - lbp_hist[i]) * 32)),Scalar(255, 0, 0));}return LBP_hist_color;
}

    其余几种LBP,可以参考博客[4]。

3、HOG特征

    HOG特征也是一种被广泛应用的特征,这种特征最早用于行人检测领域。当然,方法都是可以相互借鉴的,在另外一个十分著名的开源库dlib中,人脸检测采用的就是HOG特征训练一个SVM分类器的思路来做的,经过评测,对比opencv的haar特征+Adaboost的做法,HOG+SVM会更加准确,当然,在速度上来说haar+Adaboost会更快。

   由于梯度主要对应于图像中的边缘, HOG的基本思路就是统计目标物体的局部形状边缘梯度信息,主要计算步骤如下:

   1) gamma变换:降低局部阴影和光照变化影响;

   2) 梯度计算:利用一阶或二阶差分近似计算图像梯度及方向

    梯度分量计算:

                                            \left\{\begin{matrix} dx= f(x+1,y)-f(x-1,y)&direction\ of \ x \\ dy=f(x,y+1)-f(x,y-1)&direction\ of\ y \end{matrix}\right.

    梯度和方向计算:

                                                                  \left\{\begin{matrix} gradient= \sqrt{dx^{2}+dy^{2}}\\ \theta=atan(\frac{dy}{dx})\end{matrix}\right.

   3) 方向划分:

    这个步骤实际上做的就是将方向对应角度区间离散化及模糊处理。首先,将方向对应角度无符号化,其实本质上就是将位于一条直线上的两个方向都视为一个角度,也即是\theta\theta-\pi视为同一个角度,其中\theta>0,这样方向范围就变成了[0,\pi];然后,将角度范围均等划分为9个bins,每一个bin对应一个角度,所有bins对应的角度为:

                                                                [0,\pi /9,2\pi /9,3\pi /9,...,8\pi /9]

    4) 梯度直方图统计:

    做梯度方向统计时,为什么要考虑对应梯度值?原因很简单,因为实际上,一个像素的梯度值越大,该像素为边缘的可能性越大,在做梯度方向统计时,会考虑到对应梯度值进行加权,然而,加权过程中存在方向位于方向划分的边界上,这个时候就将梯度平均到对应两个区间,计算过程如图7所示。

                                                            图7 梯度直方图计算示意图(摘自参考文献[3])

     例如,红色虚线对应部分,梯度方向\theta\pi /18,这时就将梯度值4平均划分给0和\pi /9对应bin,对应于0度和20度bin各自增加2。如果当前梯度方向\theta位于bins[i]bins[i+1]之间时,将梯度用插值的方式进行分配统计,统计过程如图8所示。

       

                                                                 图8 梯度直方图计算方式(摘自参考文献[3])

    计算过程如下:

                                                                          0:\frac{165-160}{20}*20=21.25

                                                                         160:\frac{180-165}{20}*20=63.75

    而单个像素的梯度对于噪声比较敏感,直接对每一个像素梯度进行统计,得到的特征可能不够鲁棒,因此,将图像进行分块统计,HOG原文是将图像划分为8x8大小的cell,cell的个数为:

                                                                          img.width/8*img.height/8

    为进一步降低HOG特征对于噪声、光照等因素的影响,将cell进一步组合,将2x2个cell组合成一个block,然后对block进行归一化处理。组合过程如图9所示。

                                                                          

                                                                   图9 cell组合成block过程示意图(摘自文献[3])

    组合完之后,每个block表示的向量大小为4x9=36,如果图片大小为128x64,那么cell的个数为:128/8x64/8=16x8,对应block个数为:(16-2+1)*(8-2+1)=15x7=105个,因此,最终得到hog特征的维度为36x105=3780维。

    

~~~~未完待续,后面补充代码及应用。

参考文献:

[1] https://blog.csdn.net/xiaowei_cqu/article/details/8216109

[2] https://blog.csdn.net/kuweicai/article/details/79039218

[3] https://www.learnopencv.com/histogram-of-oriented-gradients/

[4] https://blog.csdn.net/lsq2902101015/article/details/48680779

 

 

这篇关于三种特征分类器Haar、LBP和HOG的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1074670

相关文章

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

详解Java中三种状态机实现方式来优雅消灭 if-else 嵌套

《详解Java中三种状态机实现方式来优雅消灭if-else嵌套》这篇文章主要为大家详细介绍了Java中三种状态机实现方式从而优雅消灭if-else嵌套,文中的示例代码讲解详细,感兴趣的小伙伴可以跟... 目录1. 前言2. 复现传统if-else实现的业务场景问题3. 用状态机模式改造3.1 定义状态接口3

redis中session会话共享的三种方案

《redis中session会话共享的三种方案》本文探讨了分布式系统中Session共享的三种解决方案,包括粘性会话、Session复制以及基于Redis的集中存储,具有一定的参考价值,感兴趣的可以了... 目录三种解决方案粘性会话(Sticky Sessions)Session复制Redis统一存储Spr

Python清空Word段落样式的三种方法

《Python清空Word段落样式的三种方法》:本文主要介绍如何用python-docx库清空Word段落样式,提供三种方法:设置为Normal样式、清除直接格式、创建新Normal样式,注意需重... 目录方法一:直接设置段落样式为"Normal"方法二:清除所有直接格式设置方法三:创建新的Normal样

把Python列表中的元素移动到开头的三种方法

《把Python列表中的元素移动到开头的三种方法》在Python编程中,我们经常需要对列表(list)进行操作,有时,我们希望将列表中的某个元素移动到最前面,使其成为第一项,本文给大家介绍了把Pyth... 目录一、查找删除插入法1. 找到元素的索引2. 移除元素3. 插入到列表开头二、使用列表切片(Lis

Java继承映射的三种使用方法示例

《Java继承映射的三种使用方法示例》继承在Java中扮演着重要的角色,它允许我们创建一个类(子类),该类继承另一个类(父类)的所有属性和方法,:本文主要介绍Java继承映射的三种使用方法示例,需... 目录前言一、单表继承(Single Table Inheritance)1-1、原理1-2、使用方法1-

HTML5 中的<button>标签用法和特征

《HTML5中的<button>标签用法和特征》在HTML5中,button标签用于定义一个可点击的按钮,它是创建交互式网页的重要元素之一,本文将深入解析HTML5中的button标签,详细介绍其属... 目录引言<button> 标签的基本用法<button> 标签的属性typevaluedisabled

Java调用C#动态库的三种方法详解

《Java调用C#动态库的三种方法详解》在这个多语言编程的时代,Java和C#就像两位才华横溢的舞者,各自在不同的舞台上展现着独特的魅力,然而,当它们携手合作时,又会碰撞出怎样绚丽的火花呢?今天,我们... 目录方法1:C++/CLI搭建桥梁——Java ↔ C# 的“翻译官”步骤1:创建C#类库(.NET

java对接第三方接口的三种实现方式

《java对接第三方接口的三种实现方式》:本文主要介绍java对接第三方接口的三种实现方式,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录HttpURLConnection调用方法CloseableHttpClient调用RestTemplate调用总结在日常工作

SpringBoot实现接口数据加解密的三种实战方案

《SpringBoot实现接口数据加解密的三种实战方案》在金融支付、用户隐私信息传输等场景中,接口数据若以明文传输,极易被中间人攻击窃取,SpringBoot提供了多种优雅的加解密实现方案,本文将从原... 目录一、为什么需要接口数据加解密?二、核心加解密算法选择1. 对称加密(AES)2. 非对称加密(R