https://blog.csdn.net/chaipp0607/article/details/70888899
https://blog.csdn.net/kuweicai/article/details/78981150?utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7EBlogCommendFromMachineLearnPai2%7Edefault-1.control
图像直方图中的特征值由 x i x_i xi的像素构成的特征直方图为: H ( I ) = [ h ( x 1 ) , h ( x 2 ) , … , h ( x n ) ] H(I)=[h(x_1),h(x_2),\dots,h(x_n)] H(I)=[h(x1),h(x2),…,h(xn)]
其中 h ( x i ) h(x_i) h(xi)表示像素个数的归一化处理值,特征直方图反映出来的是某一特征的概率分布,对于灰度图像,直方图就是灰度信息统计概率分布,对 h ( x i ) h(x_i) h(xi)进行累计,得到累计直方图为: S ( I ) = [ s ( x 1 ) , s ( x 2 ) , … , s ( x n ) ] S(I)=[s(x_1),s(x_2),\dots,s(x_n)] S(I)=[s(x1),s(x2),…,s(xn)]
HOG是通过计算和统计图像局部区域的梯度方向直方图来实现特征描述的,对于一幅图像,在点 ( x , y ) (x,y) (x,y)处的梯度幅度 ∣ ∇ f ( x , y ) ∣ |\nabla f(x,y)| ∣∇f(x,y)∣和方向角 θ \theta θ为:
∣ ∇ f ( x , y ) ∣ = m a g ( ∇ f ( x , y ) ) = G x 2 + G y 2 |\nabla f(x,y)|=mag(\nabla f(x,y))=\sqrt{G_x^2+G_y^2} ∣∇f(x,y)∣=mag(∇f(x,y))=Gx2+Gy2
θ = a r c t a n ( G y / G x ) \theta=arctan(G_y / G_x) θ=arctan(Gy/Gx)
其中 G x G_x Gx和 G y G_y Gy分布x方向与y方向的梯度,HOG在进行特征描述的时候将 θ \theta θ的梯度方向在 [ − π 2 , π 2 ] [-\frac{\pi}{2},\frac{\pi}{2}] [−2π,2π]区间划分为N个均匀空间 S k S_k Sk,像素点(x,y)在k个梯度方向上的梯度投影为:
L k ( x , y ) = { ∇ f ( x , y ) ∣ θ ∈ S k 0 θ ∉ S k L_k(x,y)=\begin{cases} \nabla f(x,y)| & \theta \in S_k\\ 0& \theta \notin S_k \end{cases} Lk(x,y)={∇f(x,y)∣0θ∈Skθ∈/Sk
图像梯度发个信直方图就是对图像中所有像素点K维梯度特征的直方图统计,将图像划分成小部分连通域,细胞单元的各个像素点进行梯度方向直方图描述,最后结合成相应的特征描述器,提取步骤如下:
(1)归一化处理,为了提高图像特征描述对光照及环境变化的鲁棒性,降低图像局部的阴影、局部曝光过多及纹理失真,尽可能抑制噪声干扰。
(2)计算图像梯度,对于图像 I ( x , y ) I(x,y) I(x,y),计算图像在 ( x , y ) (x,y) (x,y)处的水平方向梯度 G x = I ( x + 1 , y ) − I ( x − 1 , y ) G_x=I(x+1,y)-I(x-1,y) Gx=I(x+1,y)−I(x−1,y),竖直方向梯度为 G y = I ( x , y + 1 ) − I ( x , y − 1 ) G_y=I(x,y+1)-I(x,y-1) Gy=I(x,y+1)−I(x,y−1),计算水平与竖直方向梯度只需要对图像进行模板卷积即可得到,水平模板为 [ − 1 , 0.1 ] [-1,0.1] [−1,0.1],竖直模板为 [ − 1 , 0.1 ] T [-1,0.1]^T [−1,0.1]T;
(3)统计梯度方向,将图像划分为 8 × 8 8 \times 8 8×8个方格单元, 2 × 2 2 \times 2 2×2个单元组成一个块,然后对属于块内的像素点投票统计,计算每个方格单元的梯度特征,每个像素点梯度方向都采用线性插值。将每个方块单元梯度特征组合放在一起
(4)特征向量归一化,为克服光照不均匀变化与背景和对比的差异,需要对块内特征向量进行归一化处理,首先对每个块内36维特征V进行 L 2 − n o r m L_2-norm L2−norm归一化,即完成操作 V = V ∣ ∣ V ∣ ∣ 2 + ε 2 V=V \sqrt{||V||^2+ \varepsilon^2} V=V∣∣V∣∣2+ε2,其中 ε \varepsilon ε为很小的常数,然后利用 L 2 − h y s L_2-hys L2−hys重新进行归一化,同时保持限制V的最大值为0.2.由于相邻快之间可能存在重叠,使得每个单元对块都有影响,因此需要对梯度强度归一化,使每一个单元格特征以不同的结果多次出现在最后的特征向量中。
(5)生成特征向量。将图像的每一个块特征组合在一起,得到图像的HOG特征。
Opencv提供了专门HOGDescriptior类用于完成HOG特征检测,传统HOG特征计算时间复杂度较高,在实际进行特征描述时一般次啊用积分直方图来代替,像素点(x,y)积分直方图为梯度图像中满足矩形区域所有像素点的梯度方向直方图。
#include
#include
#include
#include
#include
int main(void)
{
cv::Mat input = cv::imread("d:/Opencv Picture/HOG/simple.png");
if (input.empty())
return 1;
cv::Mat src = input.clone();
//这一部分是如何计算HOG特征描述子
#if 0
cv::Mat dst, dst_gray;
resize(src, dst, cv::Size(64, 128));
cvtColor(dst, dst_gray, CV_BGR2GRAY);
cv::HOGDescriptor detector(cv::Size(64, 128), cv::Size(16, 16), cv::Size(8, 8), cv::Size(8, 8), 9);
std::vector<float> descriptor;
std::vector<cv::Point> location;
detector.compute(dst_gray, descriptor, cv::Size(0, 0), cv::Size(0, 0), location);
std::cout << "descriptor size " << descriptor.size();
#endif
//下面是调用opencv中集成的基于HOG的SVM行人检测数据集,进行行人检测
cv::HOGDescriptor hog =cv::HOGDescriptor::HOGDescriptor();
hog.setSVMDetector(hog.getDefaultPeopleDetector());
std::vector<cv::Rect> peopleLocation;
hog.detectMultiScale(src, peopleLocation, 0, cv::Size(8, 8), cv::Size(16, 16), 1.05, 2.0);
for (int i = 0; i < peopleLocation.size(); ++i)
{
rectangle(src, peopleLocation[i], cv::Scalar(0, 0, 255));
}
imshow("input", input);
imshow("src", src);
cvWaitKey();
return 0;
}