欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Python與C++中梯度方向直方圖的實(shí)現(xiàn)

 更新時(shí)間:2022年03月17日 10:37:56   作者:Meringue_zz  
在學(xué)習(xí)HOG特征的時(shí)候,發(fā)現(xiàn)一片英文文章講得淺顯易懂。因此翻譯在這里學(xué)習(xí),感興趣的朋友快來看看吧

原文鏈接:Histogram of Oriented Gradients

(文中的圖片均來自翻譯原文)

什么是特征描述子

特征描述子一張圖片或者一個(gè)圖片塊的一種表示,通過提取有用信息并扔掉多余的信息來簡(jiǎn)化圖像。

通常,特征描述子將一張大小為width×height×3 (通道數(shù))的圖片化成一個(gè)長(zhǎng)度為n的特征向量/數(shù)組。以HOG特征為例,輸入圖像的大小是64×128×3,輸出是一個(gè)長(zhǎng)度為3780的特征向量。

注意一點(diǎn),HOG特征也可以是其它大小,但這里我使用原文獻(xiàn)中使用的大小,這樣你可以更容易地通過一個(gè)具體的例子來理解這個(gè)概念。

上面這些聽起來不錯(cuò),但是對(duì)于一張圖片的信息,哪些是有用的哪些是冗余的呢?為了定義這個(gè)有用信息,我們需要知道它對(duì)什么有用。顯然,特征向量對(duì)于我們看一張圖像沒什么用。但是,它對(duì)圖像識(shí)別和目標(biāo)檢測(cè)這樣的任務(wù)很有用。將由這些算法生成的特征向量作為支持向量機(jī)等分類算法的輸入往往可以得到不錯(cuò)的結(jié)果。

但是,對(duì)于分類任務(wù)來說,哪類特征是有用的呢?讓我們先用一個(gè)例子討論一下。假設(shè)我們想設(shè)計(jì)一個(gè)目標(biāo)檢測(cè)器來檢測(cè)襯衫或者外套上的紐扣。通常紐扣是圓的(可能在圖片上會(huì)是橢圓)而且一般會(huì)有一些孔用于縫紉。你可以在一張紐扣的圖片上執(zhí)行邊緣檢測(cè),僅僅通過觀察邊緣圖像就可以判斷它是不是一個(gè)紐扣。在這個(gè)例子中,邊緣信息是有用的而顏色信息是無用的。此外,特征也需要有區(qū)分能力。例如,從某一張圖片中提取的一個(gè)好的特征應(yīng)具備區(qū)分紐扣和其他圓心物體(如硬幣和車輪)的能力。

對(duì)于HOG特征描述子,選用梯度方向的分布作為特征。一張圖像的梯度(x和y方向的導(dǎo)數(shù))很有用因?yàn)樵谶吘壓凸战牵◤?qiáng)度變化劇烈的區(qū)域)處的梯度幅值很大。而且我們知道邊緣和拐角比其他平坦的區(qū)域包含更多關(guān)于物體形狀的信息。

如何計(jì)算梯度方向直方圖

在這一節(jié),我們將詳細(xì)介紹HOG描述子的計(jì)算。為了解釋計(jì)算的每個(gè)步驟,我們使用一個(gè)圖片塊進(jìn)行分析。

Step 1: 預(yù)處理

正像之前提到的那樣,HOG特征通過在一張64×128的圖片塊上計(jì)算得到以用于行人檢測(cè)。當(dāng)然完整的圖片可以是任意的尺寸。通常我們會(huì)在圖片的不同位置分析多尺度圖片塊。唯一的要求就是圖片塊需要有固定的長(zhǎng)寬比。在我們的例子中,圖片塊需要保持1:2 的縱橫比。比如:100×200, 128×256或者1000×2000都可以,但101×205就不滿足要求。

為了解釋這一點(diǎn),我在下面選用了一張720×475的圖片。我們?cè)趫D上選擇一個(gè)圖片塊來計(jì)算HOG特征。這個(gè)小塊是從原圖像上裁剪下來的并且縱橫比調(diào)整為64×128。這樣我們就準(zhǔn)備好計(jì)算這個(gè)圖片塊的HOG特征了。

