MATLAB代码实现HOG方向梯度直方图特征提取

第一步:原始图像预处理:灰度图、伽马矫正

 导入图片后,转化为灰度图,对图像进行滤波、矫正。滤波、矫正使用的方法、参数根据图片的情况进行选择。

第二步:计算各像素的总梯度、梯度方向

使用[-1,0,1]作x方向的算子;[-1;0;1]作y方向的算子;x方向梯度存入f1(i,j);y方向梯度存入f2(i,j)。计算总梯度与梯度方向。

总梯度:rho(i,j)=((f1(i,j))^2+(f2(i,j)^2))^0.5

梯度方向:theta(i,j)=(atan(f2(i,j)/f1(i,j)))*180/3.14

matlab图像左向右为正,上向下为正,计算完梯度方向后需要将其转换为平面直角坐标系中的角度以y轴正方向为0°,顺时针旋转,角度由0°变化至360°。便于后续统计方向梯度直方图。

matlab中图像坐标与角度如下图所示:

为了方便后续不同角度区间的统计,可将上图的角度转换为下图的坐标,本例子中将360°划分为6个区间,间隔为60°,统计6个区间的的方向梯度直方图(角度划分方法、划分间隔可根据需要做不同选择): 

第三步:设置1个cell为cellx×celly的图片区域,该例中取10×10个像素,统计10×10=100个像素6个方向上的直方图特征。

本例子图像大小为300×400像素,因此需要统计(300/10)×(400/10)=30×40=1200个cell,每个cell中包含100个像素点,每个点都包含总梯度、梯度方向的信息,将这100个像素点根据梯度方向,划分为6个组,统计每个组的总梯度累加值(统计完后选用合适的方法对每个cell的6个方向上的总梯度累加值做归一化处理,得到1个cell的特征值。或者统计时不做简单累加,采用插值方法进行各方向的累加,得到1个cell的特征值)。

(cell的大小可根据实际需要做不同选择。)

第四步:设置1个block为n×n个cell,该例中取1个block为3×3个cell,因每个cell中包含6个方向的直方图特征,则每个block包含9×6=54个特征。

逐行、逐列取block,每个cell会多次进入不同的block进行统计。本例子中1个block由3×3个cell组成,一共可取得(30-2)×(40-2)=1064个block,每个cell包含6个特征值,因此1个block中包含9×6=54个特征值,最终产生1064×54=57456个特征值。(每个block中的54个特征值可选用合适的方法进行归一化处理)。

matlab实现程序如下:

F=imread('D:\Desktop\matlab\13.png');

%第一步:原始图像预处理:灰度图、伽马矫正。
F=rgb2gray(F);
subplot(2,3,1),imshow(F);title('灰度图');

f=double(F);
[row,col]=size(f);
for i=1:row
    for j=1:col
         f(i,j)=(f(i,j))^0.5;                     %伽马矫正Gamma=1/2,
    end
end
subplot(2,3,2),imshow(f,[]);title('伽马矫正');

%第二步:计算各像素的总梯度、梯度方向
f1=zeros(row,col);           %f1用于存x方向梯度
f2=zeros(row,col);           %f2用于存y方向梯度
rho=zeros(row,col);          %rho用于存总方向梯度
theta=zeros(row,col);        %theta用于存梯度方向
gx=[-1,0,1];                 %计算x方向的算子,matlab图像左向右为正
gy=[-1;0;1];                 %计算x方向的算子,matlab图像上向下为正
for i=2:row-1
    for j=2:col-1
        fx=[f(i,j-1),f(i,j),f(i,j+1)];
        fy=[f(i-1,j);f(i,j);f(i+1,j)];
        Gx=gx.*fx;
        Gy=gy.*fy;
        f1(i,j)=sum(Gx,"all");                    %计算x方向梯度
        f2(i,j)=sum(Gy,"all");                    %计算y方向梯度
        rho(i,j)=((f1(i,j))^2+(f1(i,j)^2))^0.5;    %计算总梯度
        %下面计算梯度方向,matlab图像左向右为正,上向下为正,使用f2(i,j)/f1(i,j)计算方向后需要将其转换为平面直角坐标系中的角度
        %以y轴正方向为0°,顺时针旋转,角度由0°变化至360°。便于统计方向梯度直方图
        if f1(i,j)>0 && f2(i,j)<0                                          
             theta(i,j)=(atan(f2(i,j)/f1(i,j)))*180/3.14+90;                  %x方向梯度>0,y方向梯度<0,平面直角坐标系中的第一象限,转换为0°~90°范围
        end
        if f1(i,j)>0 && f2(i,j)>0 
             theta(i,j)=(atan(f2(i,j)/f1(i,j)))*180/3.14+90;                  %x方向梯度>0,y方向梯度>0,平面直角坐标系中的第四象限,转换为90°~180°范围
        end
        if f1(i,j)<0 && f2(i,j)>0 
             theta(i,j)=(atan(f2(i,j)/f1(i,j)))*180/3.14+270;                 %x方向梯度<0,y方向梯度>0,平面直角坐标系中的第三象限,转换为180°~270°范围
        end
        if f1(i,j)<0 && f2(i,j)<0 
             theta(i,j)=(atan(f2(i,j)/f1(i,j)))*180/3.14+270;                 %x方向梯度<0,y方向梯度<0,平面直角坐标系中的第二象限,转换为270°~360°范围
        end
        if f1(i,j)==0 && f2(i,j)<0 
             theta(i,j)=0.00001;                                              %x方向梯度=0,y方向梯度<0,平面直角坐标系中的y轴正方向,转换为0°,为了和无梯度方向(f2(i,j)、f1(i,j)均为0的情况)区别开,设该方向为极小的正值
        end
        if f1(i,j)>0 && f2(i,j)==0 
             theta(i,j)=90;                                                   %x方向梯度>0,y方向梯度=0,平面直角坐标系中的x轴正方向,转换为90°
        end
        if f1(i,j)==0 && f2(i,j)>0 
             theta(i,j)=180;                                                  %x方向梯度=0,y方向梯度>0,平面直角坐标系中的y轴负方向,转换为180°
        end
        if f1(i,j)<0 && f2(i,j)==0 
             theta(i,j)=270;                                                  %x方向梯度<0,y方向梯度=0,平面直角坐标系中的x轴负方向,转换为270°
        end
        if f1(i,j)==0 && f2(i,j)==0 
             theta(i,j)=0;                                                    %f2(i,j)、f1(i,j)均为0,无梯度方向
        end
     end
