HOG:从理论到OpenCV实践
HOG:從理論到OpenCV實(shí)踐
CSDN博客 原文? http://blog.csdn.net/zhazhiqiang/article/details/21047207 主題 OpenCV(轉(zhuǎn)載請注明出處: http://blog.csdn.net/zhazhiqiang/ ?未經(jīng)允許請勿用于商業(yè)用途)
一、理論1、HOG特征描述子的定義:
? ? locally normalised histogram of gradient orientation in dense overlapping grids,即局部歸一化的梯度方向直方圖,是一種對圖像局部重疊區(qū)域的密集型描述符,?它通過計算局部區(qū)域的梯度方向直方圖來構(gòu)成特征。
2、本質(zhì):? ? Histogram of Oriented Gradient descriptors provide a dense overlapping description of image regions,即統(tǒng)計圖像局部區(qū)域的梯度方向信息來作為該局部圖像區(qū)域的表征。
3、OpenCV中的HOG算法來源:
? ? ? Histograms of Oriented Gradients for Human Detection , CVPR 2005。詳細(xì)的算法可以參考這個文章。這里是 英文 和 中文 的介紹。
4、 檢測窗口Win、塊Block、單元格Cell的基本信息
(1)大小:A、檢測窗口:WinSize=128*64像素,在圖像中滑動的步長是8像素(水平和垂直都是)
B、塊:BlockSize=16*16像素,在檢測窗口中滑動的步長是8像素(水平和垂直都是)
C、單元格:CellSize=8*8像素
D、梯度方向:一個Cell的梯度方向分為9個方向,在一個單元格內(nèi)統(tǒng)計9個方向的梯度直方圖
(2)HOG描述子? ? OpenCV中一個Hog描述子是針對一個檢測窗口而言的,一個檢測窗口有((128-16)/8+1)*((64-16)/8+1)=105個Block,一個Block有4個Cell,一個Cell的Hog描述子向量的長度是9,所以一個檢測窗口的Hog描述子的向量長度是105*4*9=3780維。
? ??HOG特征提取是統(tǒng)計梯度直方圖特征。具體來說就是將梯度方向(0->360°)劃分為9個區(qū)間,將圖像化為16x16的若干個block,每個block再化為4個cell(8x8)。對每一個cell,算出每一像素點(diǎn)的梯度方向和模,按梯度方向增加對應(yīng)bin的值,最終綜合N個cell的梯度直方圖形成一個 高維描述子向量 。實(shí)際實(shí)現(xiàn)的時候會有 各種插值 。
5、算法流程:(1)灰度化
? ? 由于顏色信息作用不大,通常轉(zhuǎn)化為灰度圖。
(2)標(biāo)準(zhǔn)化gamma空間
? ? 為了減少光照因素的影響,首先需要將整個圖像進(jìn)行規(guī)范化(歸一化),這種處理能夠有效地降低圖像局部的陰影和光照變化。
? ? ? ? ? ? Gamma壓縮公式:
? ? ? ? ? ? ?比如可以取Gamma=1/2;
(3)計算圖像每個像素的梯度(包括大小和方向)
? ? 計算圖像橫坐標(biāo)和縱坐標(biāo)方向的梯度,并據(jù)此計算每個像素位置的梯度方向值;求導(dǎo)操作不僅能夠捕獲輪廓,人影和一些紋理信息,還能進(jìn)一步弱化光照的影響。 梯度算子:水平邊緣算子: [-1, 0, 1] ;垂直邊緣算子: [-1, 0, 1]T???? ? 圖像中像素點(diǎn)(x,y)的梯度為:
? ? 作者也嘗試了其他一些更復(fù)雜的模板,如3×3 Sobel 模板,或?qū)蔷€模板(diagonal masks),但是在這個行人檢測的實(shí)驗(yàn)中,這些復(fù)雜模板的表現(xiàn)都較差,所以作者的結(jié)論是:模板越簡單,效果反而越好。
作者也嘗試了在使用微分模板前加入 一個高斯平滑濾波,但是這個高斯平滑濾波的加入使得檢測效果更差,原因是:許多有用的圖像信息是來自變化劇烈的邊緣,而在計算梯度之前加入高斯濾波會把這些邊緣濾除掉。 (4)將圖像分割為小的Cell單元格 由于Cell單元格是HOG特征最小的結(jié)構(gòu)單位,而且其塊Block和檢測窗口Win的滑動步長就是一個Cell的寬度或高度,所以,先把整個圖像分割為一個個的Cell單元格(8*8像素)。 (5)為每個單元格構(gòu)建梯度方向直方圖【重點(diǎn)】? ? 這步的目的是:統(tǒng)計局部圖像梯度信息并進(jìn)行量化(或稱為編碼),得到局部圖像區(qū)域的特征描述向量。同時能夠保持對圖像中人體對象的姿勢和外觀的弱敏感性。
? ? 我們將圖像分成若干個“單元格cell”,例如每個cell為8*8個像素(可以是矩形的(rectangular),也可以是星形的(radial))。假設(shè)我們采用9個bin的直方圖來統(tǒng)計這8*8個像素的梯度信息。也就是將cell的梯度方向360度分成9個方向塊,如圖所示: 例如:如果這個像素的梯度方向是20-40度,直方圖第2個bin的計數(shù)就加一,這樣,對cell內(nèi)每個像素用梯度方向在直方圖中進(jìn)行 加權(quán)投影 (映射到固定的角度范圍),就可以得到這個cell的梯度方向直方圖了,就是該cell對應(yīng)的9維特征向量(因?yàn)橛?個bin)。
? ? 像素梯度方向用到了,那么梯度大小呢?梯度大小就是作為投影的權(quán)值的。 例如說:這個像素的梯度方向是20-40度,然后它的梯度大小是2(假設(shè)啊),那么直方圖第2個bin的計數(shù)就不是加一了,而是加二(假設(shè)啊)。
? ? 單元格Cell中的每一個像素點(diǎn)都為某個基于方向的直方圖通道(orientation-based histogram channel) 投票 。投票是采取加權(quán)投票(weighted voting)的方式,即每一票都是帶權(quán)值的,這個權(quán)值是根據(jù)該像素點(diǎn)的梯度幅度計算出來。可以采用幅值本身或者它的函數(shù)來表示這個權(quán)值,實(shí)際測試表明: 使用幅值來表示權(quán)值能獲得最佳的效果,當(dāng)然,也可以選擇幅值的函數(shù)來表示,比如幅值的平方根(square root)、幅值的平方(square of the gradient magnitude)、幅值的截斷形式(clipped version of the magnitude)等。根據(jù)Dalal等人論文的測試結(jié)果,采用梯度幅值量級本身得到的檢測效果最佳,使用量級的平方根會輕微降低檢測結(jié)果,而使用二值的邊緣權(quán)值表示會嚴(yán)重降低效果。? ? 其中,加權(quán)采用三線性插值(鏈接為詳細(xì)說明的博文)方法,即將當(dāng)前像素的梯度方向大小、像素在cell中的x坐標(biāo)與y坐標(biāo)這三個值來作為插值權(quán)重,而被用來插入的值為像素的梯度幅值。采用三線性插值的好處在于:避免了梯度方向直方圖在cell邊界和梯度方向量化的bin邊界處的突然變化。
(6)把單元格組合成大的塊(block),塊內(nèi) 歸一化 梯度直方圖【重點(diǎn)】
? ? 由于局部光照的變化以及前景-背景對比度的變化,使得梯度強(qiáng)度的變化范圍非常大。這就需要對梯度強(qiáng)度做歸一化。歸一化能夠進(jìn)一步地對光照、陰影和邊緣進(jìn)行壓縮。
? ? 方法:
(6-1)將多個臨近的cell組合成一個block塊,然后求其梯度方向直方圖向量;
(6-2)采用L2-Norm with Hysteresis threshold方式進(jìn)行歸一化,即將直方圖向量中bin值的最大值限制為0.2以下,然后再重新歸一化一次;
? ? 注意:block之間的是“共享”的,也即是說,一個cell會被多個block“共享”。另外,每個“cell”在被歸一化時都是“block”independent的,也就是說每個cell在其所屬的block中都會被歸一化一次,得到一個vector。這就意味著:每一個單元格的特征會以不同的結(jié)果多次出現(xiàn)在最后的特征向量中。
(6-3)四種歸一化方法: ? ?
? ? 作者采用了四中不同的方法對區(qū)間進(jìn)行歸一化,并對結(jié)果進(jìn)行了比較。引入v表示一個還沒有被歸一 化的向量,它包含了給定區(qū)間(block)的所有直方圖信息。| | vk | |表示v的k階范數(shù),這里的k去1、2。用e表示一個很小的常數(shù)。這時,歸一化因子可以表示如下:
? ? ? ? L2-norm:
? ? ? ? L1-norm:
? ? ? ? L1-sqrt:
? ? ? ? L2-Hys:它可以通過先進(jìn)行L2-norm,對結(jié)果進(jìn)行截短(clipping)(即值被限制為v - 0.2v之間),然后再重新歸一化得到。
? ? 作者發(fā)現(xiàn):采用L2- Hys,L2-norm 和 L1-sqrt方式所取得的效果是一樣的,L1-norm稍微表現(xiàn)出一點(diǎn)點(diǎn)不可靠性。但是對于沒有被歸一化的數(shù)據(jù)來說,這四種方法都表現(xiàn)出來顯著的改進(jìn)。
? ??
(6-4)區(qū)間(塊)有兩個主要的幾何形狀——矩形區(qū)間(R-HOG)和環(huán)形區(qū)間(C-HOG)。
? ? A、R-HOG區(qū)間(blocks):大體上是一些方形的格子,它可以有三個參數(shù)來表征:每個區(qū)間中細(xì)胞單元的數(shù)目、每個細(xì)胞單元中像素點(diǎn)的數(shù)目、每個細(xì)胞的直方圖通道數(shù)目。例如:行人檢測的最佳參數(shù)設(shè)置是:3×3細(xì)胞/區(qū)間、6×6像素/細(xì)胞、9個直方圖通道。則一塊的特征數(shù)為:3*3*9;作者還發(fā)現(xiàn),對于R-HOG,在對直方圖做處理之前,給每個區(qū)間(block)加一個高斯空域窗口(Gaussian spatial window)是非常必要的,因?yàn)檫@樣可以降低邊緣的周圍像素點(diǎn)(pixels around the edge)的權(quán)重。R-HOG是各區(qū)間被組合起來用于對空域信息進(jìn)行編碼(are used in conjunction to encode spatial form information)。
? ? B、C-HOG區(qū)間(blocks):有兩種不同的形式,它們的區(qū)別在于:一個的中心細(xì)胞是完整的,一個的中心細(xì)胞是被分割的。如右圖所示:
作者發(fā)現(xiàn)C-HOG的這兩種形式都能取得相同的效果。C-HOG區(qū)間(blocks)可以用四個參數(shù)來表征:角度盒子的個數(shù)(number of angular bins)、半徑盒子個數(shù)(number of radial bins)、中心盒子的半徑(radius of the center bin)、半徑的伸展因子(expansion factor for the radius)。通過實(shí)驗(yàn),對于行人檢測,最佳的參數(shù)設(shè)置為:4個角度盒子、2個半徑盒子、中心盒子半徑為4個像素、伸展因子為2。前面提到過,對于R-HOG,中間加一個高斯空域窗口是非常有必要的,但對于C-HOG,這顯得沒有必要。C-HOG看起來很像基于形狀上下文(Shape Contexts)的方法,但不同之處是:C-HOG的區(qū)間中包含的細(xì)胞單元有多個方向通道(orientation channels),而基于形狀上下文的方法僅僅只用到了一個單一的邊緣存在數(shù)(edge presence count)。
(6-5)HOG描述符(不同于OpenCV定義):我們將歸一化之后的塊描述符(向量)就稱之為HOG描述符。
(6-6)塊劃分帶來的問題: 塊與塊之間是相互獨(dú)立的嗎?
答:通常的將某個變量范圍固定劃分為幾個區(qū)域,由于邊界變量與相鄰區(qū)域也有相關(guān)性,所以變量只對一個區(qū)域進(jìn)行投影而對相鄰區(qū)域完全無關(guān)時會對其他區(qū)域產(chǎn)生 混疊效應(yīng) 。
? ?? 分塊之間的相關(guān)性問題的解決:
方案一:塊重疊,重復(fù)統(tǒng)計計算
? ? 在重疊方式中,塊與塊之間的邊緣點(diǎn)被重復(fù)根據(jù)權(quán)重投影到各自相鄰塊(block)中,從而一定模糊了塊與塊之間的邊界,處于塊邊緣部分的像素點(diǎn)也能夠給相鄰塊中的方向梯度直方圖提供一定貢獻(xiàn),從而達(dá)到關(guān)聯(lián)塊與塊之間的關(guān)系的作用。Datal對于塊和塊之間相互重疊程度對人體目標(biāo)檢測識別率影響也做了實(shí)驗(yàn)分析。
方案二:線性插值權(quán)重分配
? ? 有些文獻(xiàn)采用的不是塊與塊重疊的方法,而是采用線性插值的方法來削弱混疊效應(yīng)。這種方法的主要思想是每個Block都對臨近的Block都有影響,這種影響,我們可以以一種加權(quán)方式附加上去。
? ? 基于線性插值的基本思想,對于上圖四個方向(橫縱兩個45度斜角方向)個進(jìn)行一次線性插值就可以達(dá)到權(quán)重分配目的。下面介紹一維線性插值。假設(shè)x1和x2是x塊相鄰兩塊的中心,且x1<x<x2。對w(即權(quán)重,一般可直接采用該block的直方圖值即h(x))進(jìn)行線性插值的方法如下式:?
? ? 其中b在橫縱方向取塊間隔,而在斜45度方向則可采用sqrt(2)倍的塊間隔。
(7)生成HOG特征描述向量
? ? 將所有“block”的HOG描述符組合在一起,形成最終的feature vector,該feature vector就描述了detect window的圖像內(nèi)容。二、OpenCV中 HOG 的參數(shù)與函數(shù)說明(HOG鏈接為OpenCV英文, 這里 為網(wǎng)友翻譯)
? ? ? ? 注:HOG在OpenCV中的幾個模塊中都有,略有差別,可做參考,OpenCV的官方文檔中只有對GPU模塊的HOG,這里前面幾個函數(shù)說明是GPU中的,后面兩個objedetect模塊中。其實(shí)我們在使用時用的是objedetect模塊中的HOG。
1、構(gòu)造函數(shù)(1)作用:創(chuàng)造一個HOG描述子和檢測器
(2)函數(shù)原型: C++:?gpu::HOGDescriptor:: HOGDescriptor (Size? win_size =Size(64, 128),? Size? block_size =Size(16, 16),?Size? block_stride =Size(8, 8),
Size? cell_size =Size(8, 8),?
int? nbins =9,?double? win_sigma =DEFAULT_WIN_SIGMA,?
double? threshold_L2hys =0.2,?
bool? gamma_correction =true,?
int? nlevels =DEFAULT_NLEVELS
) (3)參數(shù)注釋<1> win_size :檢測窗口大小。
<2> block_size :塊大小,目前只支持Size(16, 16)。
<3> block_stride :塊的滑動步長,大小只支持是單元格cell_size大小的倍數(shù)。
<4> cell_size :單元格的大小,目前只支持Size(8, 8)。
<5> nbins :直方圖bin的數(shù)量(投票箱的個數(shù)),目前每個單元格Cell只支持9個。
<6> win_sigma :高斯濾波窗口的參數(shù)。
<7> threshold_L2hys :塊內(nèi)直方圖歸一化類型L2-Hys的歸一化收縮率
<8> gamma_correction :是否gamma校正
<9> nlevels :檢測窗口的最大數(shù)量
2、getDescriptorSize函數(shù)
(1)作用:獲取一個檢測窗口的HOG特征向量的維數(shù)
(2)函數(shù)原型: C++:? size_t? gpu::HOGDescriptor:: getDescriptorSize ()?const3、getBlockHistogramSize函數(shù)
(1)作用:獲取塊的直方圖大小
(2)函數(shù)原型: C++:? size_t? gpu::HOGDescriptor:: getBlockHistogramSize ()?const??4、setSVMDetector?函數(shù)
(1)作用:設(shè)置線性SVM分類器的系數(shù)
(2)函數(shù)原型: C++:? void? gpu::HOGDescriptor:: setSVMDetector (const vector<float>&? detector )?5、getDefaultPeopleDetector?函數(shù)
(1)作用:獲取行人分類器(默認(rèn)檢測窗口大小)的系數(shù)(獲得3780維檢測算子)
(2)函數(shù)原型: C++:? static?vector<float> ?gpu::HOGDescriptor:: getDefaultPeopleDetector ()?6、getPeopleDetector48x96?函數(shù)
(1)作用:獲取行人分類器(48*96檢測窗口大小)的系數(shù)
(2)函數(shù)原型: C++: ?static?vector<float> ?gpu::HOGDescriptor:: getPeopleDetector48x96 ()7、getPeopleDetector64x128?函數(shù)
(1)作用:獲取行人分類器(64*128檢測窗口大小)的系數(shù)
(2)函數(shù)原型: C++:? static?vector<float> ?gpu::HOGDescriptor:: getPeopleDetector64x128 ()? 8、detect?函數(shù)(1)作用:用沒有多尺度的窗口進(jìn)行物體檢測
(2)函數(shù)原型: C++:? void? gpu::HOGDescriptor:: detect (const GpuMat&? img ,? vector<Point>&? found_locations ,?double? hit_threshold =0,?
Size? win_stride =Size(),?
Size? padding =Size()
)?? (3)參數(shù)注釋<1> img: 源圖像。只支持CV_8UC1和CV_8UC4數(shù)據(jù)類型。
<2> found_locations: 檢測出的物體的邊緣。
<3> hit_threshold: 特征向量和SVM劃分超平面的閥值距離。通常它為0,并應(yīng)由檢測器系數(shù)決定。但是,當(dāng)系數(shù)被省略時,可以手動指定它。
<4> win_stride: 窗口步長,必須是塊步長的整數(shù)倍。
<5> padding: 模擬參數(shù),使得CUP能兼容。目前必須是(0,0)。
9、detectMultiScale?函數(shù)(需有setSVMDetector)
(1)作用:用多尺度的窗口進(jìn)行物體檢測
(2)函數(shù)原型: C++:? void? gpu::HOGDescriptor:: detectMultiScale (const GpuMat&? img , vector<Rect>&? found_locations ,?double? hit_threshold =0,?
Size? win_stride =Size(),?
Size? padding =Size(),?
double? scale0 =1.05,?
int? group_threshold =2
) (3)參數(shù)注釋<1> img: 源圖像。只支持CV_8UC1和CV_8UC4數(shù)據(jù)類型。
<2> found_locations: 檢測出的物體的邊緣。
<3> hit_threshold: 特征向量和SVM劃分超平面的閥值距離。通常它為0,并應(yīng)由檢測器系數(shù)決定。但是,當(dāng)系數(shù)被省略時,可以手動指定它。
<4> win_stride: 窗口步長,必須是塊步長的整數(shù)倍。
<5> padding: 模擬參數(shù),使得CUP能兼容。目前必須是(0,0)。
<6> scale0: 檢測窗口增長參數(shù)。
<7> group_threshold: 調(diào)節(jié)相似性系數(shù)的閾值。檢測到時,某些對象可以由許多矩形覆蓋。 0表示不進(jìn)行分組。
(4)詳細(xì)說明<1> 得到層數(shù)levels?
? ? 某圖片(530,402)為例,lg(402/128)/lg1.05=23.4?則得到層數(shù)為24
<2>循環(huán)levels次,每次執(zhí)行內(nèi)容如下
? ? HOGThreadData&?tdata?=?threadData[getThreadNum()];
? ? Mat?smallerImg(sz,?img.type(),?tdata.smallerImgBuf.data);
<3>循環(huán)中調(diào)用以下核心函數(shù)
? ? detect(smallerImg,?tdata.locations,?hitThreshold,?winStride,?padding);
? ? 其參數(shù)分別為,該比例下圖像、返回結(jié)果列表、門檻值、步長、margin
? ? 該函數(shù)內(nèi)容如下:
(a)得到補(bǔ)齊圖像尺寸paddedImgSize
(b)創(chuàng)建類的對象HOGCache cache(this, img, padding, padding, nwindows == 0, cacheStride); 在創(chuàng)建過程中,首先初始化HOGCache::init,包括:計算梯度descriptor->computeGradient、得到塊的個數(shù)105、每塊參數(shù)個數(shù)36。
(c)獲得窗口個數(shù)nwindows,以第一層為例,其窗口數(shù)為(530+32*2-64)/8+ (402+32*2-128)/8+1 =67*43=2881,其中(32,32)為winStride參數(shù), 也可用(24,16)
(d)在每個窗口執(zhí)行循環(huán),內(nèi)容如下:
在105個塊中執(zhí)行循環(huán),每個塊內(nèi)容為:通過getblock函數(shù)計算HOG特征并 歸一化,36個數(shù)分別與算子中對應(yīng)數(shù)進(jìn)行相應(yīng)運(yùn)算;判斷105個塊的總和 s >= hitThreshold 則認(rèn)為檢測到目標(biāo)
10、getDescriptors?函數(shù)
(1)作用:返回整個圖片的塊描述符?(主要用于分類學(xué)習(xí))。
(2)函數(shù)原型: C++:? void? gpu::HOGDescriptor:: getDescriptors (const GpuMat&?img,? Size? win_stride ,?GpuMat&? descriptors ,?
int? descr_format =DESCR_FORMAT_COL_BY_COL
) (3)參數(shù)注釋?<1> img: 源圖像。只支持CV_8UC1和CV_8UC4數(shù)據(jù)類型。
<2> win_stride: 窗口步長,必須是塊步長的整數(shù)倍。
<3> descriptors :描述符的2D數(shù)組。
<4> descr_format: 描述符存儲格式:
DESCR_FORMAT_ROW_BY_ROW?- 行存儲。DESCR_FORMAT_COL_BY_COL?- 列存儲。
11、computeGradient 函數(shù)(1)作用:計算img經(jīng)擴(kuò)張后的圖像中每個像素的梯度和角度??
(2)函數(shù)原型:?void? HOGDescriptor:: computeGradient (const Mat&? img ,?
Mat&? grad ,? Mat&? qangle ,Size? paddingTL ,?
Size? paddingBR ) const (3)參數(shù)注釋?<1> img: 源圖像。只支持CV_8UC1和CV_8UC4數(shù)據(jù)類型。
<2> grad: 輸出梯度(兩通道),記錄每個像素所屬bin對應(yīng)的權(quán)重的矩陣,為幅值乘以權(quán)值。這個權(quán)值是關(guān)鍵,也很復(fù)雜:包括高斯權(quán)重,三次插值的權(quán)重,在本函數(shù)中先值考慮幅值和相鄰bin間的插值權(quán)重。
<3> qangle :輸入弧度(兩通道),記錄每個像素角度所屬的bin序號的矩陣,均為2通道,為了線性插值。
<4> paddingTL: Top和Left擴(kuò)充像素數(shù)。
<5> paddingBR: Bottom和Right擴(kuò)充像素數(shù)。
12、compute 函數(shù)
(1)作用:計算HOG特征向量?
(2)函數(shù)原型:? void? HOGDescriptor:: compute (const Mat&? img ,? vector<float>&? descriptors ,Size? winStride ,?
Size? padding ,const vector<Point>&? locations
) const (3)參數(shù)注釋?<1> img: 源圖像。只支持CV_8UC1和CV_8UC4數(shù)據(jù)類型。
<2> descriptors: 返回的HOG特征向量,descriptors.size是HOG特征的維數(shù)。
<3> winStride :窗口移動步長。
<4> padding: 擴(kuò)充像素數(shù)。
<5> locations: 對于正樣本可以直接取(0,0),負(fù)樣本為隨機(jī)產(chǎn)生合理坐標(biāo)范圍內(nèi)的點(diǎn)坐標(biāo)。
三、 HOG算法OpenCV實(shí)現(xiàn)流程
四、OpenCV的簡單例子
1、HOG行人檢測 (1)代碼:#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/gpu/gpu.hpp> #include <stdio.h>using namespace cv;int main(int argc, char** argv) { Mat img; vector<Rect> found; img = imread(argv[1]); if(argc != 2 || !img.data) { printf("沒有圖片\n"); return -1; } HOGDescriptor defaultHog; defaultHog.setSVMDetector(HOGDescriptor::getDefaultPeopleDetector()); //進(jìn)行檢測 defaultHog.detectMultiScale(img, found); //畫長方形,框出行人 for(int i = 0; i < found.size(); i++) { Rect r = found[i]; rectangle(img, r.tl(), r.br(), Scalar(0, 0, 255), 3); } namedWindow("檢測行人", CV_WINDOW_AUTOSIZE); imshow("檢測行人", img); waitKey(0); return 0; } (2)注解
? ? 上述過程并沒有像人臉檢測Demo里有Load訓(xùn)練好的模型的步驟,這個 getDefaultPeopleDetector 是默認(rèn)模型,這個模型數(shù)據(jù)在OpenCV源碼中是一堆常量數(shù)字,這些數(shù)字是通過原作者提供的行人樣本 INRIAPerson.tar 訓(xùn)練得到的。
? ? 這里只是用到了HOG的 識別模塊 ,OpenCV把HOG包的內(nèi)容比較多,既有HOG的特征提取,也有結(jié)合SVM的識別,這里的識別只有檢測部分,OpenCV提供默認(rèn)模型,如果使用新的模型,需要重新訓(xùn)練。
2、HOG的計算以及SVM從訓(xùn)練到識別 (可參考 OpenCV中的HOG+SVM物體分類 和 利用HOG+SVM訓(xùn)練自己的XML文件 和
opencv中的 HOGDescriptor 類 )
(1)制作樣本,將其歸一化到一個的尺度。
(2)將樣本圖像的名稱寫到一個TXT文件,方便程序調(diào)用。(3)依次提取每張圖像的HOG特征向量。
對每一張圖片調(diào)用
hog.compute (img, descriptors,Size(8,8), Size(0,0));
可以生成hog descriptors,把它保存到文件中
for(int j=0;j<3780;j++)
fprintf(f,"%f,",descriptors[j]);
(4)利用SVM進(jìn)行訓(xùn)練。
(5)得到XML文件。? ? 這里識別有兩種用法:
A、一種采用 svm.predict 來做(參考 利用HOG+SVM訓(xùn)練自己的XML文件 )
B、另一種采用 hog.setSVMDetector+訓(xùn)練的模型和hog.detectMultiScale (參考 利用Hog特征和SVM分類器進(jìn)行行人檢測? ?) 五、總結(jié)1、HOG與SIFT的區(qū)別
? ? HOG和SIFT都是描述子,以及由于在具體操作上有很多相似的步驟,所以致使很多人誤認(rèn)為HOG是SIFT的一種,其實(shí)兩者在使用目的和具體處理細(xì)節(jié)上是有很大的區(qū)別的。HOG與SIFT的主要區(qū)別如下:
(1)SIFT是基于關(guān)鍵點(diǎn)特征向量的描述。
(2)HOG是將圖像均勻的分成相鄰的小塊,然后在所有的小塊內(nèi)統(tǒng)計梯度直方圖。
(3)SIFT需要對圖像尺度空間下對像素求極值點(diǎn),而HOG中不需要。
(4)SIFT一般有兩大步驟,第一個步驟對圖像提取特征點(diǎn),而HOG不會對圖像提取特征點(diǎn)。
2、HOG的優(yōu)缺點(diǎn) 優(yōu)點(diǎn):(1)HOG表示的是邊緣(梯度)的結(jié)構(gòu)特征,因此可以描述局部的形狀信息;
(2)位置和方向空間的量化一定程度上可以抑制平移和旋轉(zhuǎn)帶來的影響;
(3)采取在局部區(qū)域歸一化直方圖,可以部分抵消光照變化帶來的影響;
(4)由于一定程度忽略了光照顏色對圖像造成的影響,使得圖像所需要的表征數(shù)據(jù)的維度降低了;
(5)而且由于這種分塊分單元的處理方法,也使得圖像局部像素點(diǎn)之間的關(guān)系可以很好得到表征。
缺點(diǎn):(1)描述子生成過程冗長,導(dǎo)致速度慢,實(shí)時性差;
(2)很難處理遮擋問題;
(3)由于梯度的性質(zhì),該描述子對噪點(diǎn)相當(dāng)敏感
總結(jié)
以上是生活随笔為你收集整理的HOG:从理论到OpenCV实践的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Histogram of Oriente
- 下一篇: HOG特征分析