Hog preprocess

原始文獻(xiàn)中Dalal和Triggs也將 γ γ 矯正放在預(yù)處理步驟中,但是帶來的增益很小因此這里我們忽略這一步。

Step 2: 計(jì)算梯度圖

為了計(jì)算HOG特征,我們需要先計(jì)算圖像水平和豎直方向的梯度。畢竟我們想要計(jì)算梯度直方圖。這一步可以很容易通過的核對(duì)對(duì)原圖像進(jìn)行濾波實(shí)現(xiàn)。

gradient kernel

我們也可以使用OpenCV中的Sobel算子(kernel size設(shè)為1)得到相同的結(jié)果。

// C++ gradient calculation. 
// Read image
Mat img = imread("bolt.png");
img.convertTo(img, CV_32F, 1/255.0);

// Calculate gradients gx, gy
Mat gx, gy; 
Sobel(img, gx, CV_32F, 1, 0, 1);
Sobel(img, gy, CV_32F, 0, 1, 1);
# Python gradient calculation 

# Read image
im = cv2.imread('bolt.png')
im = np.float32(im) / 255.0

# Calculate gradient 
gx = cv2.Sobel(img, cv2.CV_32F, 1, 0, ksize=1)
gy = cv2.Sobel(img, cv2.CV_32F, 0, 1, ksize=1)

下一步我們可以用下面的公式來計(jì)算梯度的幅值和方向。

formula

如果你使用OpenCV,可以通過下面的cartToPolar函數(shù)實(shí)現(xiàn)。

// C++ Calculate gradient magnitude and direction (in degrees)
Mat mag, angle; 
cartToPolar(gx, gy, mag, angle, 1); 

在Python中實(shí)現(xiàn)如下:

# Python Calculate gradient magnitude and direction ( in degrees ) 
mag, angle = cv2.cartToPolar(gx, gy, angleInDegrees=True)

下圖顯示了計(jì)算得到的梯度:

gradients

左:X方向梯度幅值圖;中:Y方向梯度幅值圖;右:梯度幅值圖

X方向的梯度凸顯豎直的線而Y方向的梯度凸顯水平的線。梯度的幅值出現(xiàn)在強(qiáng)度變化劇烈的地方。在強(qiáng)度平坦的區(qū)域幾乎沒有梯度。我故意忽略了梯度方向圖,因?yàn)樵趫D像上顯示梯度方向沒有傳遞太多的信息。

梯度圖像移除了很多不必要的信息(比如不變的背景),突出了輪廓信息。也就是說,你僅僅通過看梯度圖像還是可以辨認(rèn)出圖像有有一個(gè)人。

對(duì)于每一個(gè)像素,梯度都會(huì)有幅值和方向。對(duì)于彩色圖像,需要分別計(jì)算3個(gè)通道的梯度(如上圖所示)。而該像素點(diǎn)的幅值是這3個(gè)通道梯度幅值的最大值,方向是最大梯度幅值對(duì)應(yīng)的角度。

Step 3: 在8×8的cell中計(jì)算梯度直方圖

在這一步,圖像被分成8×8的很多cell,而梯度直方圖是在這些cell中計(jì)算出來的。

hog-cells

我們一會(huì)兒將學(xué)習(xí)直方圖,但在那之前,我們先理解一下為什么將圖像切分成很多8×8的cell。使用特征描述子來描述圖像中的一小塊的一個(gè)重要原因是它用更為緊湊的表示方法刻畫了原圖像。一個(gè)8×8的圖片塊包含了8×8×3=192個(gè)像素值。而這個(gè)圖像塊的每個(gè)像素點(diǎn)梯度信息包含梯度幅值和方向兩個(gè)值,一共是8×8×2=128個(gè)值,這128個(gè)值可以通過用包含9個(gè)bin的直方圖表示成一個(gè)一維數(shù)組(包含9個(gè)值)。這樣做不僅可以使圖像表示更緊湊,而且在一個(gè)圖片塊中計(jì)算直方圖可以讓這種表示方法對(duì)噪聲有更強(qiáng)的魯棒性。單個(gè)像素的梯度信息可能包含噪聲,而一個(gè)8×8的圖片塊中的直方圖讓這種表示方法對(duì)噪聲更不敏感。

