欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

HOG ,SIFT 特征实现

程序员文章站 2022-07-14 23:51:44
...

http://blog.csdn.net/q123456789098/article/details/52748918   讲的很清晰

HOG特征:


方向梯度直方图(Histogram of Oriented Gradient, HOG)特征是一种在计算机视觉和图像处理中用来进行物体检测的特征描述子。它通过计算和统计图像局部区域的梯度方向直方图来构成特征。Hog特征结合SVM分类器已经被广泛应用于图像识别中,尤其在行人检测中获得了极大的成功。需要提醒的是,HOG+SVM进行行人检测的方法是法国研究人员Dalal在2005的CVPR上提出的,而如今虽然有很多行人检测算法不断提出,但基本都是以HOG+SVM的思路为主。
(1)主要思想:
在一副图像中,局部目标的表象和形状(appearance and shape)能够被梯度或边缘的方向密度分布很好地描述。(本质:梯度的统计信息,而梯度主要存在于边缘的地方)。
(2)具体的实现方法是:
首先将图像分成小的连通区域,我们把它叫细胞单元。然后采集细胞单元中各像素点的梯度的或边缘的方向直方图。最后把这些直方图组合起来就可以构成特征描述器。
(3)提高性能:
把这些局部直方图在图像的更大的范围内(我们把它叫区间或block)进行对比度归一化(contrast-normalized),所采用的方法是:先计算各直方图在这个区间(block)中的密度,然后根据这个密度对区间中的各个细胞单元做归一化。通过这个归一化后,能对光照变化和阴影获得更好的效果。
(4)优点:
与其他的特征描述方法相比,HOG有很多优点。首先,由于HOG是在图像的局部方格单元上操作,所以它对图像几何的和光学的形变都能保持很好的不变性,这两种形变只会出现在更大的空间领域上。其次,在粗的空域抽样、精细的方向抽样以及较强的局部光学归一化等条件下,只要行人大体上能够保持直立的姿势,可以容许行人有一些细微的肢体动作,这些细微的动作可以被忽略而不影响检测效果。因此HOG特征是特别适合于做图像中的人体检测的。
 
2、HOG特征提取算法的实现过程:
大概过程:
HOG特征提取方法就是将一个image(你要检测的目标或者扫描窗口):
1)灰度化(将图像看做一个x,y,z(灰度)的三维图像);
2)采用Gamma校正法对输入图像进行颜色空间的标准化(归一化);目的是调节图像的对比度,降低图像局部的阴影和光照变化所造成的影响,同时可以抑制噪音的干扰;
3)计算图像每个像素的梯度(包括大小和方向);主要是为了捕获轮廓信息,同时进一步弱化光照的干扰。
4)将图像划分成小cells(例如6*6像素/cell);
5)统计每个cell的梯度直方图(不同梯度的个数),即可形成每个cell的descriptor;
6)将每几个cell组成一个block(例如3*3个cell/block),一个block内所有cell的特征descriptor串联起来便得到该block的HOG特征descriptor。
7)将图像image内的所有block的HOG特征descriptor串联起来就可以得到该image(你要检测的目标)的HOG特征descriptor了。这个就是最终的可供分类使用的特征向量了。
HOG ,SIFT 特征实现

 具体每一步的详细过程如下:
(1)标准化gamma空间和颜色空间
为了减少光照因素的影响,首先需要将整个图像进行规范化(归一化)。在图像的纹理强度中,局部的表层曝光贡献的比重较大,所以,这种压缩处理能够有效地降低图像局部的阴影和光照变化。因为颜色信息作用不大,通常先转化为灰度图;
Gamma压缩公式:

HOG ,SIFT 特征实现

比如可以取Gamma=1/2;

(2)计算图像梯度
计算图像横坐标和纵坐标方向的梯度,并据此计算每个像素位置的梯度方向值;求导操作不仅能够捕获轮廓,人影和一些纹理信息,还能进一步弱化光照的影响。
图像中像素点(x,y)的梯度为

