• HOG特征


      HOG(Histogram of gradient)统计图像局部区域的梯度方向信息来作为该局部图像区域的表征。HOG特征具有以下几个特点:

      (1)不具有旋转不变性(较大的方向变化),实际应用中不变性是通过采用不同旋转方向的训练样本;

      (2)不具有尺度不变性,其尺度不变性是通过改变检测图像的大小来实现的;

    关于提取HOG特征,记录一下几点:

    1. 在实现HOG特征提取过程中,必须了解几个概念:cell(单元),block(块),detectWin(检测窗口),它们之间的关系是:检测窗口中可以划分为多个block,每个block中包含多个cell;每个cell能生成一个直方图,将一个block中所有的cell的直方图拼接在一起,则形成block的直方图(特征向量),最后将检测窗口中所有block的直方图拼接在一起,形成我们要回去的HOG特征向量,这个特征向量就可以导入到分类器中进行分类;

    2. 整个过程主要分为两个步骤:(1)计算梯度图和梯度方向; (2)计算每个block的直方图;

    3. 两个难点:(1)对于彩色图像,在计算梯度图需要选择幅值最大的通道;计算梯度方向时,需要根据选择的映射区间[0,pi]或[0,2*pi]; (2)计算每个block直方图时,涉及到三线性插值问题;下面代码中的缺陷:一是没有处理彩色图像;二是没有采用三线性插值的方式计算block的直方图。

    具体的步骤及细节见代码:

      1 function [hog_Feature] = myHOG(detectedImg, options)
      2 % -------------------------------------------------------------------------
      3 % 实现HOG(Histogram of gradient)特征的提取过程
      4 %
      5 % detectedImg-- 检测窗口包含的图像(灰度图)
      6 % options-- 参数结构体,包含许多参数设置:
      7 %            cellH, cellW:单元大小  
      8 %            blockH, blockW:块大小
      9 %            winH, winW:检测窗口大小    
     10 %            stride:块移动步长
     11 %            bins:直方图长度    
     12 %            flag:梯度方向隐射区间(0:[0,pi],1:[0,2*pi])
     13 %            epsilon: 用于做归一化的常量因子
     14 % @hog_Feature-- 检测窗口图像对应的HOG特征向量,大小为1*M,其中
     15 %    M = ((winH-blockH)/stride+1)*((winW-blockW)/stride+1)...
     16 %        *(blockW/cellW)*(blockH/cellH) * bins
     17 %
     18 % HOG特征提取步骤:
     19 % ----------------
     20 % step 1.由于Dalal在论文中提到色彩和伽马归一化步骤对最终的结果没有影响,故省略该步骤;
     21 % 利用[-1,0,1]和[1,0,-1]'分别计算图像的x方向和y方向的梯度(这里不采用Sobel或是其他
     22 % 边缘算子来计算梯度,是因为它们对图像做了平滑处理后再求梯度,这样会丢失很多梯度信息)
     23 % 然后计算每个像素点对应的梯度幅值和方向:
     24 %    ||grad|| = |grad_x| + |grad_y|(或||grad|| = sqrt(grad_x^2+grad_y^2))
     25 %    gradOri = arctan(grad_y/grad_x) (gradOri属于(-pi/2,pi/2))
     26 % 在根据参数flag将每个像素点的梯度方向映射到对应区间中,如果flag为0则选择区间[0,pi]
     27 % 位于(i,j)位置像素点的方向为: 
     28 %       gradOri(i,j)=gradOri(i,j)<0?gradOri(i,j)+pi, gradOri(i,j);
     29 % 如果flag为1选择区间为[0,2*pi],这时需要根据grad_x和grad_y的正负来判断:
     30 %  (1)grad_x>=0&&grad_y>=0(第一象限) gradOri(i,j)=arctan(grad_y/grad_x);
     31 %  (2)grad_x<0&&grad_y>=0(第二象限)  gradOri(i,j)=arctan(grad_y/grad_x)+pi;
     32 %  (3)grad_x<0&&grad_y<0(第三象限)   gradOri(i,j)=arctan(grad_y/grad_x)+pi;
     33 %  (4)grad_x>=0&&grad_y<0(第四象限)  gradOri(i,j)=arctan(grad_y/grad_x)+2*pi;
     34 % ------------------
     35 % step 2.为了便于理解,直接写上四层循环,外面两层循环定位block,里面两层定位cell;
     36 % 一个block对应(blockH*blockW/(cellH*cellW)*bins的特征向量,每个cell对应1*bins
     37 % 的直方图,计算block的直方图在函数calHist中完成,这里计算直方图需要注意两点:
     38 % (1)计算cell直方图时,根据像素点梯度幅值进行权值投影,投影时采用软分配方式,即
     39 % 采用插值的方式进行投影,根据梯度方向距离相邻两个区间的中心点的距离进行插值;
     40 % (2)Dalal在论文中提到,对于R-HOG而言,处理直方图前,在整个block加上一个高斯窗口
     41 % 这样可以降低block边界像素点的权重,直方图投票值由原先的幅值变为幅值和高斯乘积;
     42 % (3)完成block直方图的计算后,需要在整个block范围内进行直方图归一化操作,归一化
     43 % 方式有多种,这里默认采用L2-norm(hist=hist/sqrt(hist^2+epsilon^2)).
     44 % ------------------
     45 % step 3.合并检测窗口中的所有block的向量(HOG特征向量)
     46 %
     47 % 注:整个过程还涉及到一些细节,比如导入图像尺度和设置的检测窗口大小不同时,需要
     48 % 完成尺度缩放;在求图像梯度时,边界问题如何处理,是直接填充0还是复制边界,这里
     49 % 直接填充0;最后一点就是在计算block直方图时,没有进行三维插值,即每个单元中的像
     50 % 素点只对该单元有投票的权力,对当前block的其他单元没有影响。
     51 %
     52 % Author: L.L.He
     53 % Time: 6/8/2014
     54 % -------------------------------------------------------------------------
     55 tic;
     56 assert(nargin>=1);
     57 if ~exist('options', 'var')
     58     % 如果参数没有指定,则设置为如下默认值
     59     options = struct;
     60     options.cellH = 8;   options.cellW = 8;
     61     options.blockH = 16; options.blockW = 16;
     62     options.winH = 64;   options.winW = 128;
     63     options.stride = 8;  options.bins = 9;
     64     options.flag = 1;    options.epsilon = 1e-4;
     65 end
     66 % 处理输入的待检测图像
     67 [r, c, d] = size(detectedImg);
     68 if d ~= 1
     69     % 需要转换为灰度图
     70     detectedImg = rgb2gray(detectedImg);
     71 end
     72 detectedImg = double(detectedImg);
     73 if r~=options.winH && c~=options.winW
     74     % 根据检测窗口的大小对输入图像进行尺度缩放(采用双线性插值)
     75     detectedImg = imresize(detectedImg, [options.winH options.winW],...
     76                            'bilinear');
     77 end
     78 
     79 % step 1--采用1-D差分卷积核计算x方向和y方向的梯度(幅值和方向)
     80 mask = [-1, 0, 1];
     81 [grad, gradOri] = calGrad(detectedImg, mask, options.flag);
     82 
     83 % 根据block的大小计算高斯核
     84 sigma = min(options.blockH, options.blockW)*0.5;
     85 sigma_2 = sigma.^2;
     86 [X, Y] = meshgrid(0:options.blockW-1,0:options.blockH-1);
     87 X = X - (options.blockW-1)/2;
     88 Y = Y - (options.blockH-1)/2;
     89 gaussWeight = exp(-(X.^2+Y.^2)/(2*sigma_2));
     90 
     91 % 创建一个三维矩阵存放所有block的直方图
     92 r_tmp = (options.winH-options.blockH)/options.stride+1;
     93 c_tmp = (options.winW-options.blockW)/options.stride+1;
     94 b_tmp = options.bins *(options.blockH*options.blockW)/...
     95         (options.cellH*options.cellW);
     96 blockHist = zeros(r_tmp, c_tmp, b_tmp);
     97 
     98 % step 2--计算检测窗口中每个block的直方图(HOG特征向量)
     99 for i=1:options.stride:(options.winH-options.blockH+1)
    100     for j=1:options.stride:(options.winW-options.blockW+1)
    101         block_grad = grad(i:i+options.blockH-1,j:j+options.blockW-1);
    102         block_gradOri = gradOri(i:i+options.blockH-1,j:j+options.blockW-1);
    103         % 计算单个block的直方图(投票值为梯度幅值和高斯权重的乘积),并进
    104         % 进行归一化处理
    105         block_r = floor(i/options.stride)+1;
    106         block_c = floor(j/options.stride)+1;
    107         blockHist(block_r,block_c,:) = calHist(block_grad.*gaussWeight, ...
    108                            block_gradOri, options);
    109     end
    110 end
    111 
    112 % step 3--将所有block的直方图拼接成一维向量作为检测窗口的HOG特征向量
    113 hog_Feature = reshape(blockHist, [1 numel(blockHist)]);
    114 toc;
    115 end
    116 
    117 % =========================================================================
    118 function [grad, gradOri] = calGrad(img, mask, flag)
    119 % -------------------------------------------------------------------------
    120 % 利用指定的差分卷积核计算x方向和y方向的梯度(包括幅值和方向)
    121 % img-- 源图像
    122 % mask-- 计算x方向梯度的差分卷积核(y方向的卷积核是转置后取反)
    123 % flag-- 梯度方向隐射区间标识
    124 % @grad-- 梯度幅值
    125 % @gradOri-- 梯度方向
    126 % -------------------------------------------------------------------------
    127 assert(nargin==3);
    128 xMask = mask;
    129 yMask = -mask';
    130 grad = zeros(size(img));
    131 gradOri = zeros(size(img));
    132 grad_x = imfilter(img, xMask);
    133 grad_y = imfilter(img, yMask);
    134 % 计算梯度幅值和方向角
    135 grad = sqrt(double(grad_x.^2 + grad_y.^2));
    136 if flag == 0
    137     % 将梯度方向映射到区间[0,pi]
    138     gradOri = atan(grad_y./(grad_x+eps));
    139     idx = find(gradOri<0);
    140     gradOri(idx) = gradOri(idx) + pi;
    141 else
    142     % 将梯度方向映射到区间[0,2*pi]
    143     % 第一象限
    144     idx_1 = find(grad_x>=0 & grad_y>=0);
    145     gradOri(idx_1) = atan(grad_y(idx_1)./(grad_x(idx_1)+eps));
    146     % 第二(三)象限
    147     idx_2_3 = find(grad_x<0);
    148     gradOri(idx_2_3) = atan(grad_y(idx_2_3)./(grad_x(idx_2_3)+eps)) + pi;
    149     % 第四象限
    150     idx_4 = find(grad_x>=0 & grad_y<0);
    151     gradOri(idx_4) = atan(grad_y(idx_4)./(grad_x(idx_4)+eps)) + 2*pi;
    152 end
    153 end
    154 % =========================================================================
    155 
    156 % =========================================================================
    157 function hist = calHist(block_grad, block_gradOri, options)
    158 % -------------------------------------------------------------------------
    159 % 计算单个block的直方图(它由多个cell直方图拼接而成),并归一化处理
    160 % block_grad-- block区域对应的梯度幅值矩阵
    161 % block_gradOri-- block区域对应的梯度方向矩阵
    162 % options-- 参数结构体,可以得到block中有多少个cell
    163 % -------------------------------------------------------------------------
    164 bins = options.bins;
    165 cellH = options.cellH; cellW = options.cellW;
    166 blockH = options.blockH; blockW = options.blockW;
    167 assert(mod(blockH,cellH)==0&&mod(blockW,cellW)==0);
    168 hist = zeros(blockH/cellH, blockW/cellW, bins);
    169 % 每个bin对应的角度大小(如果bins为9,每个bin为20度)
    170 if options.flag == 0
    171     anglePerBin = pi/bins; 
    172     correctVar = pi; % 用来修正currOri为负的情况
    173 else
    174     anglePerBin = 2*pi/bins;
    175     correctVar = 2*pi;
    176 end
    177 halfAngle = anglePerBin/2; % 后面要用到先计算出来
    178 for i = 1:blockH
    179     for j=1:blockW
    180         % 计算当前位置(i,j)属于的单元
    181         cell_r = floor((i-1)/cellH)+1;
    182         cell_c = floor((j-1)/cellW)+1;
    183         
    184         % 计算当前像素点相连的两个bin并投票
    185         currOri = block_gradOri(i,j) - halfAngle;
    186         % 为了将第一个bin和最后一个bin连接起来,视0度和180度等价
    187         if currOri <= 0
    188             currOri = currOri + correctVar;
    189         end
    190         % 计算该像素点梯度方向所属的两个相连bin的下标
    191         pre_idxOfbin = floor(currOri/anglePerBin) + 1;
    192         pro_idxOfbin = mod(pre_idxOfbin,bins) + 1;
    193         % 向相邻的两个bins进行投票(到中心点的距离作为权重)
    194         center = (2*pre_idxOfbin-1)*halfAngle;
    195         dist_w = (currOri + halfAngle-center)/anglePerBin;
    196         hist(cell_r,cell_c,pre_idxOfbin) = hist(cell_r,cell_c,pre_idxOfbin)...
    197                                            + (1-dist_w)*block_grad(i,j);
    198         hist(cell_r,cell_c,pro_idxOfbin) = hist(cell_r,cell_c,pro_idxOfbin)...
    199                                            + dist_w*block_grad(i,j);
    200     end
    201 end
    202 % 将每个cell的直方图合并(拼接一维向量)
    203 hist = reshape(hist, [1 numel(hist)]);
    204 % 归一化处理(默认选择L2-norm,可以用其他规则替代)
    205 hist = hist./sqrt(hist*hist'+ options.epsilon.^2);
    206 end
    207 % =========================================================================
  • 相关阅读:
    Linux基础_linux发展历史
    Python基础_迭代器、生成器、模块与包
    Python基础_如何用pip安装文件
    Selenium 实现多机器部署分布式执行
    Selenium 日期控件处理和JS定位
    Selenium 无头浏览器
    Selenium 窗口和frame定位
    Selenium 自动化测试模型
    Selenium 验证码处理
    Selenium PageObject设计模式
  • 原文地址:https://www.cnblogs.com/Happyhe/p/3895993.html
Copyright © 2020-2023  润新知