end
subplot(2,3,3),imshow(f1,[]);title('x方向梯度');
subplot(2,3,4),imshow(f2,[]);title('y方向梯度');
subplot(2,3,5),imshow(rho,[]);title('总梯度');
subplot(2,3,6),imshow(theta,[]);title('梯度方向');

%第三步:设置1个cell为cellx×celly的图片区域,该例中取10×10个像素,统计10×10=100个像素6个方向上的直方图特征.
       % 需要统计(300/10)×(400/10)=30×40=1200个cell
theta_num=6;                    %设置统计6个方向的直方图特征(也可设置为统计9个或其他n个方向)
cellx=10;                       %设置1个cell有几行像素               
celly=10;                       %设置1个cell有几列像素
theta_size=360/theta_num;       %统计6个方向上的直方图,每个方向60°

cell_rho=zeros(cellx,celly);    %创建cell_rho矩阵,用来放1个cell中各像素的总梯度
cell_theta=zeros(cellx,celly);  %创建cell_theta矩阵,用来放1个cell中各像素的梯度方向
histogram=zeros(1,theta_num);   %创建histogram数组,用来放1个cell中的6个统计直方图特征
Cell=cell(row/cellx,col/celly); %定义元胞数组大小,用于存放所有cell中的6个直方图特征

for x=1:row/cellx                                                          %需要确定图片尺寸的行数可被整除,即可得到图片可分为几行cell
    for y=1:col/celly                                                      %需要确定图片尺寸的列数可被整除,即可得到图片可分为几列cell
         cell_rho=rho(10*x-9:10*x,10*y-9:10*y);                            
         cell_theta=theta(10*x-9:10*x,10*y-9:10*y);                        %把每个cell中的总梯度、梯度方向放入矩阵cell_rho、cell_theta中,便于后面统计
                          
             for i=1:cellx
                  for j=1:celly
                      if cell_theta(i,j)>0
                      histogram(ceil(cell_theta(i,j)/theta_size))=histogram(ceil(cell_theta(i,j)/theta_size))+cell_rho(i,j); %统计10×10像素中各6个方向的直方图特征,放入histogram这个1×6的数组中
                      end
                  end
             end
             s=sum(histogram,"all");
             for h=1:theta_num
                 histogram(h)=histogram(h)/s;     %归一化
             end
             figure(2),plot(histogram);
             Cell{x,y}=histogram;                 %将归一化后的histogram(1×6)放入元胞数组中
             for h=1:theta_num
                 histogram(h)=0;                  %将histogram各元素置0,为下一个cell统计做好准备
             end
             
             histogram=zeros(1,6);
    end
end

%第四步:设置1个block为n×n个cell,该例中取1个block为3×3个cell,因每个cell中包含6个方向的直方图特征,则每个block包含9×6=54个特征.
       % 逐行、逐列取block,一共可取得(30-2)×(40-2)=1064个block,最终产生1064×6=6384个特征值
n=3;
[v,w]=size(Cell);
feature=cell(1,(v-(n-1))*(w-(n-1)));

for xx=1:v-2
    for yy=1:w-2
        feature{(xx-1)*(w-2)+yy}=[Cell{xx:xx+(n-1),yy:yy+(n-1)}];          %将3×3个cell的特征向量合并放入1个block中,作为1个block的特征
    end
end
%feature包含整图1064个block中所有的特征值

l=length(feature);
fmesh=[];
for i=1:l
    fmesh=[fmesh;feature{i}(:)'];            %用于画图
end
figure(3);
mesh(fmesh);

下图为完成第一步、第二步的结果:

下图为完成第三步,其中1个cell的6个方向的特征值:

下图为各block特征值的可视化结果,即本图片提取得到的HOG特征值:

需要能够识别图片为汽车,则需要其他的训练方法与检测方法,本例子仅简单介绍提取HOG特征值的流程,其中有多处需要根据实际情况选择参数、方法。

本例子参考了以下内容:

HOG特征提取原理_沈子恒的博客-CSDN博客

MATLAB HOG方向梯度直方图 - 一杯清酒邀明月 - 博客园 (cnblogs.com)

【人脸识别】基于matlab HOG特征提取人脸识别【含Matlab源码 641期】_matlab提取hog特征_海神之光的博客-CSDN博客

猜你喜欢

转载自blog.csdn.net/weixin_56832351/article/details/129439271