1. 程式人生 > >hog特徵原理詳解及matlab程式碼學習筆記

hog特徵原理詳解及matlab程式碼學習筆記

1HOG特徵:

       方向梯度直方圖(Histogram of Oriented Gradient, HOG)特徵是一種在計算機視覺和影象處理中用來進行物體檢測的特徵描述子。它通過計算和統計影象區域性區域的梯度方向直方圖來構成特徵。Hog特徵結合SVM分類器已經被廣泛應用於影象識別中,尤其在行人檢測中獲得了極大的成功。需要提醒的是,HOG+SVM進行行人檢測的方法是法國研究人員Dalal2005CVPR上提出的,而如今雖然有很多行人檢測演算法不斷提出,但基本都是以HOG+SVM的思路為主。

1)主要思想:

       在一副影象中,區域性目標的表象和形狀(appearance and shape

)能夠被梯度或邊緣的方向密度分佈很好地描述。(本質:梯度的統計資訊,而梯度主要存在於邊緣的地方)。

2)具體的實現方法是:

       首先將影象分成小的連通區域,我們把它叫細胞單元。然後採集細胞單元中各畫素點的梯度的或邊緣的方向直方圖。最後把這些直方圖組合起來就可以構成特徵描述器。

3)提高效能:

       把這些區域性直方圖在影象的更大的範圍內(我們把它叫區間或block)進行對比度歸一化(contrast-normalized),所採用的方法是:先計算各直方圖在這個區間(block)中的密度,然後根據這個密度對區間中的各個細胞單元做歸一化。通過這個歸一化後,能對光照變化和陰影獲得更好的效果。

4)優點:

       與其他的特徵描述方法相比,HOG有很多優點。首先,由於HOG是在影象的區域性方格單元上操作,所以它對影象幾何的和光學的形變都能保持很好的不變性,這兩種形變只會出現在更大的空間領域上。其次,在粗的空域抽樣、精細的方向抽樣以及較強的區域性光學歸一化等條件下,只要行人大體上能夠保持直立的姿勢,可以容許行人有一些細微的肢體動作,這些細微的動作可以被忽略而不影響檢測效果。因此HOG特徵是特別適合於做影象中的人體檢測的。

2HOG特徵提取演算法的實現過程:

大概過程:

HOG特徵提取方法就是將一個image(你要檢測的目標或者掃描視窗):

1)灰度化(將影象看做一個x,y,z

(灰度)的三維影象);

2)採用Gamma校正法對輸入影象進行顏色空間的標準化(歸一化);目的是調節影象的對比度,降低影象區域性的陰影和光照變化所造成的影響,同時可以抑制噪音的干擾;

3)計算影象每個畫素的梯度(包括大小和方向);主要是為了捕獲輪廓資訊,同時進一步弱化光照的干擾。

4)將影象劃分成小cells(例如6*6畫素/cell);

5)統計每個cell的梯度直方圖(不同梯度的個數),即可形成每個celldescriptor

6)將每幾個cell組成一個block(例如3*3cell/block),一個block內所有cell的特徵descriptor串聯起來便得到該blockHOG特徵descriptor

7)將影象image內的所有blockHOG特徵descriptor串聯起來就可以得到該image(你要檢測的目標)的HOG特徵descriptor了。這個就是最終的可供分類使用的特徵向量了。

 

具體每一步的詳細過程如下:

1)標準化gamma空間和顏色空間

為了減少光照因素的影響,首先需要將整個影象進行規範化(歸一化)。在影象的紋理強度中,區域性的表層曝光貢獻的比重較大,所以,這種壓縮處理能夠有效地降低影象區域性的陰影和光照變化。因為顏色資訊作用不大,通常先轉化為灰度圖;

     Gamma壓縮公式:

比如可以取Gamma=1/2

2)計算影象梯度

計算影象橫座標和縱座標方向的梯度,並據此計算每個畫素位置的梯度方向值;求導操作不僅能夠捕獲輪廓,人影和一些紋理資訊,還能進一步弱化光照的影響。