HOG ,SIFT 特征实现

最常用的方法是:首先用[-1,0,1]梯度算子对原图像做卷积运算,得到x方向(水平方向,以向右为正方向)的梯度分量gradscalx,然后用[1,0,-1]T梯度算子对原图像做卷积运算,得到y方向(竖直方向,以向上为正方向)的梯度分量gradscaly。然后再用以上公式计算该像素点的梯度大小和方向。
 
(3)为每个细胞单元构建梯度方向直方图
第三步的目的是为局部图像区域提供一个编码,同时能够保持对图像中人体对象的姿势和外观的弱敏感性。
我们将图像分成若干个“单元格cell”,例如每个cell为6*6个像素。假设我们采用9个bin的直方图来统计这6*6个像素的梯度信息。也就是将cell的梯度方向360度分成9个方向块,如图所示:例如:如果这个像素的梯度方向是20-40度,直方图第2个bin的计数就加一,这样,对cell内每个像素用梯度方向在直方图中进行加权投影(映射到固定的角度范围),就可以得到这个cell的梯度方向直方图了,就是该cell对应的9维特征向量(因为有9个bin)。
像素梯度方向用到了,那么梯度大小呢?梯度大小就是作为投影的权值的。例如说:这个像素的梯度方向是20-40度,然后它的梯度大小是2(假设啊),那么直方图第2个bin的计数就不是加一了,而是加二(假设啊)。
HOG ,SIFT 特征实现

细胞单元可以是矩形的(rectangular),也可以是星形的(radial)。
 (4)把细胞单元组合成大的块(block),块内归一化梯度直方图
由于局部光照的变化以及前景-背景对比度的变化,使得梯度强度的变化范围非常大。这就需要对梯度强度做归一化。归一化能够进一步地对光照、阴影和边缘进行压缩。
作者采取的办法是:把各个细胞单元组合成大的、空间上连通的区间(blocks)。这样,一个block内所有cell的特征向量串联起来便得到该block的HOG特征。这些区间是互有重叠的,这就意味着:每一个单元格的特征会以不同的结果多次出现在最后的特征向量中。我们将归一化之后的块描述符(向量)就称之为HOG描述符。
区间有两个主要的几何形状——矩形区间(R-HOG)和环形区间(C-HOG)。R-HOG区间大体上是一些方形的格子,它可以有三个参数来表征:每个区间中细胞单元的数目、每个细胞单元中像素点的数目、每个细胞的直方图通道数目。
例如:行人检测的最佳参数设置是:3×3细胞/区间、6×6像素/细胞、9个直方图通道。则一块的特征数为:3*3*9;
 
(6)那么一个图像的HOG特征维数是多少呢?  (HOG 直观认识)
顺便做个总结:Dalal提出的Hog特征提取的过程:把样本图像分割为若干个像素的单元(cell),把梯度方向平均划分为9个区间(bin),在每个单元里面对所有像素的梯度方向在各个方向区间进行直方图统计,得到一个9维的特征向量,每相邻的4个单元构成一个块(block),把一个块内的特征向量联起来得到36维的特征向量,用块对样本图像进行扫描,扫描步长为一个单元。最后将所有块的特征串联起来,就得到了人体的特征。例如,对于64*128的图像而言,每16*16的像素组成一个cell,每2*2个cell组成一个块,因为每个cell有9个特征,所以每个块内有4*9=36个特征,以8个像素为步长,那么,水平方向将有7个扫描窗口,垂直方向将有15个扫描窗口。也就是说,64*128的图片,总共有36*7*15=3780个特征。

 

简介

        HOGHistogram of Oriented Gridients的简写)特征检测算法,最早是由法国研究员Dalal等在CVPR-2005上提出来的,一种解决人体目标检测的图像描述子,是一种用于表征图像局部梯度方向和梯度强度分布特性的描述符。其主要思想是:在边缘具体位置未知的情况下,边缘方向的分布也可以很好的表示行人目标的外形轮廓。

        Dalal等提出的HOG+SVM算法,在进行行人检测取得了极大地成功后,更多新算法不断涌现,不过大都是以HOG+SVM的思路为主线。

