HOG特征检测学习笔记

HOG简介

HOG(Histogram of Oriented Gridients)特征检测算法,最早由法国研究院Dalal等在CVPR2005上提出,是一种用于检测人体目标检测的图像描述子,用于表征图像局部梯度方向和梯度强度分布特性。其主要思想是:在边缘具体位置未知的情况下,边缘方向的分布也可以很好地表示行人目标的外形轮廓。Dalal等提出的HOG+SVM算法当时在行人检测上取得了巨大的成功,而此后涌现的许多算法,大多是以HOG+SVM的思想为主线。

HOG特征算法流程

大致分为以下几个步骤:颜色空间归一化(Gamma校正)–>梯度计算–>梯度方向直方图–>重叠块直方图归一化–>HOG特征。

1、颜色空间归一化

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

a、图像灰度化

彩色图像有R、G、B,3个颜色通道,将其转换为单通道的灰度图像。很简单,使用以下公式:

gray=0.3red+0.59green+0.11blue g r a y = 0.3 ∗ r e d + 0.59 ∗ g r e e n + 0.11 ∗ b l u e

b、Gamma校正

在图像亮度不均匀的情况下,可以通过Gamma校正来将图像中整体亮度提高或降低。公式如下:

Y(x,y)=I(x,y)γ Y ( x , y ) = I ( x , y ) γ

其中, γ γ 为权值。在这里我们令 γ=0.5 γ = 0.5 ,即取平方根;也可以自行取其他 γ γ 值来得到不同的效果。

下图是使用Gamma校正前后的结果,左图是原图,右图是 γ=0.5 γ = 0.5 进行Gamma校正的结果。直观上可以看出右图的整体亮度更接近了,左图的像素间亮度差距较大。
这里写图片描述

2、梯度计算

前面对颜色空间进行归一化后的图像,再求取其梯度以及梯度方向。分别在水平和垂直方向进行计算。

水平方向梯度算子为: [101] [ − 1 0 1 ] ,垂直方向梯度算子为: [101]T [ − 1 0 1 ] T

假设当前在计算像素点 (x,y) ( x , y ) 的梯度,则其水平梯度值 Gx G x 和垂直梯度值 Gy G y 为:

Gx(x,y)=I(x+1,y)I(x1,y) G x ( x , y ) = I ( x + 1 , y ) − I ( x − 1 , y )

Gy(x,y)=I(x,y+1)I(x,y1) G y ( x , y ) = I ( x , y + 1 ) − I ( x , y − 1 )

根据水平梯度值 Gx G x 和垂直梯度值 Gy G y 求出梯度值:

G(x,y)=Gx(x,y)2+Gy(x,y)2 G ( x , y ) = G x ( x , y ) 2 + G y ( x , y ) 2

角度值 θ(x,y) θ ( x , y ) 也可以求出:

θ(x,y)=arctan(Gx(x,y)Gy(x,y)) θ ( x , y ) = a r c t a n ( G x ( x , y ) G y ( x , y ) )

计算出的梯度图如下所示:
这里写图片描述

3、梯度方向直方图

将图像分为若干个cells(单元),先假设每个cell有 8×8=64 8 × 8 = 64 个像素,相邻的cell之间互不重叠。在每个cell中,计算梯度方向直方图,将所有梯度方向分成9个bins(即9维的特征向量),如下图所示。

这里写图片描述

比如说z2块,对应着两部分,一部分是 20 20 ∘ 40 40 ∘ ,另一部分是 200 200 ∘ 220 220 ∘

如图所示,可以分成9个bin分别对应一定的角度范围,这9个bins即为直方图的横轴,而这些角度范围内所对应的梯度的累加值为直方图的纵轴。

最后我们可以得到每个cell的梯度方向直方图。

4、重叠块直方图归一化

一般来说,一个块(block)由若干个单元(cell)组成,一个单元(cell)由若干个像素点组成。以下是矩形HOG示意图:

这里写图片描述

