HOG特徵檢測的原理及opencv API呼叫
阿新 • • 發佈:2019-02-10
1.預處理
用於計算HOG特徵的影象一般都是選擇大小為64x128畫素大小。在opencv中可以直接呼叫resize()來完成,得到src。當然也有先裁剪在resize()的操作方式。這裡也可以採用gamma correction對src進行處理,但是從Dalal和Triggs的論文可知,其作用並不是很大,所以也可以不用。
2.計算梯度影象
需要計算出src在X和Y方向的梯度影象Gx和Gy(梯度影象均為單通道影象),然後根據Gx和Gy計算出幅值和角度,這裡的角度一般採用無符號表示,即0~180度。另外如果src是三通道的影象,那麼將三個通道中的最大值作為該點的梯度值。這樣做的好處就是將原本8x8個畫素,每個畫素有3個通道,就是8x8x3個數據,計算梯度後每個畫素點有兩個值(幅值和角度)就是8x8x2個數據。資料量變少了,少的部分就是顏色資訊,只保留了邊緣訊號。
在opencv中,可以用sobel()運算元來計算梯度,然後用cartToPolar()來計算幅值和角度。
// 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);
3.計算梯度直方圖
以8x8個畫素為一個cell,計算每個cell的直方圖,每個直方圖有9個bin,分別表示0 20 40 。。。 160度9個方向,而把對應的方向上的幅值作為bin的值。這裡需要考慮的是如果出現一個方向,比如10度,幅度為2,那麼將其線性分解到0和20度兩個bin上,各加1。對於為什麼是對8x8進行直方圖計算,其實比如32x32也是沒有問題的,作者指出對於行人檢測,8x8已經足夠。
選擇以8x8個畫素作為單位計算直方圖,考慮了畫素點周維的資料,這樣會降低噪聲的影響。
在第三步中計算得到的梯度直方圖,如果光照發生變化,那麼直方圖也會相應的發生很大變化,所以這裡進行歸一化處理,這樣可以降低對光照的敏感性。
具體的操作是,在16x16畫素為一個block,將一個block中的4個梯度直方圖進行歸一化(4個直方圖,共36個bin作為一個向量進行歸一化),然後以8x8個畫素作為步長,迴圈操作。在一幅64x128的影象中可以找到7x15個block.而每個block有36x1個數據。所以最後得到的HOG特徵(描述子)是一個7x15x36=3780維的資料。
5. Opencv API的呼叫
opencv中已經集成了HOG特徵提取的演算法。下面是呼叫試例。
#include<opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
int main(void)
{
Mat input = imread("d:/Opencv Picture/HOG/simple.png");
if (input.empty())
return 1;
Mat src = input.clone();
//這一部分是如何計算HOG特徵描述子
#if 0
Mat dst,dst_gray;
resize(src, dst, Size(64, 128));
cvtColor(dst, dst_gray, CV_BGR2GRAY);
HOGDescriptor detector(Size(64, 128), Size(16, 16), Size(8, 8), Size(8, 8), 9);
vector<float> descriptor;
vector<Point> location;
detector.compute(dst_gray, descriptor, Size(0, 0), Size(0, 0),location);
cout << "descriptor size " << descriptor.size();
#endif
//下面是呼叫opencv中整合的基於HOG的SVM行人檢測資料集,進行行人檢測
HOGDescriptor hog=HOGDescriptor();
hog.setSVMDetector(hog.getDefaultPeopleDetector());
vector<Rect> peopleLocation;
hog.detectMultiScale(src,peopleLocation,0,Size(8,8),Size(16,16),1.05,2.0);
for (int i = 0; i < peopleLocation.size(); ++i)
{
rectangle(src, peopleLocation[i], Scalar(0, 0, 255));
}
imshow("input", input);
imshow("src", src);
cvWaitKey();
return 0;
}