尧图建网站 尧图建网站 YAOTU WEB BUILD 免费咨询
ARTICLE DETAIL

资讯详情

深耕网站建设与建站编程的一线实战洞察。

MATLAB实现HOG特征+SVM目标识别完整攻略

MATLAB实现HOG特征+SVM目标识别完整攻略 简介本资源是一套面向本硕博教研学习者的HOG特征提取与多分类SVM目标识别算法MATLAB实现方案适用于计算机视觉、模式识别等方向的算法原理理解与工程实践训练。压缩包共2503个文件主体为2500张PNG格式样本图像用于训练/测试数据集辅以1个AVI操作录像视频完整演示仿真流程、1个M文件主运行脚本Runme.m及1个TXT说明文档整体仅1.8MB轻量易部署。已有517人下载学习适配MATLAB 2021a及以上版本强调规范运行路径与入口文件调用逻辑避免子函数误执行。资源提供从图像预处理、HOG特征向量化、多类SVM模型构建到分类结果可视化的全流程代码实现并配套高清操作录屏清晰展示参数设置、变量调试与结果分析过程显著降低初学者在特征工程与分类器集成环节的理解门槛。 当年我拿着课程设计题目目标识别到处找方案的时候实验室的机器根本没有独显跑一版像样的深度学习模型要等到天荒地老。后来在师兄指点下换成了HOG特征加SVM不到半天就跑出了能上台演示的结果。这个组合在MATLAB里做目标识别其实真的是小数据、无GPU环境下性价比极高的路线HOG负责把图像变成有区分度的特征向量SVM负责把这些向量分门别类。代码量可控训练几分钟完成解释性还强。我把从特征原理、多分类SVM策略到MATLAB完整实现、调参再到录制一份合格仿真操作视频的完整经验整理出来给正在做课程设计、毕业设计或者只是想快速验证一个小型视觉识别系统的人参考。1. 为什么传统HOG加上SVM在目标识别里仍然值得用1.1 深度学习的压迫下传统方法还有没有位置先说结论有而且在小样本场景下作用很大。做目标识别时很多人第一反应就是上CNN、上预训练模型。但真实情况是课程设计和不少横向课题的数据量并没有那么充裕每个类别只有几十到几百张图很常见。这种量级下CNN极其容易过拟合训练集准确率98%一到测试集直接掉到70%以下调参又非常折磨。HOG加SVM的优势在于特征维度可控、训练速度快、不需要独立显卡几分钟就能出结果。更关键的是它的决策过程是可解释的——你可以明确指出是哪个区域、哪个方向梯度分布让模型做出了判断。这在答辩时非常加分老师问你的系统为什么能识别你可以从特征和分类器两个层面讲清楚而不是笼统地说神经网络自动学习。1.2 HOG和SVM分工的直觉理解HOG这个词全称是Histogram of Oriented Gradients方向梯度直方图。它的核心思想非常朴素把图像划分成小块统计每个小块里边缘轮廓的方向分布。你可以把它理解成一个记忆力很强的人虽然不认识猫这个概念但他能记住猫的边缘方向分布规律哪里横向、哪里纵向、哪里是斜的他都门清。SVM则是后面的决策者。它拿到HOG提取出的特征向量之后会寻找一个能把不同类别分得最开的分界超平面。HOG负责描述SVM负责分类两者分工明确。这个组合最早在行人检测上取得了巨大成功后面被广泛迁移到各种目标识别任务上。1.3 这套组合适合处理哪些目标识别任务从我实际接触的情况看HOG加SVM适合的目标通常有几个共同点目标在图像中相对居中不需要特别复杂的空间推理类别之间在形状轮廓上有明显差异图像会提前被缩放裁剪到统一尺寸。典型场景包括手写数字和英文字母识别、简单交通标志分类、车标识别、水果和蔬菜分类、工件表面缺陷分类、农作物叶片病害识别。我在实际项目中还用它做过变电站设备仪表读数识别效果也稳定。如果目标是做复杂场景下的目标检测比如行人要从街景里框出来那需要配合滑动窗口和难例挖掘工程量会大不少但核心特征仍然可以是HOG。2. HOG特征提取图像是怎么变成直方图向量的2.1 核心逻辑梯度方向直方图HOG特征提取的起点是计算图像的梯度。对灰度图像中每个像素分别计算水平方向和垂直方向的梯度值然后合成梯度的幅值和方向。计算方式如下% 用Sobel算子近似计算梯度 [Gx, Gy] imgradientxy(img); [Gmag, Gdir] imgradient(Gx, Gy);为什么要用梯度而不是原始像素值因为梯度对光照变化不太敏感。比如一块区域整体变亮或变暗像素值整体抬升但相邻像素之间的差值也就是梯度不会发生剧烈变化。目标识别最怕的就是同一种目标在不同光照下表现差异太大梯度这个特性正好帮助系统摆脱光照干扰。方向直方图是HOG的核心。在每个小的图像块里把0到180度无符号梯度或0到360度有符号梯度均匀分成若干个方向区间也就是bin然后统计每个区间内有多少像素。像素对直方图的贡献不是简单加1而是按梯度幅值加权。幅值大的边缘贡献大幅值小的平坦区域贡献小这样直方图就能反映边缘的强度。2.2 cell、block与重叠的数学关系HOG特征不是整张图做一个直方图那样会丢失太多空间信息。它把图像划分成一个个小的cell比如8x8像素的cell每个cell单独统计直方图。然后为了消除光照和对比度变化的影响又把相邻的2x2个cell组合成一个block在block内部对特征向量做归一化。block还有一个关键设计重叠。相邻block之间会有重叠区域也就是说同一个cell的特征会同时出现在多个block中。我的理解是这种冗余是故意的。虽然特征维度变高了但某个边缘方向的统计不会因为边界划分的微小偏移而完全丢失鲁棒性显著提升。举一个具体的计算例子。假设输入图像统一为高128像素、宽64像素cell尺寸取8x8像素。这样图像在高度方向被分成16个cell宽度方向被分成8个cell。block尺寸是2x2个cellblock的移动步长是1个cell因此block在高度方向有16减1等于15个位置宽度方向有8减1等于7个位置总block数为15乘7等于105个。每个block包含4个cell每个cell的直方图是9个bin所以每个block的特征维度是36。整张图像的HOG特征总维度就是105乘以36等于3780维。2.3 HOG参数对特征维度的影响MAC MATLAB中直接调用extractHOGFeatures就可以完成全部计算但参数选择直接影响特征维度和最终效果这张表是我调参时常用的对照表。参数常见取值对模型影响CellSize[8 8] 或 [16 16]cell越大特征维度越低但对细节位置越不敏感BlockSize[2 2]以cell为单位越大归一化范围越大局部细节越容易丢失BlockOverlap1个cell重叠越多鲁棒性越好但维度越高NumBins9 或 18方向分得越细区分能力越强但容易过拟合通常第一版就取默认值CellSize为[8 8]NumBins为9BlockSize为[2 2]BlockOverlap为1个cell跑通整个流程之后再去调整。不要一上来就追求高维度的精细特征3780维对于几百张图的训练集已经足够表达。3. 多分类SVM从是/否到选哪一类3.1 为什么SVM天生是二分类器原始SVM解决的是二分类问题给定正负两类样本找一个分类超平面让两类样本到这个平面的距离都尽可能大这样分类间隔最大泛化能力也就更好。当数据在高维空间线性不可分时SVM会通过核函数把数据映射到更高维空间在高维空间里寻找线性分类面。但在目标识别里要分的往往不止两类。比如要识别猫、狗、鸟三类动物SVM就需要组合策略。这也是很多初学者最容易困惑的地方为什么我调用fitcsvm训练得好好的来了三类数据就报错了因为fitcsvm本身就是二分类器多分类应该用fitcecoc。3.2 一对多与一对一的取舍多分类SVM最基础的两个策略是一对多One-vs-All和一对一One-vs-One。一对多的做法是有K个类别就训练K个二分类器第i个分类器把第i类作为正样本把其余所有类别作为负样本。缺点是负样本数量往往远大于正样本类别不平衡比较严重分类边界容易被多数类带偏。一对一的做法是对任意两个类别都训练一个二分类器总共需要K乘(K-1)除以2个分类器。预测时让所有分类器投票票数最多的类别胜出。优点是每个分类器面对的两类数据相对均衡缺点是类别多时分类器数量会明显上涨。比如10类数据一对一要训练45个模型训练和预测耗时都会增加。我实际使用时的经验是类别数小于10时优先选择一对一类别数很多且样本量偏少时可以试一对多。不过大多数情况下直接交给fitcecoc的默认策略即可没有必要在自己手动组合多个fitcsvm。3.3 MATLAB中fitcecoc的正确打开方式fitcecoc这个函数比手动组合多个二分类器省心得多。它把SVM学习器和多分类编码策略封装在一起底层会自动训练多个SVM并完成结果解码。% 定义SVM学习器模板 t templateSVM(KernelFunction, linear, Standardize, true); % 训练多分类SVM mdl fitcecoc(trainFeatures, trainLabels, ... Learners, t, ... Coding, onevsone);这里有几个容易踩的细节。第一Learners参数传入的是模板对象templateSVM不是字符串svm。第二Standardize设置为true让SVM在训练前对每个特征维度做标准化这一步对大尺度特征非常重要。HOG特征的各个维度数值范围差异不小不标准化的话数值大的维度会主导距离计算。第三Coding参数可以指定onevsone或onevsall也可以不指定用默认值。3.4 ECOC纠错输出编码的直觉理解fitcecoc里的ecoc指的是error-correcting output codes纠错输出编码。一对多和一对一其实都是它的特例。这种编码方式会给每个类别分配一个码字比如1010这样的二进制序列预测时计算测试样本和每个类别码字之间的距离取距离最近的作为最终类别。这样做的好处是即使某个二分类器判断错误只要其他分类器的结果能弥补最终类别仍然可能判断正确类似于信息传输里的纠错编码思想。理解这一点之后再看fitcecoc的各种参数就不会觉得抽象了。它就是在用一套统一的框架来管理多个二分类器。4. 数据准备模型上限在这里决定4.1 用imageDatastore组织数据集我见过不少人做MATLAB图像识别习惯用dir函数遍历文件夹自己拼路径然后一个循环一个循环读图。这样做不是不行只是代码冗长且容易出错。MATLAB自带的imageDatastore就是为这个场景设计的。数据集目录最好按照根目录下每个子文件夹一个类别的方式来组织dataset/ cat/ 001.jpg 002.jpg dog/ 001.jpg 002.jpg bird/ 001.jpg 002.jpg然后只需要一行代码就能把整个数据集加载进来标签自动从文件夹名提取imds imageDatastore(dataset, ... IncludeSubfolders, true, ... LabelSource, foldernames);用imageDatastore而不是手动读图有几个明显优势不用自己维护标签数组不会因为文件顺序错乱导致标签错位shuffle和splitEachLabel等函数可以直接调用训练测试划分非常方便。4.2 统一尺寸HOG特征的前提约束HOG特征维度与输入图像大小强相关。如果训练时图像是128x64测试时输入一张256x256的图特征维度对不上分类器根本无法预测。所以必须把所有图像统一resize到固定尺寸。这里有一个细节统一尺寸不是随便选一个框而是要考虑目标本身的宽高比。如果目标是行人这种上下细长的结构用高128宽64的尺寸就比较合适。如果目标是汽车这种横向结构可能用高64宽128更好。对于长方形的目标直接resize成正方形会让目标严重变形HOG统计出的方向分布也会失真。fixedSize [128 64]; img readimage(imds, i); if size(img, 3) 3 img rgb2gray(img); end img imresize(img, fixedSize);我习惯在resize前先转灰度。extractHOGFeatures其实也支持彩色图像它会自动转灰度处理但手动转换更明确也能避免一些边界情况带来的警告。4.3 类别不平衡问题当某类样本明显少于其他类时SVM的分类边界会被多数类带偏。比如猫有500张狗只有50张模型很容易把所有测试样本都判成猫。解决这个问题最直接的办法是随机过采样少数类把样本量补到和多数类接近。% 找出样本量最少的类别 tbl countEachLabel(imds); minCount min(tbl.Count); % 对少数类重复采样补足数量 for i 1:height(tbl) if tbl.Count(i) minCount idx find(imds.Labels tbl.Label(i)); extraIdx randsample(idx, minCount - tbl.Count(i), true); imds imageDatastore([imds.Files; imds.Files(extraIdx)], ... Labels, [imds.Labels; imds.Labels(extraIdx)]); end end这段代码思路很简单但要注意过采样会让同一个样本在训练集中重复出现多次如果重复次数太多模型会过拟合到重复样本上。补足数量而不是无限翻倍效果就好很多。4.4 训练集和测试集划分数据划分是模型评估的基础。通常按照8比2或者7比3的比例随机划分训练集和测试集。用splitEachLabel一步完成[trainImds, testImds] splitEachLabel(imds, 0.8, randomized);注意一定要加randomized否则splitEachLabel会按照文件顺序切分前面连续的一大段都是同一类划分就完全没有意义了。另外如果划分后某个类别的训练样本过少可以适当提高训练比例但对应测试集的评估效果也会打折扣。5. 完整的MATLAB实现和调参过程5.1 提取HOG特征的主程序下面这段是从训练集提取HOG特征并组装特征矩阵的完整代码。我写代码时习惯先拿一张图确定特征维度再用这个维度预分配矩阵避免在循环里反复动态扩展数组速度会快很多。% 加载数据集 imds imageDatastore(dataset, ... IncludeSubfolders, true, ... LabelSource, foldernames); % 划分训练集和测试集 [trainImds, testImds] splitEachLabel(imds, 0.8, randomized); % HOG参数 cellSize [8 8]; fixedSize [128 64]; % 先读取一张图确定特征维度 sampleImg readimage(trainImds, 1); if size(sampleImg, 3) 3 sampleImg rgb2gray(sampleImg); end sampleImg imresize(sampleImg, fixedSize); sampleFeatures extractHOGFeatures(sampleImg, CellSize, cellSize); numFeatures numel(sampleFeatures); % 提取全部训练集特征 numTrain numel(trainImds.Files); trainFeatures zeros(numTrain, numFeatures); trainLabels trainImds.Labels; for i 1:numTrain img readimage(trainImds, i); if size(img, 3) 3 img rgb2gray(img); end img imresize(img, fixedSize); trainFeatures(i, :) extractHOGFeatures(img, CellSize, cellSize); end fprintf(特征矩阵大小: %d x %d\n, size(trainFeatures, 1), size(trainFeatures, 2));这套代码的关键点是先确定numFeatures再预分配trainFeatures矩阵最后循环填充。当训练集有几千张图像时预分配能让整个提取过程快上不少。5.2 训练多分类SVM分类器特征提取完成后训练部分其实很简洁% 定义线性SVM模板 t templateSVM(KernelFunction, linear, Standardize, true); % 训练多分类SVM mdl fitcecoc(trainFeatures, trainLabels, ... Learners, t, ... Coding, onevsone); % 如果想快速评估模型使用交叉验证 cvmdl fitcecoc(trainFeatures, trainLabels, ... Learners, t, ... Coding, onevsone, ... KFold, 5); cvAccuracy 1 - kfoldLoss(cvmdl); fprintf(5折交叉验证准确率: %.2f%%\n, cvAccuracy * 100);我习惯先做交叉验证而不是直接训练一个模型。交叉验证能更稳定地反映模型在小数据上的真实水平避免测试集里正好混入了一些很好分或者很难分的样本导致评估结果波动太大。关于核函数的选择当特征维度比较高比如3780维样本量只有几百到几千时线性核往往就够用了而且训练快、不容易过拟合。RBF核能力强但需要调两个超参数在小数据上更容易过拟合。我的建议是先上线性核如果准确率明显不满足要求再换RBF。5.3 测试与混淆矩阵评估训练好模型之后用测试集评估。测试集的特征提取流程和训练集完全一致再用predict函数预测。numTest numel(testImds.Files); testFeatures zeros(numTest, numFeatures); testLabels testImds.Labels; for i 1:numTest img readimage(testImds, i); if size(img, 3) 3 img rgb2gray(img); end img imresize(img, fixedSize); testFeatures(i, :) extractHOGFeatures(img, CellSize, cellSize); end % 预测并计算准确率 predLabels predict(mdl, testFeatures); accuracy sum(predLabels testLabels) / numel(testLabels); fprintf(测试集准确率: %.2f%%\n, accuracy * 100); % 混淆矩阵 confMat confusionmat(testLabels, predLabels); disp(confMat);混淆矩阵是最直观的误差分析工具。它能告诉你哪两类之间最容易混淆。比如看到dog被大量预测成cat那说明这两类的HOG特征确实比较接近需要重点检查预处理或者考虑增加训练样本。5.4 特征可视化与模型解释MATLAB的extractHOGFeatures有两个输出第二个输出visualization可以直接用来画特征图[features, vis] extractHOGFeatures(sampleImg, CellSize, cellSize); figure; imshow(sampleImg); hold on; plot(vis); title(HOG特征可视化);可视化效果是原图叠加上圆形的方向直方图表示每个圆的位置对应一个block的中心圆内的辐射线长度表示该block内某个方向的梯度强度。这张图放在答辩PPT里非常直观评审老师一眼就能看出系统关注的是目标的边缘轮廓区域。5.5 调参路径不要一上来就改参数根据我的经验HOG加SVM的调参有一个优先级从高到低依次是数据、预处理、特征参数、SVM参数。先检查数据划分是否正确、各类别样本是否均衡再确认目标区域在resize之后没有严重变形然后才是调cellSize、NumBins和核函数。很多时候准确率上不去问题根本不在参数而在于数据集里混入了噪声很大的样本或者训练集测试集图像来源不一致。6. 仿真操作视频怎么把识别流程录清楚6.1 为什么操作视频是个加分项不少课程设计和毕业设计的验收都要求提供一份代码仿真操作视频用来证明程序是真实能跑的、结果可复现。有些朋友以为网上找个现成视频就能交差这件事我不太建议。一方面视频内容和你的数据集、代码很可能对不上答辩时老师随便问一个细节就穿帮另一方面录制视频的过程本身就是一次完整的流程图梳理会让你对项目理解得更深。自己认真录一份通常只要五到八分钟效果却比现成视频好很多。6.2 视频结构按数据-训练-测试三阶段设计一份清晰的操作视频应该按照下面这个结构来组织阶段建议时长展示内容开场15秒项目目录结构、代码文件清单数据集展示30秒展示每个类别的样本图像说明数量特征提取与训练1至2分钟运行训练脚本展示特征维度和训练进度交叉验证30秒展示5折交叉验证准确率单图测试1分钟输入一张新图展示预测类别与置信度批量测试1分钟测试集整体预测展示混淆矩阵收尾15秒总结流程点出后续优化方向这个结构很有讲究先让观看者建立预期知道数据集长什么样再让他看到训练过程而不是后台偷偷跑完最后用单图测试和批量测试两层证据证明模型有效。如果有代码需要临时修改的地方比如切换测试图像最好放在单图测试阶段一起展示不要反复打断节奏。6.3 录屏实操需要注意的技术细节第一分辨率至少1280x720代码编辑器里的字体调大到14号或16号否则视频里代码看不清观感很差。录屏软件用Windows自带的录屏功能或者OBS都可以后者还能同时录麦克风方便边演示边讲解。第二录之前先把流程完整走一遍。这一步不是浪费时间而是确保不会在录制过程中出现意外报错。MATLAB偶尔会因为路径问题找不到文件或者因为字体编码导致中文路径报错。稳妥起见项目路径和数据集路径里不要出现中文。第三录制过程中把命令行分成一小段一小段输入而不是一次性粘贴一大段再运行。每一步都稍微停顿配合口头解释。这样做出来的视频不是给人看结果而是教人看方法可读性完全不一样。6.4 演示过程中常见翻车点最容易翻车的几个地方训练脚本运行时间过长视频录到一半还没有输出观众早就失去耐心命令行输出中文乱码影响观感测试阶段读取了一张和训练数据分布差异很大的图像比如背景特别复杂导致预测结果不理想。针对最后一种情况提前在单图测试阶段选几张效果稳定的代表性图像预览结果确认无误后再录。7. HOG和SVM组合的常见坑位和误区7.1 搜索SVM会被同名技术干扰这里说一个很实际的坑。在搜索引擎里搜SVM这个词结果里经常混进来大量和CPU硬件、虚拟机相关的同名缩写。我在刚接触这个主题时也经历过一搜一屏无关结果的情况。它和咱们说的支持向量机Support Vector Machine完全不是一回事只是缩写恰好相同。搜索本主题相关的内容时建议直接用全称support vector machine或者带上MATLAB支持向量机作为限定词能省下不少筛选时间。7.2 MATLAB版本和工具箱依赖extractHOGFeatures函数属于Computer Vision Toolboxfitcecoc属于Statistics and Machine Learning Toolbox。如果环境里没有这两个工具箱代码会直接报未定义函数或类。配置环境时用ver命令检查一下工具箱是否完整比闷头跑代码更高效。版本方面我建议至少R2020b以上。太老的版本里extractHOGFeatures的默认参数和输出格式有差异网络教程里的代码不一定能直接跑通。7.3 特征维度失控和内存爆炸如果图像尺寸设置得很大比如256x256同时cellSize又取[4 4]HOG特征维度会飙升到数万维。几百张图像可能还撑得住几千张图像直接会导致训练矩阵占用大量内存训练时间也明显变长。如果真的需要降低特征维度先尝试调大cellSize到[16 16]或者对提取出的特征做PCA降维保留主成分后再喂给SVM。7.4 文件夹里混入非图像文件imageDatastore在读取数据集目录时如果目录里混入了非图像文件比如Thumbs.db、Mac系统产生的隐藏文件会直接报错导致流程中断。这个问题在网上提问频率很高但其实只需要在构造imageDatastore之前把目录清理干净就能避免% 清理目录中所有非图片文件 dirData dir(fullfile(dataset, **, *)); for i 1:length(dirData) if ~dirData(i).isdir [~, ~, ext] fileparts(dirData(i).name); if ~ismember(lower(ext), {.jpg, .jpeg, .png, .bmp}) delete(fullfile(dirData(i).folder, dirData(i).name)); end end end这段代码会把所有非jpg、png、bmp文件删掉运行时要确保dataset目录就是你想清理的目录别误删其他文件。7.5 resize导致目标变形固定尺寸resize是HOG流程里的必要条件但如果是直接从原始图像硬拉成统一尺寸目标宽高比差异大时就会变形。比如一个横向拉长的目标被压成正方形原来水平的边缘在HOG统计中可能变成了斜向特征分布完全被破坏。解决办法是先根据目标的宽高比做裁剪把目标区域裁成接近统一宽高比的矩形然后再resize。如果你和我一样需要在有限的算力和数据条件下快速建立一个目标识别系统我的建议是别急着上深度学习先用HOG加SVM把整套流程从数据到评估完整跑通。你会发现识别这个概念会变得非常具体也会更清楚特征提取和分类器到底在各自解决什么问题。等以后数据和硬件条件都到位了再往CNN迁移这些基础理解同样会帮上大忙。本文还有配套的精品资源点击获取
返回列表