我们常用的三种HOG结构:R-HOG(矩形HOG)、C-HOG(圆形HOG)、Single centre C-HOG(中心环绕HOG)。单位都是block。论文中提到,R-HOG和C-HOG的效果差不多,而Single centre C-HOG则相对差一点。后面都默认使用R-HOG,另外两种不做赘述,如果感兴趣,请自行查阅论文。

这里写图片描述

前面假设了每个cell有 8×8=64 8 × 8 = 64 个像素,这里还要假设每个block有 2×2=4 2 × 2 = 4 个cell。

下图表示得比较形象,摘自https://blog.csdn.net/hujingshuang/article/details/47337707/

这里写图片描述

颜色标出来的就是block,一个block里面有4个cell,不过其像素值不一定跟实际图片严格对应,只是个示意图。注意到,相邻block之间都有重叠的cell,目的就是利用相邻信息,引入各个block之间的关系。

注意到一个block的大小为 644=256 64 ∗ 4 = 256 个像素,然而图片大小不一定正好是其整数倍,所以还要调整图片的大小,缩放到其整数倍,以分离出整数个block。

到这里先停停,整理一下相关的参数设置。每个block中有 2×2=4 2 × 2 = 4 个cell,每个cell中有 8×8=64 8 × 8 = 64 个像素,计算每个cell的梯度方向直方图得到9维的bins(HOG特征向量),一个block中HOG特征向量的长度则有 4×9=36 4 × 9 = 36

接着还要对每个block块内的HOG特征向量进行归一化。一般有以下几种方法:

这里写图片描述

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

5、后续操作

其实到这里已经得到了整幅图像的HOG特征向量了,使用一系列样本提取得到的HOG特征向量送入SVM分类器训练,寻找最优超平面进行分类。

在实际应用中,往往是从一幅图片中取出若干个小窗口进行特征提取,这样子可以得到有目标的窗口作为正样本,和没有目标的窗口作为负样本。将正负样本送入SVM训练,识别时也是取一个相同大小的滑动窗口,使用训练好的SVM来判断滑动窗口是否包含目标。

程序实现

1、matlab实现提取hog特征

前面部分截图就是下面程序的运行结果,已经注释了。程序不算复杂。

%%
% 参考博客:https://blog.csdn.net/baidu_30028771/article/details/65937451。代码实现,部分原理讲解。
% 其他参考资料:

%%
clear all;
clc;
close all;

%%
img = imread('lena.bmp');

%% 1、灰度化
img = rgb2gray(img);
img = double(img);

step = 8;   % step*step个像素作为一个cell
[m1, n1] = size(img);

%改变图像尺寸为step的最近整数倍
img = imresize(img, [floor(m1/step)*step, floor(n1/step)*step], 'nearest');
[m, n] = size(img);

%% 2、伽马校正
% Gamma校正前图片
% figure();
% imshow(img, []);

img = sqrt(img);

% Gamma校正后图片
% figure();
% imshow(img, []);

%% 3、求梯度和方向
fy = [-1, 0, 1];    %定义竖直模板
fx = fy';           %定义水平模板
Iy = imfilter(img, fy, 'replicate');    %竖直梯度
Ix = imfilter(img, fx, 'replicate');    %水平梯度
Ied = sqrt(Ix.^2 + Iy.^2);              %梯度值
Iphase = Iy ./ Ix;      %边缘斜率,有些为inf,-inf,nan,其中nan需要再处理一下
the = atan(Iphase) * 180 / pi;

% 计算得到的梯度图
% figure();
% imshow(Ied, []);

for i = 1:m
    for j = 1:n
        if(Ix(i,j)>=0&Iy(i,j)>=0)
            the(i,j) = the(i,j);
        elseif(Ix(i,j)<=0&Iy(i,j)>=0)
            the(i,j) = the(i,j) + 180;
        elseif(Ix(i,j)<=0&Iy(i,j)<=0)
            the(i,j) = the(i,j) + 180;
        elseif(Ix(i,j)>=0&Iy(i,j)<=0)
            the(i,j) = the(i,j) + 360;
        end

        if isnan(the(i,j)) == 1
            the(i,j) = 0;
        end
    end