HOG特征算法

        HOG特征检测算法的几个步骤:颜色空间归一化—>梯度计算—>梯度方向直方图—>重叠块直方图归一化—>HOG特征。下面分别对其进行介绍。

1、颜色空间归一化

        由于图像的采集环境、装置等因素,采集到的人脸图像效果可能不是很好,容易出现误检或漏检的情况,所以需要对采集到的人脸进行图像预处理,主要是处理光线太暗或太强的情况,这里有两次处理:图像灰度化、Gamma校正。

①图像灰度化

       对于彩色图像,将RGB分量转化成灰度图像,其转化公式为:

HOG ,SIFT 特征实现

②Gamma校正

       在图像照度不均匀的情况下,可以通过Gamma校正,将图像整体亮度提高或降低。在实际中可以采用两种不同的方式进行Gamma标准化,平方根、对数法。这里我们采用平方根的办法,公式如下(其中γ=0.5):

HOG ,SIFT 特征实现

代码:

int main()

{

Mat picture = imread("test.jpg", 0);//灰度

Mat img;

picture.convertTo(img, CV_32F); //转换成浮点

sqrt(img, img); //gamma校正

normalize(img, img, 0, 255, NORM_MINMAX, CV_8UC1);//归一化像素值[0,255]

imshow("原图", picture);

imshow("Gamma校正", img);

waitKey();


return 0;
}

结果:

HOG ,SIFT 特征实现HOG ,SIFT 特征实现

2、梯度计算

对经过颜色空间归一化后的图像,求取其梯度及梯度方向。分别在水平和垂直方向进行计算,梯度算子为:

HOG ,SIFT 特征实现

HOG ,SIFT 特征实现

代码:

/*****************************************

Copyright (c) 2015 Jingshuang Hu


@filename:demo.cpp

@datetime:2015.08.06

@author:HJS

@e-mail:aaa@qq.com

@blog:http://blog.csdn.net/hujingshuang

*****************************************/


#include <iostream>

#include <cv.h>

#include <opencv2/core/core.hpp>

#include <opencv2/highgui/highgui.hpp>

#include <opencv2/imgproc/imgproc.hpp>


using namespace cv;

using namespace std;


int main()

{

Mat picture = imread("test.jpg", 0);//灰度

Mat img;


picture.convertTo(img, CV_32F); //转换成浮点

sqrt(img, img); //gamma校正

normalize(img, img, 0, 255, NORM_MINMAX, CV_32F);//归一化[0,255]浮点数


Mat gradient = Mat::zeros(img.rows, img.cols, CV_32F);//梯度

Mat theta = Mat::zeros(img.rows, img.cols, CV_32F);//角度


for (int i = 1; i < img.rows - 1; i++)

{

for (int j = 1; j < img.cols - 1; j++)

{

float Gx, Gy;


Gx = img.at<float>(i, j + 1) - img.at<float>(i, j - 1);

Gy = img.at<float>(i + 1, j) - img.at<float>(i - 1, j);


gradient.at<float>(i, j) = sqrt(Gx * Gx + Gy * Gy);//梯度模值

theta.at<float>(i, j) = float(atan2(Gy, Gx) * 180 / CV_PI);//梯度方向[-180°,180°]

}

}


normalize(gradient, gradient, 0, 255, NORM_MINMAX, CV_8UC1);//归一化[0,255] 无符号整型

normalize(img, img, 0, 255, NORM_MINMAX, CV_8UC1);


imshow("原图", picture);

imshow("Gamma校正", img);

imshow("梯度图", gradient);

waitKey();


return 0;

}

结果:

 

HOG ,SIFT 特征实现HOG ,SIFT 特征实现HOG ,SIFT 特征实现

