目标图像特征提取算子(HOG)

1、简介


       HOG(Histograms of Oriented Gradients,方向梯度直方图)最初是在2005年的CVPR会议上由法国研究员Dala提出来的,主要用来进行行人检测。目前HOG+SVM已经被广泛应用到目标检测和分类等领域。博主主要用HOG+SVM方法进行手势分类,原文请参考:“Histograms of Oriented Gradients for Human Detection“。


2、算法实现


       核心思想:

       ①将图像检测窗口分成许多空间区域单元(cells),在每一个cell中计算一维梯度方向或者边缘方向直方图;

       ②若干个cells组成一个block,一个block中的梯度方向直方图是由这若干个cells的梯度方向直方图组成,为了 

           对光照、阴影等鲁棒,需要对block进行对比度归一化处理;

       ③实际上所有的block之间是有重叠的(重叠的区域为一个cell,后面会具体讲道),将检测窗口的所有blocks的

           梯度直方图连接起来就形成了整个检测窗口的梯度方向直方图(HOG)描述子。


       具体过程:

           


     (1)Gamma/Colour Normalization

        Gamma校正方式为 I(x,y) = [ I(x,y) ] ^Gamma。基于人眼处理图像的方式,一般取Gamma=0.5。此过程主要是为了调节图像对比度、减少光照影响、抑制噪声干扰。

       原文提到:在灰度图像、RGB图像和LAB色彩空间进行的Gamma校正对结果只有少许的影响,是因为在后续阶段对block进行了归一化处理。对每一个颜色通道进行的颜色归一化处理结果并不理想,所以一般对灰度图像进行Gamma校正即可。

     (2)Gradient Computation

       为了降低灰度图像的早点,线采用离散高斯平滑模板进行平滑,高斯函数在不同平滑的尺度下进行对灰度图像进行平滑操作,然后采用[-1 ,0 ,1]的差分模板进行梯度计算。求导操作不仅能够捕获轮廓,人影和一些纹理信息,还能进一步弱化光照的影响。水平和垂直方向上梯度计算公式如下:

                                                     

       原文提到:人体检测效果最佳(即不做高斯平滑),使得错误率缩小了约一倍。不做平滑操作,可能原因:图像是基于边缘的,平滑会降低边缘信息的对比度,从而减少图像中的信号信息。对于彩色图像,分别计算每个颜色通道的梯度,然后选择最大范数的梯度作为该像素的梯度向量。

     (3)Spatial / Orientation Binning

       每个像素计算出一个权重投票,局部空间区域(cells)中投票权重累积到各个方向条(bins)上,权重计算公式为:
                                                        

       方向角范围可以为[0° 180°],也可以为[0° 360°],方向角计算公式为:

                                                            

     原文提到:权重计算可以为幅值本身,幅值平方,幅值平方根和二值边缘表述。文中实验结果显示为梯度幅值本身时效果最好(然而在实际使用中与采用上式的权重计算公式并没有卵的差别)。为了减少走样,相邻的bins的投票在方向和位置上采取双线性插值方法。而且方向角为[0° 180°]是效果最好。

      那么将180°分为多少个bins时效果最好呢?

      实验表明:将180°分为9个bins时效果最好,也就是说每个bin包括20°的角度范围。

     原文提到:对于行人检测来说,由于衣服和背景的颜色变化范围较大,可能会导致[0° 360°]的效果差些。或许在目标任务识别(轿车,摩托车)等方面,[0° 360°]范围的效果较好。

      (4)Normalization and Descriptor Blocks

       由于局部光照和前后景的对比,梯度强度变化范围会很大,所以有效的对比度归一化可以提高效果。选取的block之间有重叠,所以每一个标量cell响应都会对最终的描述子向量有所贡献,不同的blocks需要归一化。

       block的选取哪种方式好呢?

       原文提到:选取正方形的cell结果较好,而且当每个cell包含6×6~8×8,每个bolck包含2×2~3×3时效果最好。

       bolck该选择什么方式归一化呢?

       常见的归一化形式有:

                                               

       该算子的关键在于行人轮廓与背景之间的对比,而不是内部边缘或者轮廓与前景的对比,所以行人穿着或者姿势变化时对该算子影响不大。

测试代码如下:

im = imread('1(1).jpg');
if size(im,3) == 3
    im = rgb2gray(im);
end
im = double(im);
rows = size(im,1);
cols = size(im,2);
%h = fspecial('gaussian');
%im = imfilter(im,h);
%figure,imshow(im,[]);
im = im.^0.5;   % gamma calibration
%figure,imshow(im,[]);
Ix = im;
Iy = im;
for i = 1:rows-2   % Calculate the gradient in X and Y direction
    Iy(i,:) = im(i+2,:)-im(i,:);
end
    Iy(rows-1,:) = Iy(rows-2,:);
    Iy(rows,:) = Iy(rows-2,:);
for j = 1:cols-2
    Ix(:,j) = im(:,j+2)-im(:,j);
end
    Ix(:,cols-1) = Ix(:,cols-2);
    Ix(:,cols) = Ix(:,cols-2);
