基于支持向量机的图像分类(下篇:MATLAB实现)

摘要:本文通过图文详细介绍如何利用支持向量机对图像进行分类,经过上篇文章对原理的介绍,这里介绍利用MATLAB编程实现。更多相关资源详解也可参考博主最新博文基于支持向量机的手写数字识别详解(MATLAB GUI代码,提供手写板)。本文后续章节将介绍的主要部分有:

  • 图片数据集整理
  • 特征提取
  • SVM训练与测试
  • 分类结果评价
  • 结果显示

点我下载:SVM图像分类的MATLAB完整程序及图片集文件

博主相关博文参考:基于支持向量机的图像分类系统(MATLAB GUI界面版)


1. 前言

机器学习是人工智能研究发展到一定阶段的必然产物。二十世纪八十年代是机器学习成为一个独立学科的学科领域、各种机器学习技术百花绽放的时期。支持向量机于1995年正式发表[Cortes and Vapnik,1995],由于在文本分类任务中的卓越性能[Joachims,1998],很快成为机器学习的主流技术,并直接掀起了“统计学习”(statistical learning)在2000年前后的高潮。——《机器学习》 周志华

2010年前后,随着计算能力的迅猛提升和大数据的涌现,神经网络研究在“深度学习”的名义下又重新崛起,并迎来又一次发展高潮。近年研究SVM的论文少了很多,SVM的风头很多时候确实已被强势崛起的深度学习浪潮所淹没,95年的SVM比我们年龄还大,有点仿佛英雄迟暮的感觉。不过在我看来,实现简单而且非常强大的分类算法SVM仍然有其研究价值,与神经网络相比SVM亦有过人之处,如特征维数多于样本数的情况,而小样本学习至今仍是深度学习的一大难题。

当浅层神经网络效果不佳时,人们将目光转向支持向量机,而支持向量机亦不负众望,以不错的成绩让人们对机器学习重拾信心。感谢支持向量机,感谢在神经网络几经起落的时候,支持向量机继往开来、自成一脉,填补了机器学习的一段空窗期,让这条曲折向上的研究之路绵延至今迎来了现在人工智能百花齐放的时代!

接下来就通过简单的图片分类问题,通过MATLAB程序理解认识一下这一简单而强大的分类算法——支持向量机.


2. 图片数据集整理

首先需要准备好分类的数据集,数据的整理是机器学习中的重要一环。这里我们自行整理一个用于分类的图片集,图片集有四类图片,分别为车、猫、花、鱼。从百度上下载这四种图片,并分别存放在四个文件夹中,如下图所示

四类图片每类分别下载100张左右的图片,这四百张图片作为分类的数据集,以7:3的比例将其分为训练图片集和测试图片集,分别放到picturestestPictures两个文件夹中。这两个文件夹下同上图一样都有car、cat、flw、fsh四个文件夹,值得注意的是测试样本的图片应可能不出现在训练集图片库中。做好以上工作,用于分类的图片集就准备完毕了。

(当然用于分类的图片集常用的是cafir10图片集,这个数据集是写论文或研究时普遍用到的,可能会在后面的文章中介绍其用法,这里就暂时不使用cafir了。)

为了便于后面的特征提取等对每张图片进行的操作,这里在程序中有必要将图片文件的存储位置、数量、类别等信息整理到一个数据结构中,新建一个m文件,程序代码如下

dir=('D:\pictures');
testdir=('D:\testPictures\test');
trainingSet = imageSet(dir,'recursive');
testSet = imageSet(testdir,'recursive');

以上代码中用到imageSet( )函数是一个图片集整理的函数(MATLAB R2016b及以上版本支持),返回的是dir文件路径下文件夹内的文件信息。例如得到的trainingSet为一个1*4的imageSet变量,每个imageSet变量由Description、ImageLocation、Count三个属性组成,分别代表对子文件的描述、文件存储位置和图片数量。如下图所示是testSet(1)内部情况


3. 主要步骤

和深度学习的算法相比,传统的机器学习在进行图片分类时输入的不是原始图片而是先进行一个特征提取的步骤。在上篇中已经介绍了特征提取的相关内容,这里用的是方向梯度直方图(HOG)以及灰度共生矩阵(GLCM)。

3.1 GLCM提取

MATLAB中灰度共生矩阵的提取可以调用graycomatrix( )函数,不过这里为了取不同方向(0、45、90、135度)的灰度共生矩阵,通过循环计算各个方向的灰度共生矩阵并进行归一化处理(计算对比度、逆差距、熵、自相关),然后取平均值和方差作为最终提取的特征。

新建一个m文件并命名为getGLCMFeatures,输入以下代码

