介紹
在機器學習算法的世界裡,特徵工程是非常重要的。實際上,作為一名數據科學家,這是我最喜歡的方面之一!從現有特徵中設計新特徵並改進模型的性能,這就是我們進行最多實驗的地方。
世界上一些頂級數據科學家依靠特徵工程來提高他們在競賽排行榜得分。我相信你甚至會在結構化數據上使用各種特徵工程技術。
我們可以將此技術擴展到非結構化數據(例如圖像)嗎?對於計算機視覺愛好者來說,這是一個有趣的問題,我們將在本文中解決這個問題。準備好對圖像數據進行特徵提取形式的特徵工程吧!
在本文中,我將向你介紹一種流行的圖像特徵提取技術——方向梯度直方圖(Histogram of Oriented Gradients),或俗稱的HOG。我們將了解什麼是HOG特徵描述子,它是如何工作的(算法背後的完整數學原理),最後,用Python實現它。
目錄
什麼是特徵描述子?HOG特徵描述子簡介HOG的計算過程預處理數據計算梯度計算幅值和方向使用梯度和方向創建直方圖的方法HOG的計算過程計算梯度直方圖標準化梯度一幅完整圖像的特徵在Python中實現HOG特徵描述子什麼是特徵描述子?
你可能在閱讀標題時就已經遇到了這個問題。所以,在我們跳進文章的HOG部分之前,首先要清楚這一點。
看看下面顯示的兩個圖像。你能分辨出圖像中的物體嗎?
我們可以清楚地看到這裡的右圖有狗,左圖有車。現在,讓我讓這項任務稍微複雜一點,分辨下圖所示的對象:
還是挺容易的。你能猜出第一種和第二種情況之間有什麼區別嗎?第一對圖像有很多信息,比如物體的形狀,顏色,邊緣,背景等。
另一方面,第二對信息少得多(只有形狀和邊緣),但它仍然足以區分這兩個圖像。
你知道我想說什麼嗎?在第二種情況下,我們還是很容易區分對象,因為它具有識別對象所需的必要信息。這正是特徵描述子的作用:
它是圖像的簡化表示,僅包含有關圖像的最重要信息。
以下是一些最受歡迎的的特徵描述子。
HOG:方向梯度直方圖SIFT:尺度不變的特徵變換SURF:加速穩健特徵在本文中,我們將重點關注HOG特徵描述子及其工作原理。讓我們開始吧!
HOG特徵描述子簡介
HOG(Histogram of Oriented Gradients)是一種特徵描述子,通常用於從圖像數據中提取特徵。它廣泛用於計算機視覺任務的物體檢測。
讓我們看一下HOG的一些重要方面,它們與其他特徵描述子不同:
HOG描述符關注對象的結構或形狀。現在你可能會問,這和我們為圖像提取的邊緣特徵有什麼不同?在邊緣特徵的情況下,我們只識別像素是否是邊緣。HOG還能夠提供邊緣方向。這是通過提取邊緣的梯度和方向(或者你可以說大小和方向)來實現的此外,這些方向是在「局部」進行部分計算的。這意味著整個圖像被分割成更小的區域,對於每個區域,計算梯度和方向。我們將在接下來的小節中更詳細地討論這個問題最後,HOG將分別為這些區域生成一個直方圖。直方圖是使用像素值的梯度和方向創建的,因此得名「方向梯度直方圖」。給一個正式定義:
HOG特徵描述子計算圖像局部區域中梯度方向的出現次數。
使用OpenCV等工具實現HOG非常簡單。這只是幾行代碼,因為我們在skimage.feature庫中有一個名為hog的預定義函數。但是,我們在本文中的重點是如何實際計算這些特徵。
計算方向梯度直方圖(HOG)的過程
我們現在應該對HOG特徵描述子的基本概念有所了解。是時候深入研究本文背後的核心思想了。讓我們討論HOG的逐步計算過程。
考慮下面的尺寸圖像(180 x 280)。讓我們詳細了解如何為此圖像創建HOG特徵:
第一步:預處理數據(64x128)
這是大多數人都非常熟悉的一步。預處理數據是任何機器學習項目中的關鍵步驟,即使在處理圖像時也沒有什麼不同。
我們需要對圖像進行預處理,並將寬高比降低到1:2。圖像大小最好是64 x 128。這是因為我們將圖像分成88和1616小塊來提取特徵。具有指定的大小(64 x 128)將使我們的所有計算相當簡單。事實上,這正是原始論文中使用的值。
回到我們的例子,讓我們將大小為64x128作為目前的標準圖像大小。以下是調整後的圖像:
第二步:計算梯度(x和y方向)
下一步是計算圖像中每個像素的梯度。梯度是x和y方向上的小變化。這裡,我要從圖像中取一小塊,然後計算它的梯度:
我們將得到這個部分的像素值。假設我們為給定的部分生成下面的像素矩陣(這裡的矩陣只是作為一個例子,這些並不是給定部分的原始像素值):
我突出顯示了像素值85。現在,要確定x方向上的梯度,我們需要從右邊的像素值減去左邊的值。類似地,為了計算y方向的梯度,我們將從所選像素上的像素值減去下面的像素值。
因此,該像素的x和y方向的梯度為:
X方向的變化($G_x$)= 89-78 = 11Y方向的變化($G_y$)= 68-56 = 8這個過程將給我們兩個新的矩陣,一個在x方向上存儲梯度,另一個在y方向上存儲梯度。這類似於使用大小為1的Sobel內核。當發生劇烈變化時(例如在邊緣附近),幅值(magnitude)會更高。
我們分別計算了x和y方向的梯度。對圖像中的所有像素重複相同的過程。下一步是使用這些值找到幅值和方向。
第三步:計算幅值和方向
使用我們在最後一步中計算的梯度,我們現在將確定每個像素值的大小和方向。對於這一步,我們將使用勾股定理(是的,與你在學校學習的那個相同!)。
看看下面的圖片:
在之前的例子中,Gx和Gy分別是11和8。應用勾股定理計算總梯度大小:
總梯度幅值=√[(G_x)^2 +(G_y)^2]總梯度幅值=√[(11)^2 +(8)^2]= 13.6接下來,計算相同像素的方向。我們知道我們可以把角度寫成tan
tan(Φ)= Gy/Gx
因此,角度的值將是:
Φ= atan(Gy/Gx)
當我們代入這些值時,角度是36°。現在,對於每個像素值,我們有總梯度(幅值)和方向。我們需要使用這些梯度和方向生成直方圖。
但是請稍等——在深入研究HOG特徵描述子中如何創建直方圖之前,我們需要稍作休息。把這看作是整個過程中的一小步。我們將首先討論一些簡單的方法來創建直方圖使用兩個值,梯度和方向。
使用梯度和方向創建直方圖的不同方法
直方圖是顯示一組連續數據的頻率分布的圖。變量(以箱子的形式)在x軸上,頻率在y軸上。這裡,我們設x軸上為角度,y軸為頻率。
方法1:
讓我們從生成直方圖的最簡單方法開始。我們將取每個像素值,找到像素的方向並更新頻率表。
下面是高亮像素(85)的處理過程。由於該像素的角度為36°,我們將對角度值36添加一個數字,表示頻率:
對所有像素值重複相同的過程,最後得到一個頻率表,表示角度以及這些角度在圖像中的出現情況。這個頻率表可用於生成在x軸上有角度值的直方圖和在y軸上有頻率值的直方圖。
這是創建直方圖的一種方法。注意,這裡直方圖的bin值(角度的間隔)為1。因此我們得到大約180個不同的桶,每個桶代表一個角度值。另一種方法是為更大的角度值間隔創建直方圖特徵。
方法2:
這個方法與前面的方法類似,不同之處在於我們的bin值為20。因此,我們在這裡得到的桶數是9。
同樣,對於每個像素,我們將檢查角度,並以9 x 1矩陣的形式存儲角度值的頻率。繪製這個將給我們直方圖:
方法3:
上述兩種方法僅使用角度值來生成直方圖,並且不考慮梯度值。這是我們可以生成直方圖的另一種方式 - 我們可以使用梯度幅值(magnitude)來填充矩陣中的值,而不是使用頻率。以下是示例:
方法4:
讓我們對上面的方法做一個小修改。在這裡,我們將像素梯度的貢獻添加到像素梯度兩側的區間。請記住,更接近角度的bin值有更高的貢獻。
這正是在HOG特徵描述子中創建直方圖的方式。
第4步:計算8×8單元(9×1)中梯度的直方圖
HOG特徵描述子中創建的直方圖不會為整個圖像生成。將圖像分割為8×8個單元格,計算每個單元格的方向梯度直方圖。
通過這樣做,我們得到了代表整個圖像的小塊的特徵(或直方圖)。我們當然可以把這個值從8 x 8換成16 x 16或者32 x 32。
如果我們將圖像劃分為8×8個單元格並生成直方圖,我們使用我們在上一節中討論的方法4生成該矩陣,將為每個單元格獲得9 x 1矩陣。
一旦我們為圖像中的8×8小塊生成了HOG,下一步就是對直方圖進行標準化。
步驟5:將16×16單元(36×1)中的梯度標準化
在我們理解這是如何做到的之前,首先理解為什麼要這樣做是很重要的。
雖然我們已經為圖像的8×8單元創建了HOG特徵,但是圖像的梯度對整體光照很敏感。這意味著對於特定的圖像,圖像的某些部分與其他部分相比會非常明亮。
我們不能從圖像中完全消除這個。但是我們可以通過使用16×16個塊來對梯度進行歸一化來減少這種光照變化。下面的例子可以解釋如何創建16×16塊:
在這裡,我們將組合四個8×8單元來創建一個16×16塊。並且我們已經知道每個8×8單元具有用於直方圖的9×1矩陣。因此,我們將有四個9×1矩陣或一個36×1矩陣。為了標準化該矩陣,我們將這些值中的每一個除以值的平方和的平方根。在數學上,對於給定的向量V:
V = [a1,a2,a3,... a36]
我們計算平方和的根:
k =√(a1)2+(a2)2+(a3)2+ .... (A36)2
並將向量V中的所有值除以此值k:
結果將是尺寸為36×1的歸一化向量。
第6步:完整圖像的特徵
我們現在正處於為圖像生成HOG特徵的最後一步。到目前為止,我們已經為16×16塊圖像創建了特徵。現在,我們將結合所有這些來獲得最終圖像的特徵。
你能猜出我們將為給定圖像提供的特徵總數是多少?我們首先需要找出一個64×128圖像可以得到多少這樣的16×16塊:
我們將有105(7×15)塊16×16。這105個塊中的每一個都具有36×1的向量作為特徵。因此,圖像的總特徵將是105×36×1 = 3780個特徵。
我們現在將為單個圖像生成HOG特徵,並驗證我們是否在最後獲得相同數量的特徵。
在Python中實現HOG特徵描述子
是時候實現了!我敢肯定,這是本文中最受期待的部分。讓我們開始吧。
我們將看到如何在單個圖像上生成HOG特徵,以及是否可以在更大的數據集上應用相同的HOG特徵。我們將首先加載所需的庫和我們要為其創建HOG特徵的圖像:
#導入所需的庫from skimage.io import imread, imshowfrom skimage.transform import resizefrom skimage.feature import hogfrom skimage import exposureimport matplotlib.pyplot as plt%matplotlib inline#讀入圖片img = imread('puppy.jpeg')imshow(img)print(img.shape)(663,459,3)
我們可以看到圖像的形狀是663 x 459.我們將不得不將此圖像調整為64 x 128.請注意,我們使用的是skimage,它將輸入作為高度x寬度。
#調整圖像大小resized_img = resize(img, (128,64)) imshow(resized_img) print(resized_img.shape)(128,64,3)
在這裡,我將直接使用skimage.features的hog函數。因此,我們不必單獨計算梯度,幅值(總梯度)和方向。hog函數將在內部計算它並返回特徵矩陣。
此外,如果你設置參數'visualize = True',它將返回HOG的圖像。
#創建hog特徵fd, hog_image = hog(resized_img, orientations=9, pixels_per_cell=(8, 8), cells_per_block=(2, 2), visualize=True, multichannel=True)在繼續之前,讓我先介紹一下這些超參數代表什麼。或者,你可以在此處查看官方文檔中的定義。
orientations是我們要創建桶的數量。由於我想要一個9 x 1矩陣,我將orientations設置為9pixelspercell定義我們為其創建直方圖的單元格的大小。在我們在本文中介紹的示例中,我們使用了8 x 8個單元格,在這裡我將設置相同的值。如前所述,你可以選擇更改此值我們有另一個超參數cellperblock,它是我們對直方圖進行標準化的塊的大小。這個參數是每個塊的單元格數量而不是像素的數量。因此,我們將使用2 x 2而不是16 x 16函數的特徵矩陣存儲在變量fd中,圖像存儲在hog_image中。讓我們檢查一下特徵矩陣的形狀:
fd.shape(3780)'''HOG FEATURES'''# 導入需要的包from skimage.io import imread, imshowfrom skimage.transform import resizefrom skimage.feature import hogfrom skimage import exposure#讀取圖片img = imread('puppy.jpeg')#改變圖片尺寸resized_img = resize(img, (128,64))#產生HOG特徵fd, hog_image = hog(resized_img, orientations=9, pixels_per_cell=(8, 8),cells_per_block=(2, 2), visualize=True, multichannel=True)print('\n\nShape of Image Features\n\n')print(fd.shape)Shape of Image Features(3780,)正如預期的那樣,我們有3,780個圖像特徵,這驗證了我們之前在步驟7中所做的計算。你可以選擇更改超參數的值,這將為你提供不同大小的特徵矩陣。
讓我們最後看看HOG圖像:
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(16, 8), sharex=True, sharey=True) ax1.imshow(resized_img, cmap=plt.cm.gray) ax1.set_title('Input image') # 縮放直方圖以便更好地顯示 hog_image_rescaled = exposure.rescale_intensity(hog_image, in_range=(0, 10)) ax2.imshow(hog_image_rescaled, cmap=plt.cm.gray) ax2.set_title('Histogram of Oriented Gradients')plt.show()
結束筆記
本文背後的想法是讓你了解HOG特徵描述子背後的實際原理以及如何計算特徵。整個過程分為7個簡單步驟。
下一步,我鼓勵你嘗試在簡單的計算機視覺問題上使用HOG特徵,並查看模型性能是否有所改善。