end
the = the + 0.000001;%防止角度为0

%% 4、划分cell、求cell的直方图( 1 cell = 8*8 pixel )
step=8;                %step*step个像素作为一个cell
orient=9;               %方向直方图的方向个数
angle_step = 360 / orient;%每个方向包含的角度数
Cell = cell(1,1);        %所有的角度直方图,cell是可以动态增加的,所以先设了一个
i = 1;
j = 1;
ii = 1;
jj = 1;
for i = 1:step:m
    ii = 1;
    for j = 1:step:n
        Hist1(1:orient) = 0;
        for p = 1:step
            for q = 1:step
                %梯度方向直方图
                Hist1(ceil(the(i+p-1, j+q-1)/angle_step)) = Hist1(ceil(the(i+p-1, j+q-1)/angle_step)) + Ied(i+p-1, j+q-1);
            end
        end
        Cell{ii, jj} = Hist1;
        ii = ii + 1;
    end
    jj = jj + 1;
end

%% 5、划分block,求block的特征值,使用重叠方式( 1 block = 2*2 cell )
[m, n] = size(Cell);
feature = cell(1, (m-1)*(n-1));
for i=1:m-1
    for j=1:n-1
        block = [];
        block = [Cell{i,j}(:)' Cell{i,j+1}(:)' Cell{i+1,j}(:)' Cell{i+1,j+1}(:)'];
        block = block ./ sum(block);%归一化
        feature{(i-1)*(n-1)+j} = block;
    end
end

%% 6、图像的HOG特征值
[m, n] = size(feature);
l = 2 * 2 * orient;
featureVec = zeros(1, n * l);
for i = 1:n
    featureVec((i-1)*l+1:i*l) = feature{i}(:);
end

运行后,我们再来大概计算一下参数,看看与结果的维度是否一致。

测试图片采用的是lena的那张标准图像。

这里写图片描述

首先读入的图片大小是512*512。

这里写图片描述

一个cell的大小是 8×8=64 8 × 8 = 64 ,一个block有 2×2=4 2 × 2 = 4 个cell。

一个block大小为 (2×8)×(2×8)=16×16=256 ( 2 × 8 ) × ( 2 × 8 ) = 16 × 16 = 256 个像素。

由于图像长宽均为512,且可以整除16,故不需要对图像缩放。

使用R-HOG,则共有 (512/81)×(512/81)=63×63=3969 ( 512 / 8 − 1 ) × ( 512 / 8 − 1 ) = 63 × 63 = 3969 个block。

feature变量保存了每个block的HOG特征向量,matlab中可以看到正好一致。

这里写图片描述

对于每个cell,其提取出的HOG特征向量有9个bins,即9维特征向量。则每个block有 4×9=36 4 × 9 = 36 维特征向量。

那么,整幅图像共有 36×3969=142884 36 × 3969 = 142884 维HOG特征向量。

featureVec变量中保存了展开的所有HOG特征向量,可以看到与计算结果一致:

这里写图片描述

2、opencv行人检测

#include <iostream>
#include <opencv2/opencv.hpp>

int main()
{
    cv::Mat img = cv::imread("test![2018-04-03_224420](E:\opencv\My OpenCV projects\HOG特征\HOG_Notes\2018-04-03_224420.jpg).jpg");
    cv::HOGDescriptor hog(cv::Size(64, 128), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9);
    hog.setSVMDetector(cv::HOGDescriptor::getDefaultPeopleDetector());
    std::vector<cv::Rect> regions;
    hog.detectMultiScale(img, regions, 0, cv::Size(8, 8), cv::Size(32, 32), 1.05, 1);
    // 显示
    for (size_t i = 0;i < regions.size();i++)
    {
        cv::rectangle(img, regions[i], cv::Scalar(0, 0, 255), 2);
    }
    cv::imshow("行人检测", img);
    cv::waitKey();

    return 0;
}

opencv中集成了HOG特征算子和训练好的用于行人检测的SVM分类器,偷下懒就不介绍函数api了,请自行查询文档。

运行结果如下:

这里写图片描述

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值