function [features] = getGLCMFeatures(image)
features_all  = [];
for i = 1:10
    glcm = graycomatrix(image, 'Offset', [0,i]);
    stats = graycoprops(glcm);
    
    glcm45 = graycomatrix(image, 'Offset', [-i,i]);
    stats45 = graycoprops(glcm45);
    
    glcm90 = graycomatrix(image, 'Offset', [-i,0]);
    stats90 = graycoprops(glcm90);
    
    glcm135 = graycomatrix(image, 'Offset', [-i,-i]);
    stats135 = graycoprops(glcm135);
    
    stats7x4 = [stats.Contrast stats.Correlation stats.Energy stats.Homogeneity;
        stats45.Contrast stats45.Correlation stats45.Energy stats45.Homogeneity;
        stats90.Contrast stats90.Correlation stats90.Energy stats90.Homogeneity;
        stats135.Contrast stats135.Correlation stats135.Energy stats135.Homogeneity];
    features_all = [features_all mean(stats7x4,1) std(stats7x4,0,1)];
end
features = features_all;

新建的getGLCMFeatures函数输入为彩色图像转换后的灰度图像矩阵,输出为提取后的灰度共生矩阵特征。

3.2 合并特征

自己编写一个提取特征的函数命名为extractFeature,这个函数输入为整理过的训练集和测试集,输出为训练集的特征、标签和测试集的特征、标签。这个函数的功能是将HOG特征和前面提取的GLCM特征合并。

代码第2到13行是为了确定每张图片提取特征后得到的矩阵大小,以方便后面的操作同时也是为了预分配空间以提高代码效率。首先取第一张图片进行灰度化以及阈值分割,将图片大小调整在256*256的范围(统一大小)分别进行HOG和GLCM的特征提取,分别得到两种特征向量,取两个向量的长度之和就是一张图片特征提取后的总长度了。