但是為什么要用8×8的圖片塊呢?為什么不是32×32?這是由我們需要尋找的特征比例決定的。HOG特征起初是被用來檢測(cè)行人的。8×8的cell在一張64×128的行人圖片塊中的足以捕捉感興趣的特征(如人臉、頭頂?shù)龋?/p>

上述梯度直方圖本質(zhì)上是一個(gè)包含9個(gè)數(shù)字的向量(或數(shù)組),這9個(gè)數(shù)字分別對(duì)應(yīng)0°、20°、40°、… 160°。

我們來看一下圖片塊中的一個(gè)8×8 cell的梯度是什么樣子。

這里寫圖片描述

中:一個(gè)RGB cell及其梯度(用箭頭表示);右:cell中的梯度大小和方向(數(shù)字表示)

如果你是一個(gè)計(jì)算機(jī)視覺領(lǐng)域新手,中間的這幅圖為你提供了很多信息。它展示了用箭頭表示的梯度信息的梯度圖——箭頭的指向表示了梯度的方向而箭頭的長(zhǎng)度表示了梯度的大小。需要注意到的一點(diǎn)是箭頭的方向指向了圖像強(qiáng)度變化的方向,而梯度大小表示了強(qiáng)度的變化有多大。

在右邊的圖上,我們發(fā)現(xiàn)8×8的cell中表示梯度的數(shù)字有一點(diǎn)細(xì)微的差別——角度實(shí)在0°到180°之間的而不是0°到360°之間。這些叫做“無符號(hào)梯度”,因?yàn)橐驗(yàn)橐粋€(gè)正負(fù)方向的兩個(gè)梯度由同一個(gè)數(shù)字表示。換句話說,某一個(gè)梯度箭頭和它對(duì)應(yīng)的另一個(gè)值(加上180°對(duì)應(yīng)的那個(gè)值)被當(dāng)作是同一個(gè)梯度。根據(jù)經(jīng)驗(yàn),無符號(hào)梯度被證明比有符號(hào)梯度效果更好。一些HOG特征的實(shí)現(xiàn)代碼會(huì)允許你選擇是否使用有符號(hào)梯度。

下一步就是在這些8×8的cells上創(chuàng)建梯度直方圖。直方圖包含9個(gè)bins分別對(duì)應(yīng)著0°、20°、40°、… 160°。

下圖解釋了具體的過程。我們?cè)诤蜕厦婺莻€(gè)圖一樣的8×8的cells上查看梯度的大小和方向。每個(gè)bin是基于梯度方向選出來的,對(duì)應(yīng)的票數(shù)(加在當(dāng)前bin上的值)對(duì)應(yīng)著梯度的大小。我們先來看看用藍(lán)色圓圈出來的像素,它的梯度的角度是80°,大小為2。因此它在第5個(gè)bin上加2。下圖中用紅色圈出來的梯度的角度是10°,大小是4。由于10°是在0°和20°的中間位置, 因此改位置梯度對(duì)應(yīng)票數(shù)被一分為二加到相鄰的兩個(gè)bin上。

這里寫圖片描述

還有一個(gè)細(xì)節(jié)需要注意。如果梯度方向大于160°。此時(shí)梯度的角度位于160°和180°之間。我們知道0°和180°是一樣的(無符號(hào)梯度),因此在下面的例子中,梯度方向?yàn)?65°的像素按比例將梯度大小分配到0°和160°的bin中。

這里寫圖片描述

8×8的cell中所有像素處的梯度按照方向?qū)⑻荻却笮±奂拥?個(gè)bin以創(chuàng)建最后的梯度直方圖。上圖中的cell對(duì)應(yīng)的梯度直方圖如下:

這里寫圖片描述

在我們的表示結(jié)果中,y軸對(duì)應(yīng)0°。你可以發(fā)現(xiàn)上面的直方圖中有大量的權(quán)重(梯度大小的投票結(jié)果)在0°和180°附近,這從另外一個(gè)角度說明了在這個(gè)cell中大部分梯度方向要么朝上要么朝下。

Step 4: 16×16 Block標(biāo)準(zhǔn)化

這里寫圖片描述

在上述步驟中,我們基于圖像的梯度創(chuàng)建直方圖。一張圖片的梯度對(duì)整體的光線的光線比較敏感。如果你把圖像所有的像素值除以2使整張圖像變暗,梯度的大小也會(huì)變?yōu)樵瓉淼囊话?,從而梯度直方圖的值也會(huì)將為原來的一半。理想情況下,我們想讓特征描述子獨(dú)立于光線變化。換句話說,我們想要“標(biāo)準(zhǔn)化”這個(gè)直方圖使它不受光線變化的影響。

在我講梯度直方圖如何標(biāo)準(zhǔn)化之前,我們先來看看一個(gè)長(zhǎng)度為3的向量如何標(biāo)準(zhǔn)化。

假設(shè)我們有一個(gè)RGB顏色向量[128, 64, 32]。這個(gè)向量的長(zhǎng)度是

。這也叫做向量的L2范數(shù)。將這個(gè)向量的所有元素除以向量長(zhǎng)度146.64就可以得到一個(gè)標(biāo)準(zhǔn)化的向量[0.87, 0.43, 0.22],現(xiàn)在考慮另外一個(gè)向量,這個(gè)向量的元素是第一個(gè)向量的兩倍即2×[128, 64, 32]=[256, 128, 64]。你可以自己計(jì)算一下它對(duì)應(yīng)的標(biāo)準(zhǔn)化結(jié)果,發(fā)現(xiàn)結(jié)果仍然是[0.87, 0.43, 0.22],這個(gè)值和第一個(gè)RGB向量的標(biāo)準(zhǔn)化向量相同。你可以發(fā)現(xiàn)標(biāo)準(zhǔn)化一個(gè)向量移除了這個(gè)向量的尺度信息。

現(xiàn)在我們知道如何標(biāo)準(zhǔn)化一個(gè)向量,你可能想到當(dāng)計(jì)算HOG特征的時(shí)候你可以像之前標(biāo)準(zhǔn)化一個(gè)3×1向量一樣去標(biāo)準(zhǔn)化9×1的直方圖。這的確是個(gè)不錯(cuò)的想法,但是更好的做法是標(biāo)準(zhǔn)化一個(gè)更大的16×16的block。一個(gè)16×16的block包含4個(gè)直方圖,這4個(gè)直方圖可以連接成一個(gè)36×1的向量,而且這個(gè)向量仍然可以像那個(gè)3×1的向量一樣進(jìn)行標(biāo)準(zhǔn)化。每次標(biāo)準(zhǔn)化后,整個(gè)窗口移動(dòng)8個(gè)像素并再次計(jì)算得到一個(gè)36×1的標(biāo)準(zhǔn)化向量,就這樣一直重復(fù)這個(gè)過程。

Step 5: 計(jì)算HOG特征向量

為了計(jì)算整個(gè)圖片塊最終的特征向量所有的36×1的向量被連接成一個(gè)大向量。這個(gè)大向量的維度是多少大呢?

我們來計(jì)算:

- 1. 我們有多少個(gè)不同位置的16×16的block?一共有 (64-8)/8=7 個(gè)水平的位置和 (128-8)/8=15 個(gè)豎直的位置,所以總計(jì)7×15=105個(gè)。

- 2. 每一個(gè)16×16的block被表示成一個(gè)36×1的向量。因此,當(dāng)我們把他們連接成一個(gè)大向量的時(shí)候會(huì)得到一個(gè)36×105=3780維度的向量。

