目標圖像特徵提取算子(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);


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