影象中畫素點(x,y)的梯度為:

       最常用的方法是:首先用[-1,0,1]梯度運算元對原影象做卷積運算,得到x方向(水平方向,以向右為正方向)的梯度分量gradscalx,然後用[1,0,-1]T梯度運算元對原影象做卷積運算,得到y方向(豎直方向,以向上為正方向)的梯度分量gradscaly。然後再用以上公式計算該畫素點的梯度大小和方向。

3)為每個細胞單元構建梯度方向直方圖

第三步的目的是為區域性影象區域提供一個編碼,同時能夠保持對影象中人體物件的姿勢和外觀的弱敏感性。

我們將影象分成若干個“單元格cell”,例如每個cell6*6個畫素。假設我們採用9bin的直方圖來統計這6*6個畫素的梯度資訊。也就是將cell的梯度方向360度分成9個方向塊,如圖所示:例如:如果這個畫素的梯度方向是20-40度,直方圖第2bin的計數就加一,這樣,對cell內每個畫素用梯度方向在直方圖中進行加權投影(對映到固定的角度範圍),就可以得到這個cell的梯度方向直方圖了,就是該cell對應的9維特徵向量(因為有9bin)。

        畫素梯度方向用到了,那麼梯度大小呢?梯度大小就是作為投影的權值的。例如說:這個畫素的梯度方向是20-40度,然後它的梯度大小是2(假設啊),那麼直方圖第2bin的計數就不是加一了,而是加二(假設啊)。

         細胞單元可以是矩形的(rectangular),也可以是星形的(radial)。

4)把細胞單元組合成大的塊(block),塊內歸一化梯度直方圖

       由於區域性光照的變化以及前景-背景對比度的變化,使得梯度強度的變化範圍非常大。這就需要對梯度強度做歸一化。歸一化能夠進一步地對光照、陰影和邊緣進行壓縮。

        作者採取的辦法是:把各個細胞單元組合成大的、空間上連通的區間(blocks)。這樣,一個block內所有cell的特徵向量串聯起來便得到該blockHOG特徵。這些區間是互有重疊的,這就意味著:每一個單元格的特徵會以不同的結果多次出現在最後的特徵向量中。我們將歸一化之後的塊描述符(向量)就稱之為HOG描述符。

        區間有兩個主要的幾何形狀——矩形區間(R-HOG)和環形區間(C-HOG)。R-HOG區間大體上是一些方形的格子,它可以有三個引數來表徵:每個區間中細胞單元的數目、每個細胞單元中畫素點的數目、每個細胞的直方圖通道數目。

       例如:行人檢測的最佳引數設定是:3×3細胞/區間、6×6畫素/細胞、9個直方圖通道。則一塊的特徵數為:3*3*9

5)收集HOG特徵

最後一步就是將檢測視窗中所有重疊的塊進行HOG特徵的收集,並將它們結合成最終的特徵向量供分類使用。

6)那麼一個影象的HOG特徵維數是多少呢?

        順便做個總結:Dalal提出的Hog特徵提取的過程:把樣本影象分割為若干個畫素的單元(cell),把梯度方向平均劃分為9個區間(bin),在每個單元裡面對所有畫素的梯度方向在各個方向區間進行直方圖統計,得到一個9維的特徵向量,每相鄰的4個單元構成一個塊(block),把一個塊內的特徵向量聯起來得到36維的特徵向量,用塊對樣本影象進行掃描,掃描步長為一個單元。最後將所有塊的特徵串聯起來,就得到了人體的特徵。例如,對於64*128的影象而言,8*8的畫素組成一個cell,每2*2cell組成一個塊,因為每個cell9個特徵,所以每個塊內有4*9=36個特徵,以8個畫素為步長,那麼,水平方向將有7個掃描視窗,垂直方向將有15個掃描視窗。也就是說,64*128的圖片,總共有36*7*15=3780個特徵。

HOG維數,16×16畫素組成的block,8x8畫素的cell

註釋:

行人檢測HOG+SVM

總體思路:
1、提取正負樣本hog特徵
2、投入svm分類器訓練,得到model
3、由model生成檢測子
4、利用檢測子檢測負樣本,得到hardexample

