本文主要是根据分析一份matlab代码PHOG特征生成的demo得到的,作为总结便于以后使用。
if sum(sum(G))>100
E = edge(G,'canny');
[GradientX,GradientY] = gradient(double(G));
GradientYY = gradient(GradientY);
Gr = sqrt((GradientX.*GradientX)+(GradientY.*GradientY));
index = GradientX == 0;
GradientX(index) = 1e-5;
YX = GradientY./GradientX;
if angle == 180, A = ((atan(YX)+(pi/2))*180)/pi; end
if angle == 360, A = ((atan2(GradientY,GradientX)+pi)*180)/pi; end
[bh bv] = anna_binMatrix(A,E,Gr,angle,bin);
else
bh = zeros(size(I,1),size(I,2));
bv = zeros(size(I,1),size(I,2));
end
首先需要说明的是G是一幅灰度图,将灰度图看做矩阵进行统计,看看是否有足够的像素产生梯度信息,如果小于100的话,表明整个图像接近于是一幅完全的黑色图像。经过上面的比较之后,再对图像进行canny轮廓处理,得到的图像为0-1二值图像(至于其用处在后面介绍)。紧跟其后是对整个图像求梯度,由于梯度实际上是一个在X或者Y方向上的方向向量,所以后面的GradientY./GradientX就相当于求得某一个像素点处的方向向量(tan=sin/cos)。不过由于GradientX可能等于0,所以在此之前,需要对GradientX做一个调整,将等于0的调整为一个较小的值。由于atan返回的范围是-pi/2到pi/2,所以需要增加一个pi/2作为调整,然后将弧度转化为角度,而下面的atan2函数则适用于当角度为360的时候,实现功能和上面的atan很相似。
function [bm bv] = anna_BinMatrix(A,E,G,angle,bin)
[contorns,n] = bwlabel(E);
X = size(E,2);
Y = size(E,1);
bm = zeros(Y,X);
bv = zeros(Y,X);
nAngle = angle/bin;
for i=1:n
[posY,posX] = find(contorns==i);
for j=1:size(posY,1)
pos_x = posX(j,1);
pos_y = posY(j,1);
b = ceil(A(pos_y,pos_x)/nAngle);
if b==0, bin= 1; end
if G(pos_y,pos_x)>0
bm(pos_y,pos_x) = b;
bv(pos_y,pos_x) = G(pos_y,pos_x);
end
end
end
bwlabel函数实现将连通域关联起来,并且将所有的连通域进行计数存放到第二个返回值中,第一个返回值是一个和图像一样大小的矩阵,这个矩阵中的第一个连通域填充1,第二个连通域填充2,以此类推。然后利用角度计算每一个直方图中的bin的跨度。利用之前计算出来的角度,得出相应位置上的角度属于直方图的哪一个bin,并且在相应的位置存放角度值。
bh_roi = bh(roi(1,1):roi(2,1),roi(3,1):roi(4,1));
bv_roi = bv(roi(1,1):roi(2,1),roi(3,1):roi(4,1));
p = anna_phogDescriptor(bh_roi,bv_roi,L,bin);
function p = anna_PhogDescriptor(bh,bv,L,bin)
p = [];
%level 0
for b=1:bin
ind = bh==b;
p = [p;sum(bv(ind))];
end
cella = 1;
for l=1:L
x = fix(size(bh,2)/(2^l));
y = fix(size(bh,1)/(2^l));
xx=0;
yy=0;
while xx+x<=size(bh,2)
while yy +y <=size(bh,1)
bh_cella = [];
bv_cella = [];
bh_cella = bh(yy+1:yy+y,xx+1:xx+x);
bv_cella = bv(yy+1:yy+y,xx+1:xx+x);
for b=1:bin
ind = bh_cella==b;
p = [p;sum(bv_cella(ind))];
end
yy = yy+y;
end
cella = cella+1;
yy = 0;
xx = xx+x;
end
end
if sum(p)~=0
p = p/sum(p);
end
经过之前的代码已经生成了梯度方向了,只需要将这些梯度方向经过统计之后就可以得到一个HOG了。上面的第一个循环就是根据bin的个数统计第一层的直方图。而第二个循环则是根据图像金字塔得到局部的HOG特征,最后进行归一化。
上面是一个很简单的HOG的实现,当然和DPM中的HOG特征不可同日而语,不过对于理解HOG的计算以及生成还是很有帮助的。完整的代码可以到我的资源也下载