本文主要是根据分析一份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 endbwlabel函数实现将连通域关联起来,并且将所有的连通域进行计数存放到第二个返回值中,第一个返回值是一个和图像一样大小的矩阵,这个矩阵中的第一个连通域填充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的计算以及生成还是很有帮助的。完整的代码可以到我的资源也下载