function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
%% 确定特征向量尺寸
img = read(trainingSet(1), 1);
%转化为灰度图像
img=rgb2gray(img);
%转化为2值图像
lvl = graythresh(img);
img = im2bw(img, lvl);
img=imresize(img,[256 256]);
cellSize = [4 4];
[hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
glcm_feature = getGLCMFeatures(img);
SizeOfFeature = length(hog_feature)+ length(glcm_feature);

%% 构建训练样本特征向量和训练样本标签
trainingFeatures = [];
trainingLabels   = [];
for digit = 1:numel(trainingSet)       
    numImages = trainingSet(digit).Count;
    features  = zeros(numImages, SizeOfFeature, 'single');%初始化特征向量
    % 遍历每张图片
    for i = 1:numImages
        img = read(trainingSet(digit), i);% 取出第i张图片
        
        img=rgb2gray(img);                % 转化为灰度图像
        glcm_feature = getGLCMFeatures(img);  % 提取GLCM特征
       
        lvl = graythresh(img);            % 阈值化
        img = im2bw(img, lvl);            % 转化为2值图像
        img=imresize(img,[256 256]);
        % 提取HOG特征
        [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
        % 合并两个特征
        features(i, :) = [hog_feature glcm_feature];
    end
    % 使用图像描述作为训练标签
    labels = repmat(trainingSet(digit).Description, numImages, 1);  
    % 逐个添加每张训练图片的特征和标签
    trainingFeatures = [trainingFeatures; features];
    trainingLabels   = [trainingLabels; labels];       
end


%% 提取测试图片集的特征向量
testFeatures = [];
testLabels   = [];
for digit = 1:numel(testSet)
           
    numImages = testSet(digit).Count;
    %初始化特征向量
    features  = zeros(numImages, SizeOfFeature, 'single');
    
    for i = 1:numImages
        
        img = read(testSet(digit), i);
        %转化为灰度图像
        img=rgb2gray(img);
        glcm_feature = getGLCMFeatures(img);
        %转化为2值图像
        lvl = graythresh(img);
        img = im2bw(img, lvl);
        img=imresize(img,[256 256]);
        [hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',cellSize);
        features(i, :) = [hog_4x4 glcm_feature];
    end
    
    % 使用图像描述作为训练标签
    labels = repmat(testSet(digit).Description, numImages, 1);
        
    testFeatures = [testFeatures; features];
    testLabels=[testLabels; labels];
        
end
end

代码18-41行是构建训练样本特征向量和训练样本标签,与前面步骤相似,只不过现在是遍历训练集每一张图片,对其进行灰度化、阈值化、调整大小,然后进行特征提取,将HOG特征和GLCM特征合并成一个向量作为特征矩阵的一行即一张图片的特征向量。样本的标签构建则将每张图片所处的文件夹的名字作为该图片的标签,并与特征向量顺序相对应。

第47-73行是构建测试样本特征向量和训练样本标签,这里将图片集换成了测试集,而步骤与训练集是一致的。

3.3 SVM训练与测试

调用前面的特征提取函数得到训练和测试用的特征向量与对应的标签,便可以进行SVM的训练和测试。MATLAB自带的训练svm函数可以用fitcecoc函数,测试可以用predict函数预测结果,训练和测试的代码如下

% 训练一个svm分类器
% fitcecoc 使用1对1的方案
classifier = fitcecoc(trainingFeatures, trainingLabels);
save classifier.mat classifier;

% 使用测试图像的特征向量预测样本标签
predictedLabels = predict(classifier, testFeatures);

代码中classifier为训练得到的SVM分类器,利用该分类器以及测试集特征向量预测测试集的标签predictLabels。后面可以将predictLabels与实际的测试标签进行对比即可评估分类好坏。

3.4 分类结果评价

在上一篇文章中提到过了,为了评价分类的好坏可以通过混淆矩阵,通过计算混淆矩阵对角线上的值占每行总数的比值得出分类正确率,其实现代码如下

%% 评估分类器
% 使用没有标签的图像数据进行测试,生成一个混淆矩阵表明分类效果
confMat=confusionmat(testLabels, predictedLabels)
accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+...
    confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4

其结果如下图所示

3.5 结果显示

尽管以上代码能得到分类正确率,但我们希望更直观的看到输入一张图片后SVM分类器的分类结果,这里编写一个函数通过图形窗口显示预测结果。新建一个m文件命名为Predict,输入如下代码

function [] = Predict(imageurl)
load classifier.mat;
figure;
img = imread(imageurl);
imshow(img);

%提取图像的特征向量
%转化为灰度图像
img=rgb2gray(img);
glcm_feature = getGLCMFeatures(img);
%转化为2值图像
lvl = graythresh(img);
img = im2bw(img, lvl);

% imshow(img);
% figure
img=imresize(img,[256 256]);
[hog_4x4, ~] = extractHOGFeatures(img,'CellSize',[4 4]);
testFeature = [hog_4x4 glcm_feature];


% 使用测试图像的特征向量预测样本标签
predictedLabel = predict(classifier, testFeature);

str = ['分类结果:' predictedLabel];
dim = [0.25 0.0004 0.2 0.2];
annotation('textbox', dim, 'string', str, 'fontsize', 20, 'color', 'g','edgecolor', 'none');

函数输入为图片的存储路径,调用函数则会通过图形窗口显示图片及分类结果,如在命令窗口输入如下代码

Predict('D:\testPictures\test\car\car9.jpg');

输出结果如下图


4. 完整代码

为了方便使用这里贴出完整代码

主函数:

clear;
dir=('D:\pictures');
testdir=('D:\testPictures\test');
trainingSet = imageSet(dir,'recursive');
testSet = imageSet(testdir,'recursive');

[trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet);
%% 
%训练一个svm分类器
%fitcecoc 使用1对1的方案
classifier = fitcecoc(trainingFeatures, trainingLabels);
save classifier.mat classifier;

% 使用测试图像的特征向量预测样本标签
predictedLabels = predict(classifier, testFeatures);

%% 评估分类器
%使用没有标签的图像数据进行测试,生成一个混淆矩阵表明分类效果
confMat=confusionmat(testLabels, predictedLabels)
accuracy=(confMat(1,1)/sum(confMat(1,:))+confMat(2,2)/sum(confMat(2,:))+...
    confMat(3,3)/sum(confMat(3,:))+confMat(4,4)/sum(confMat(4,:)))/4

Predict('D:\testPictures\test\car\car9.jpg');

getGLCMFeatures.m:

function [features] = getGLCMFeatures(image)
features_all  = [];
for i = 1:10
    glcm = graycomatrix(image, 'Offset', [0,i]);
    stats = graycoprops(glcm);
    
    glcm45 = graycomatrix(image, 'Offset', [-i,i]);
    stats45 = graycoprops(glcm45);
    
    glcm90 = graycomatrix(image, 'Offset', [-i,0]);
    stats90 = graycoprops(glcm90);
    
    glcm135 = graycomatrix(image, 'Offset', [-i,-i]);
    stats135 = graycoprops(glcm135);
    
    stats7x4 = [stats.Contrast stats.Correlation stats.Energy stats.Homogeneity;
        stats45.Contrast stats45.Correlation stats45.Energy stats45.Homogeneity;
        stats90.Contrast stats90.Correlation stats90.Energy stats90.Homogeneity;
        stats135.Contrast stats135.Correlation stats135.Energy stats135.Homogeneity];
    features_all = [features_all mean(stats7x4,1) std(stats7x4,0,1)];
end
features = features_all;

extractFeature.m:

function [trainingFeatures,trainingLabels,testFeatures,testLabels]=extractFeature(trainingSet,testSet)
%% 确定特征向量尺寸
img = read(trainingSet(1), 1);
%转化为灰度图像
img=rgb2gray(img);
%转化为2值图像
lvl = graythresh(img);
img = im2bw(img, lvl);
img=imresize(img,[256 256]);
cellSize = [4 4];
[hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
glcm_feature = getGLCMFeatures(img);
SizeOfFeature = length(hog_feature)+ length(glcm_feature);

%% 构建训练样本特征向量和训练样本标签
trainingFeatures = [];
trainingLabels   = [];
for digit = 1:numel(trainingSet)       
    numImages = trainingSet(digit).Count;
    features  = zeros(numImages, SizeOfFeature, 'single');%初始化特征向量
    % 遍历每张图片
    for i = 1:numImages
        img = read(trainingSet(digit), i);% 取出第i张图片
        
        img=rgb2gray(img);                % 转化为灰度图像
        glcm_feature = getGLCMFeatures(img);  % 提取GLCM特征
       
        lvl = graythresh(img);            % 阈值化
        img = im2bw(img, lvl);            % 转化为2值图像
        img=imresize(img,[256 256]);
        % 提取HOG特征
        [hog_feature, vis_hog] = extractHOGFeatures(img,'CellSize',cellSize);
        % 合并两个特征
        features(i, :) = [hog_feature glcm_feature];
    end
    % 使用图像描述作为训练标签
    labels = repmat(trainingSet(digit).Description, numImages, 1);  
    % 逐个添加每张训练图片的特征和标签
    trainingFeatures = [trainingFeatures; features];
    trainingLabels   = [trainingLabels; labels];       
end


%% 提取测试图片集的特征向量
testFeatures = [];
testLabels   = [];
for digit = 1:numel(testSet)
           
    numImages = testSet(digit).Count;
    %初始化特征向量
    features  = zeros(numImages, SizeOfFeature, 'single');
    
    for i = 1:numImages
        
        img = read(testSet(digit), i);
        %转化为灰度图像
        img=rgb2gray(img);
        glcm_feature = getGLCMFeatures(img);
        %转化为2值图像
        lvl = graythresh(img);
        img = im2bw(img, lvl);
        img=imresize(img,[256 256]);
        [hog_4x4, vis4x4] = extractHOGFeatures(img,'CellSize',cellSize);
        features(i, :) = [hog_4x4 glcm_feature];
    end
    
    % 使用图像描述作为训练标签
    labels = repmat(testSet(digit).Description, numImages, 1);
        
    testFeatures = [testFeatures; features];
    testLabels=[testLabels; labels];
        
end
end

Predict.m:

function [] = Predict(imageurl)
load classifier.mat;
figure;
img = imread(imageurl);
imshow(img);

%提取图像的特征向量
%转化为灰度图像
img=rgb2gray(img);
glcm_feature = getGLCMFeatures(img);
%转化为2值图像
lvl = graythresh(img);
img = im2bw(img, lvl);

% imshow(img);
% figure
img=imresize(img,[256 256]);
[hog_4x4, ~] = extractHOGFeatures(img,'CellSize',[4 4]);
testFeature = [hog_4x4 glcm_feature];


% 使用测试图像的特征向量预测样本标签
predictedLabel = predict(classifier, testFeature);

str = ['分类结果:' predictedLabel];
dim = [0.25 0.0004 0.2 0.2];
annotation('textbox', dim, 'string', str, 'fontsize', 20, 'color', 'g','edgecolor', 'none');

5. 结束语

本博文的完整MATLAB程序文件与图片集文件已经上传,下载即可运行(注意根据实际修改程序中的图片路径哦)下载地址如下

点我下载:SVM的图像分类MATLAB完整程序及图片集文件

更多相关资源详解也可参考博主最新博文基于支持向量机的手写数字识别详解(MATLAB GUI代码,提供手写板)

公众号获取
    本人微信公众号已创建,扫描以下二维码并关注公众号“AI技术研究与分享”,后台回复“SV20180411”即可获取全部资源文件信息。

由于编者能力有限,代码即使经过了多次校对,也难免会有疏漏之处。希望您能热心指出其中的错误,以便下次修改时能以一个更完美更严谨的样子,呈现在大家面前。同时如果有更好的实现方法也请您不吝赐教。

posted @ 2022-10-06 23:49  思绪无限  阅读(488)  评论(0编辑  收藏  举报