3、梯度方向直方图

        将图像划分成若干个cells(单元),8x8=64个像素为一个cell,相邻的cell之间不重叠。在每个cell内统计梯度方向直方图,将所有梯度方向划分为9bin(即9维特征向量),作为直方图的横轴,角度范围所对应的梯度值累加值作为直方图纵轴,每个bin的角度范围如下。

HOG ,SIFT 特征实现

4、重叠块直方图归一化

        【以下有关计算,请认真分析】假设有一幅图像大小为220x310,将其划分成若干个8x8cells,显然220÷8=27.5、310÷8=38.75不是整数,也就是说划分之后依然还有多余像素不能构成cell。处理办法是将图像缩放成能被8整除的长宽(如216x304),再划分。216÷8=27,304÷8=38,因此,216x304的图像可以得到27x38cells,没有重叠。

Mat picture = imread("test.jpg", 0);//灰度

resize(picture, picture, cvSize(int(picture.cols / 8) * 8, int(picture.rows / 8) * 8));//转化成能被8除尽的行、列
   由于图像中光照情况和背景的变化多样,梯度值的变化范围会比较大,因而良好的特征标准化对于检测率的提高相当重要。标准化的方法多种多样,大多数的都是将celll放在block中,然后标准化每个block。

        以上述缩放后的图像为例,共得到27x38cell,也就是将图像划分成了27x38个单元;将上下左右相邻的2x2cells当做一个block整体,如下所示(为方便观察,每个颜色框故意错开了一点),黑色8x8像素为一个cell粉红绿框都是一个block,即每个框内2x2cell组成一个block。故27x38cell可划分成26x37block,每个block16x16像素。相邻block之间是有重叠的,这样有效的利用了相邻像素信息,对检测结果有很大的帮助。

HOG ,SIFT 特征实现

接下分别对每个block进行标准化,一个block内有4cell,每个cell9维特征向量,故每个block就由4x9=36维特征向量来表征。

HOG ,SIFT 特征实现

由于L2-norm简单且在检测中效果相对较好,故一般采用它。

        经过上述对有重叠部分block的直方图归一化之后,将所有block的特征向量都组合起来,则形成26x37x36=34632维特征向量,这就是HOG特征,这个特征向量就可以用来表征整个图像了。

        实际上,在运用的时候,我们通常是选取一幅图像中的一个窗口来进行特征提取,依然以上述220X310大小图像为例,经过缩放处理后为216x304,但并不直接提取整个图像的HOG特征,而是用一个固定大小的窗口在图像上滑动,滑动的间隔为8个像素,opencv中默认的窗口大小为128x64(高128,宽64),即有(128÷8)x(64÷8)=16x8cell,也即有15x7block,这样一来一幅图像就可以取到(27-16)x(38-8)=11x30=330(27-15)x(38-7)=12x31=372个窗口(更正于:2018-04-15)。现在提取每个窗口的HOG特征,则可得到105x36=3780HOG特征向量。

        将这3303780维的HOG特征当做测试样本,用支持向量机(SVM)分类器来判别出,这些窗口的HOG特征是否有行人,有行人的用矩形框标记起来。HOG行人特征及所对应的SVM分类器的参数,在opencv中已经训练好了,我们只需要得到HOG特征,然后调用SVM即可得到判别结果。

以上是个人对HOG算法的理解,若理解不到位或者有误的,请多多指教!

代码:

 

/*****************************************

Copyright (c) 2015 Jingshuang Hu


@filename:demo.cpp

@datetime:2015.08.06

@author:HJS

@e-mail:aaa@qq.com

@blog:http://blog.csdn.net/hujingshuang

*****************************************/


#include <iostream>

#include <opencv2/opencv.hpp>


using namespace cv;

using namespace std;


int main()

{

Mat image = imread("test.jpg");

// 1. 定义HOG对象

HOGDescriptor hog(Size(64,128),Size(16,16),Size(8,8),Size(8,8),9);//HOG检测器,用来计算HOG描述子的

// 2. 设置SVM分类器

hog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); // 采用已经训练好的行人检测分类器