5、提取hardexample的hog特徵並結合第一步中的特徵一起投入訓練,得到最終檢測子。

1.對原影象gamma校正,img=sqrt(img);

2.求影象豎直邊緣,水平邊緣,邊緣強度,邊緣斜率。

3.將影象每16*16(取其他也可以)個畫素分到一個cell中。對於256*256的lena來說,就分成了16*16個cell了。

4.對於每個cell求其梯度方向直方圖。通常取9(取其他也可以)個方向(特徵),也就是每360/9=40度分到一個方向,方向大小按畫素邊緣強度加權。

5.每2*2(取其他也可以)個cell合成一個block,所以這裡就有(16-1)*(16-1)=225個block。最後歸一化直方圖。

6.所以每個block中都有2*2*9個特徵,一共有225個block,所以總的特徵有225*36個。

當然一般HOG特徵都不是對整幅影象取的,而是對影象中的一個滑動視窗取的。

lena圖:

求得的225*36個特徵:

matlab程式碼如下:

複製程式碼
clear all; close all; clc;

img=double(imread('lena.jpg'));
imshow(img,[]);
[m n]=size(img);

img=sqrt(img);      %伽馬校正

%下面是求邊緣
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需要再處理一下


%下面是求cell
step=16;                %step*step個畫素作為一個單元
orient=9;               %方向直方圖的方向個數
jiao=360/orient;        %每個方向包含的角度數
Cell=cell(1,1);              %所有的角度直方圖,cell是可以動態增加的,所以先設了一個
ii=1;                      
jj=1;
for i=1:step:m          %如果處理的m/step不是整數,最好是i=1:step:m-step
    ii=1;
    for j=1:step:n      %註釋同上
        tmpx=Ix(i:i+step-1,j:j+step-1);
        tmped=Ied(i:i+step-1,j:j+step-1);
        tmped=tmped/sum(sum(tmped));        %區域性邊緣強度歸一化
        tmpphase=Iphase(i:i+step-1,j:j+step-1);
        Hist=zeros(1,orient);               %當前step*step畫素塊統計角度直方圖,就是cell
        for p=1:step
            for q=1:step
                if isnan(tmpphase(p,q))==1  %0/0會得到nan,如果畫素是nan,重設為0
                    tmpphase(p,q)=0;
                end
                ang=atan(tmpphase(p,q));    %atan求的是[-90 90]度之間
                ang=mod(ang*180/pi,360);    %全部變正,-90變270
                if tmpx(p,q)<0              %根據x方向確定真正的角度
                    if ang<90               %如果是第一象限
                        ang=ang+180;        %移到第三象限
                    end
                    if ang>270              %如果是第四象限
                        ang=ang-180;        %移到第二象限
                    end
                end
                ang=ang+0.0000001;          %防止ang為0
                Hist(ceil(ang/jiao))=Hist(ceil(ang/jiao))+tmped(p,q);   %ceil向上取整,使用邊緣強度加權
            end
        end
        %Hist=Hist/sum(Hist);    %方向直方圖歸一化,這一步可以沒有,因為是組成block以後再進行歸一化就可以
        Cell{ii,jj}=Hist;       %放入Cell中
        ii=ii+1;                %針對Cell的y座標迴圈變數
    end
    jj=jj+1;                    %針對Cell的x座標迴圈變數
end

%下面是求feature,2*2個cell合成一個block,沒有顯式的求block
[m n]=size(Cell);
feature=cell(1,(m-1)*(n-1));
for i=1:m-1
   for j=1:n-1           
        f=[];
        f=[f Cell{i,j}(:)' Cell{i,j+1}(:)' Cell{i+1,j}(:)' Cell{i+1,j+1}(:)'];
f=f./sum(f);%歸一化
        feature{(i-1)*(n-1)+j}=f;
   end
end

%到此結束,feature即為所求
%下面是為了顯示而寫的
l=length(feature);
f=[];
for i=1:l
    f=[f;feature{i}(:)'];  
end 
figure
mesh(f)