angle = atand(Iy./Ix);% Calculate the angle and magnitude of 
angle = imadd(angle,90);
magtu = sqrt(Ix.^2+Iy.^2);
angle(isnan(angle)) = 0;% Remove NaN
magtu(isnan(magtu)) = 0;
%figure,imshow(angle,[]);
%figure,imshow(magtu,[]);
hog_feature = [];
%Find every block
for i = 1:rows/8-1
    for j = 1:cols/8-1
        angle_block = angle((i-1)*8+1:(i-1)*8+16,(j-1)*8+1:(j-1)*8+16);
        magtu_block = magtu((i-1)*8+1:(i-1)*8+16,(j-1)*8+1:(j-1)*8+16);
        %magtu_block = imfilter(mag_block,gaussian);
        block_feature = [];
        %Find every cell in a block
        for ii = 1:2
            for jj = 1:2
                angle_cell = angle_block((ii-1)*8+1:(ii-1)*8+8,(jj-1)*8+1:(jj-1)*8+8);
                magtu_cell = magtu_block((ii-1)*8+1:(ii-1)*8+8,(jj-1)*8+1:(jj-1)*8+8);
                %Find every pixel's belonged bins
                hist_cell = zeros(1,9);
                for p = 1:8
                    for q = 1:8
                        % Bi_linear Interpolation
                        if angle_cell(p,q)>10 && angle_cell(p,q)<=30
                            hist_cell(1)=hist_cell(1)+magtu_cell(p,q)*(30-angle_cell(p,q))/20;
                            hist_cell(2)=hist_cell(2)+magtu_cell(p,q)*(angle_cell(p,q)-10)/20;
                        elseif angle_cell(p,q)>30 && angle_cell(p,q)<=50
                            hist_cell(2)=hist_cell(2)+magtu_cell(p,q)*(50-angle_cell(p,q))/20;
                            hist_cell(3)=hist_cell(3)+magtu_cell(p,q)*(angle_cell(p,q)-30)/20;
                        elseif angle_cell(p,q)>50 && angle_cell(p,q)<=70
                            hist_cell(3)=hist_cell(3)+magtu_cell(p,q)*(70-angle_cell(p,q))/20;
                            hist_cell(4)=hist_cell(4)+magtu_cell(p,q)*(angle_cell(p,q)-50)/20;
                        elseif angle_cell(p,q)>70 && angle_cell(p,q)<=90
                            hist_cell(4)=hist_cell(4)+magtu_cell(p,q)*(90-angle_cell(p,q))/20;
                            hist_cell(5)=hist_cell(5)+magtu_cell(p,q)*(angle_cell(p,q)-70)/20;
                        elseif angle_cell(p,q)>90 && angle_cell(p,q)<=110
                            hist_cell(5)=hist_cell(5)+magtu_cell(p,q)*(110-angle_cell(p,q))/20;
                            hist_cell(6)=hist_cell(6)+magtu_cell(p,q)*(angle_cell(p,q)-90)/20;
                        elseif angle_cell(p,q)>110 && angle_cell(p,q)<=130
                            hist_cell(6)=hist_cell(6)+magtu_cell(p,q)*(130-angle_cell(p,q))/20;
                            hist_cell(7)=hist_cell(7)+magtu_cell(p,q)*(angle_cell(p,q)-110)/20;
                        elseif angle_cell(p,q)>130 && angle_cell(p,q)<=150
                            hist_cell(7)=hist_cell(7)+magtu_cell(p,q)*(150-angle_cell(p,q))/20;
                            hist_cell(8)=hist_cell(8)+magtu_cell(p,q)*(angle_cell(p,q)-130)/20;
                        elseif angle_cell(p,q)>150 && angle_cell(p,q)<=170
                            hist_cell(8)=hist_cell(8)+magtu_cell(p,q)*(170-angle_cell(p,q))/20;
                            hist_cell(9)=hist_cell(9)+magtu_cell(p,q)*(angle_cell(p,q)-150)/20;
                        elseif angle_cell(p,q)>170 && angle_cell(p,q)<=180
                            hist_cell(9)=hist_cell(9)+magtu_cell(p,q)*(190-angle_cell(p,q))/20;
                            hist_cell(1)=hist_cell(1)+magtu_cell(p,q)*(angle_cell(p,q)-170)/20;
                        elseif angle_cell(p,q)>0 && angle_cell(p,q)<=10
                            hist_cell(1)=hist_cell(1)+magtu_cell(p,q)*(angle_cell(p,q)+10)/20;
                            hist_cell(9)=hist_cell(9)+magtu_cell(p,q)*(10-angle_cell(p,q))/20;
                        end
                    end
                end
                block_feature = [block_feature hist_cell];
            end
        end
                % Normalize block_feature using L2-norm
                block_feature = block_feature/sqrt(norm(block_feature)^2+0.00001);
                hog_feature = [hog_feature block_feature];
    end 
end
hog_feature(isnan(hog_feature)) = 0;
%Normalize the hog_feature using L2-Hys
hog_feature = hog_feature/sqrt(norm(hog_feature)^2+0.00001);
for z = 1:length(hog_feature)
    if hog_feature(z)>0.2
        hog_feature(z)=0.2
    end
end
hog_feature = hog_feature/sqrt(norm(hog_feature)^2+0.00001);


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章