// 3. 在测试图像上检测行人区域

vector<cv::Rect> regions;

hog.detectMultiScale(image, regions, 0, Size(8,8), Size(32,32), 1.05, 1);

// 显示

for (size_t i = 0; i < regions.size(); i++)

{

rectangle(image, regions[i], Scalar(0,0,255), 2);

}

imshow("HOG行人检测", image);

waitKey();


return 0;

}

结果:

HOG ,SIFT 特征实现

HOG ,SIFT 特征实现

从图中可以看出,依然是有漏检的情况。

源码分析:

1、opencv源码解析之(6):hog源码分析

2、目标检测学习_1(用opencv自带hog实现行人检测)

3、HOG:从理论到OpenCV实践

4、opencv之HOG源代码注释

5、opencv之HOG源代码分析

 

 

 

 

FHOG

作者在传统的hog特征上进行了一些改进,这种改进的思路提供了一种把高维特征融入到相关滤波框架中的一种方法:这种方法在论文中作者基本没提,只说了参考论文:Object Detection with Discriminatively Trained Part Based Models,论文的第六部分详细说明了hog特征和fhog特征的提取方法,对于传统的hog特征还是做了一些改进。
下面说明这种方法:

1.建立像素级特征映射

 

 

首先是计算每个像素的梯度大小和方向,分别记为:

HOG ,SIFT 特征实现

 

 

然后把每个像素的梯度方向离散到p的值中的一个,可以使用对方向敏感 B1(0-360度)也可以使用对方向不敏感 B2(0-180度)。

HOG ,SIFT 特征实现


下面使用B表示B1和B2。
我们定义一个像素级的特征映射,指定每个像素梯度幅值的稀疏直方图,设b的取值为:

HOG ,SIFT 特征实现

 

 

则 (x,y)处的特征向量为:

HOG ,SIFT 特征实现

其他情况都为0.
这样的描述看起来很高级,实际上说明的问题很简单,和传统hog统计是基本一致的,我们可以认为F是有p个方向通道的映射,对于每个像素来说,通过其方向算出来的B,可以用来计算它在F的哪个方向有映射,而这个映射的带下使用其幅值来加权的。

2. 空间聚合。

 

 

设F是一个w*h大小图像的像素级特征映射,K>0是我们定义的cell的大小,通过像素级特征映射的空间聚合来得到基于cell的特征映射,也就是每一个cell一个特征,特征向量记为:

HOG ,SIFT 特征实现

 

 

其中:

HOG ,SIFT 特征实现

这种形式可以使特征具有对微小形变的不变性,并可以减少特征映射尺寸。
最简单的方法是将像素 (x,y)映射到一个cell中,定义这个cell的特征为整个cell内所有像素特征的均值或和(都是一样的,后期还要进行归一化处理),这是一种很暴力的方法,简单也有效,如果要进一步提高hog特征的描述性能。作者还提供了一种方法,利用三线插值进行处理,这种处理也是合理的。能进一步较小混叠效应,关于插值处理的具体理论和方法见:hog之三线插值。通过插值可以使得每个像素对其周围的四个cell的特征向量产生贡献。

3.归一化和截断。

 

 

梯度对偏置改变具有不变性,这种不变性是通过归一化获得的,这篇论文里作者定义了四种不同的归一化因子。将这些因子定义为 :

HOG ,SIFT 特征实现

 

 

其中 :

HOG ,SIFT 特征实现

归一化因子定义为:

HOG ,SIFT 特征实现

每个因子都包含四个cell的能量,这里用的是二范数。

HOG ,SIFT 特征实现

HOG ,SIFT 特征实现

 

上面这个式子表示了这四种不同的归一化方式,分别是用当前这个cell周围和包括自己的cell能量来进行归一化,下面用一个示意图来表示:

HOG ,SIFT 特征实现