梯度直方圖可視化

一個(gè)圖像塊梯度特征的可視化通常通過在所有8×8的cell里畫出對(duì)應(yīng)的標(biāo)準(zhǔn)化的9×1向量(直方圖)。如下圖所示。你會(huì)注意到直方圖的主要方向捕捉了人的形狀,尤其是在軀干和腿附近。

不幸的是,目前在OpenCV中并沒有一個(gè)簡(jiǎn)單的方法方法來可視化HOG特征。

到此這篇關(guān)于Python與C++中梯度方向直方圖的實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)Python 梯度方向直方圖內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • python實(shí)現(xiàn)人民幣大寫轉(zhuǎn)換

    python實(shí)現(xiàn)人民幣大寫轉(zhuǎn)換

    這篇文章主要為大家詳細(xì)介紹了python實(shí)現(xiàn)人民幣大寫轉(zhuǎn)換的方法,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2018-06-06
  • Python協(xié)程的用法和例子詳解

    Python協(xié)程的用法和例子詳解

    這篇文章主要為大家詳細(xì)介紹了Python協(xié)程的用法和例子,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-09-09
  • Python用戶自定義異常的實(shí)現(xiàn)

    Python用戶自定義異常的實(shí)現(xiàn)

    這篇文章主要介紹了Python用戶自定義異常的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-12-12
  • Python 中如何使用 setLevel() 設(shè)置日志級(jí)別

    Python 中如何使用 setLevel() 設(shè)置日志級(jí)別

    這篇文章主要介紹了在 Python 中使用setLevel() 設(shè)置日志級(jí)別,Python 提供了一個(gè)單獨(dú)的日志記錄模塊作為其標(biāo)準(zhǔn)庫的一部分,以簡(jiǎn)化日志記錄,本文將討論日志記錄 setLevel 及其在 Python 中的工作方式,需要的朋友可以參考下
    2023-07-07
  • Python內(nèi)置模塊Collections的使用教程詳解

    Python內(nèi)置模塊Collections的使用教程詳解

    collections 是 Python 的一個(gè)內(nèi)置模塊,所謂內(nèi)置模塊的意思是指 Python 內(nèi)部封裝好的模塊,無需安裝即可直接使用。本文將詳解介紹Collections的使用方式,需要的可以參考一下
    2022-03-03
  • 利用Python庫Scapy解析pcap文件的方法

    利用Python庫Scapy解析pcap文件的方法

    今天小編就為大家分享一篇利用Python庫Scapy解析pcap文件的方法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2019-07-07
  • Python爬蟲部分開篇概念講解

    Python爬蟲部分開篇概念講解

    在學(xué)習(xí)Python爬蟲部分,需要已經(jīng)學(xué)過Python基礎(chǔ)和前端的相關(guān)知識(shí),本文對(duì)python爬蟲概念及原理給大家詳細(xì)介紹,需要的朋友跟隨小編一起看看吧
    2021-04-04
  • Python入門學(xué)習(xí)之字符串與比較運(yùn)算符

    Python入門學(xué)習(xí)之字符串與比較運(yùn)算符

    這篇文章主要介紹了Python入門學(xué)習(xí)之字符串與比較運(yùn)算符,是Python語法中的基礎(chǔ)知識(shí),需要的朋友可以參考下
    2015-10-10
  • Pytorch實(shí)驗(yàn)常用代碼段匯總

    Pytorch實(shí)驗(yàn)常用代碼段匯總

    這篇文章主要介紹了Pytorch實(shí)驗(yàn)常用代碼段匯總,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-11-11
  • python處理json字符串(使用json.loads而不是eval())

    python處理json字符串(使用json.loads而不是eval())

    eval 跟json.loads 是不一樣的函數(shù),是有實(shí)現(xiàn)不一樣功能的地方,但是在某些地方它們兩個(gè)函數(shù)的功能是一樣的,本文就詳細(xì)介紹一下
    2021-09-09

最新評(píng)論