如图1-9分别是9个cell,考虑cell5,27式所表达的四个归一化因子分别是:cell 1,2,4,5的能量和,cell2,3,5,6的能量和等。也就是说对于每个cell来说分别用包括自身在内的9个cell分别组合来归一化cell的特征,然后再截断,假设我们选择角度区间为9个,那么对于每个cell来说,这样的操作会获得36维的一个特征,这就是相关滤波框架中使用的hog特征,在论文中,作者还提供了一种特征选项,称之为Fhog,下面介绍。

4.FHOG PCA降维

在论文的6.2部分,作者着重介绍了fhog的来源和取法。
作者从大量各种分辨率的图片中收集了很多36维特征(按照之前的定义),并且在这些特征上进行了PCA分析,发现了了一个现象:由前11个主特征向量定义的线性子空间基本包含了hog特征的所有信息。并且用降维之后的特征在他们的任务(目标检测)中取得了和用36维特征一样的结果。

HOG ,SIFT 特征实现


上图显示了36维hog特征的主成分分析,每个特征向量显示为4*9的矩阵,这样也是合理的,每一列对应梯度直方图的一个bin,特征值在特征向量的上方。注意到,前十一个特征向量的行或者列近似为一个定值。所以说,主特征向量所依赖的线性子空间可以由沿其矩阵表达的某一行或者某一列稀疏向量表示。

HOG ,SIFT 特征实现

 

HOG ,SIFT 特征实现

HOG ,SIFT 特征实现

 

这样我们可以定义一个13维特征,其中的元素是36为特征与每个u_k和v_k的点积。作者通过实验发现:36维特征PCA降维之后的11维特征和我们刚才这样定义得到的13维特征,在实验任务中可以取得相同的表现,而且13维特征要比PCA计算11维特征简单的多(只需36维特征求每行和及每列和)。而且13为特征有一个比较简单的解释:9个方向特征以及反映cell周围区域能量的四个特征。
前面谈到了对方向不敏感的bin划分和敏感的bin划分,作者在最后提出了一种结合这两种方式的划分方式:分别对原图进行对方向敏感和不敏感的像素级特征映射(这样会获得9+18维特征向量),然后再利用式26和27进行归一化和截断处理,这样会获得一个4*(18+9)=108维的特征向量,如果用这么大的特征维数显然是复杂的,于是我们和上面36维的处理一样,对这些进行投影和点积处理。
最终得到的是一个27+4=31维的向量,其中包括:27个在不同归一化因子上的累加和(列和)以及4个在不同方向上的累加和(行和)。27维中包含了27个bin通道,其中18个对方向敏感,9个对方向不敏感,4维分别捕获了当前cell周围4个cell组成的梯度能量。下图形象描述了这一个过程:

HOG ,SIFT 特征实现

至此,hog的两个改进版本介绍完毕。所有的精华都浓缩到这张图里。可惜我是写到这里猜找到的这张图,看论文看了好久才完全看懂这里。

 

 

 

SIFT :scale invariant feature transform



这两种方法都是基于图像中梯度的方向直方图的特征提取方法。
1. SIFT 特征 
    实现方法:
    SIFT 特征通常与使用SIFT检测器得到的感兴趣点一起使用。这些感兴趣点与一个特定的方向和尺度(scale)相关联。通常是在对一个图像中的方形区域通过相应的方向和尺度变换后,再计算该区域的SIFT特征。
    首先计算梯度方向和幅值(使用Canny边缘算子在感兴趣点的周围16X16像素点区域计算)。对得到的方向在0-360度范围内分成八个区间,然后将16X16大小的区域分成不重合的4X4个单元,每个单元内计算梯度方向直方图(八个区间)。一共得到16个单元的直方图,将这些直方图接连起来得到长度为128X1的向量,然后将该向量归一化。
    特点:
  (1)由于使用梯度进行计算,该特征计算方法对恒定的灰度变化具有不变性。
  (2)最后一步中的归一化过程使该特征对图像对比度具有一定不变性。
  (3)由于在4X4的单元内计算直方图,该特征不会受到一些小的形变的影响。

HOG ,SIFT 特征实现

 

 

相关标签: HOG