拓十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

HOG+SVM行人检测实战:Matlab实现与调参避坑指南

HOG+SVM行人检测实战:Matlab实现与调参避坑指南 简介SVMHOG行人识别算法的MATLAB实现一套面向计算机视觉学习者与研究人员的完整资料解决行人检测中HOG特征提取与SVM分类器衔接的实际问题。压缩包共2429个文件以1482张jpg和933张png图片为主涵盖正负样本、测试图片及中间过程可视化结果另有10个m脚本实现特征计算、模型训练与检测流程并附txt使用说明、mat模型数据和pptx讲解方便对照理解。包体约35.35MB结构清晰适合在MATLAB中直接运行。已有2826人学习下载。资料重点拆解HOG梯度直方图构造、fitcsvm训练、多尺度滑动窗口定位以及重心滤除、重叠面积法去重等优化策略并针对负例不足导致的误判问题给出分析思路。借助完整代码和大量可视化结果读者可掌握从样本准备、参数调整到结果评估的完整链路适用于课程设计、毕业设计及视觉入门科研。1. 把 SVMHOG 行人识别跑通为什么到了 2024 年这套老方案还值得学做过图像处理的人对 HOGSVM 应该不陌生——这是 2005 年 Dalal 和 Triggs 在 CVPR 上提出的经典行人检测方案特征层面用方向梯度直方图分类层面用支持向量机。现在深度学习大行其道YOLO 系列一版接一版但 HOGSVM 在低算力嵌入式设备、工业视觉、课程设计和算法入门这几个场景里依然没有过时。它的价值不只是“能检测人”而是把特征工程和分类器训练这两个最核心的视觉问题拆开讲透了特征怎么设计、分类器怎么训练、参数怎么调、误检怎么压。这套 Matlab 实现正好覆盖完整流程我在不少项目里都是用 Matlab 先做算法验证再移植到 C 或 Python这套流程本身就是一个极其完整的样板工程。2. HOG 特征提取从梯度方向直方图到 Matlab 的 extractHOGFeatures2.1 HOG 的原理拆解为什么方向梯度能描述行人形状HOG 的核心假设是物体的局部外观和形状可以通过局部梯度或边缘方向的分布来描述。对行人来说头部、肩膀、腿部的边缘方向特征非常稳定即使背景复杂、光照变化梯度方向依然能保持较好的区分度。实现上图像被划分成小的连通区域cell每个 cell 内统计梯度方向直方图若干 cell 组成一个 blockblock 内做对比度归一化最后把所有 block 的直方图串联起来就是最终特征向量。有几个关键参数直接决定特征质量。cell 大小典型值是 8×8 像素block 大小通常是 2×2 个 cellbin 数量梯度方向分桶数通常是 9 或 18。bin 少则角度分辨率低bin 多则特征维度爆炸且容易过拟合。block 重叠一步block stride一般设为 cell 大小的一半这样每个 cell 会出现在多个 block 中归一化效果更平滑。2.2 Matlab 实现extractHOGFeatures 的参数选择与示例代码Matlab 的 Computer Vision Toolbox 提供了现成的 extractHOGFeatures 函数这里我给出一个带注释的调用示例% 读取图像并统一灰度 img imread(pedestrian.jpg); if size(img, 3) 3 imgGray rgb2gray(img); else imgGray img; end % 设置 HOG 参数 cellSize [8 8]; % cell 大小单位像素 blockSize [2 2]; % block 由 2x2 个 cell 组成 numBins 9; % 梯度方向分桶数 blockOverlap [1 1]; % block 重叠步长 % 提取 HOG 特征 [hogFeature, visualization] extractHOGFeatures(imgGray, ... CellSize, cellSize, ... BlockSize, blockSize, ... NumBins, numBins, ... BlockOverlap, blockOverlap); % hogFeature 是行向量visualization 可用于 plot 展示 disp([HOG 特征维度: , num2str(length(hogFeature))]);这段代码的核心参数说明CellSize 决定空间分辨率8×8 是经过大量实验验证的折中选择cell 太小则特征维度大、计算慢太大则丢失细节NumBins 设为 9 表示把 0 到 180 度无符号梯度分成 9 个方向区间行人检测场景下无符号梯度比有符号梯度效果更稳BlockOverlap 设为 [1 1] 表示 block 每次滑动 1 个 cell允许重叠能有效抵消光照和对比度变化的影响。2.3 特征可视化先看图再调参避免盲目改参数提取完特征后强烈建议先做可视化确认特征确实捕捉到了行人轮廓而不是一堆无意义的数值。Matlab 的 plot 方法可以直接绘制 HOG 特征图figure; imshow(imgGray); hold on; plot(visualization); % 在原始图像上叠加 HOG 特征线 title(HOG 特征可视化);可视化能看到什么行人的头部和肩部边缘方向非常明显腿部次之。如果特征图杂乱无章多半是图像预处理有问题比如没做灰度化、图像分辨率过小、或者行人目标占画面比例太小。我一般把行人区域裁剪到 64×128 像素再提取特征这是 Dalal 论文里默认的检测窗口尺寸特征维度大约 3780 维直接用 SVM 训练速度和效果都很理想。3. SVM 分类器训练线性核还是 RBF 核正负样本怎么配3.1 为什么行人检测场景下线性 SVM 比 RBF 核更实用HOG 特征维度动辄几千维样本量通常也就几千到几万。在高维空间下线性 SVM 的泛化能力往往不输 RBF 核而且训练和预测速度快一个数量级。RBF 核的 gamma 参数如果调不好极易过拟合训练集在测试集上误检率飙升。我自己的经验是先用线性核跑通整体流程确认特征有效后再去尝试 RBF 核做对比。如果线性核的准确率已经能满足需求就不要换核省下的时间用在样本和阈值调优上更有价值。3.2 训练数据准备正样本要多样负样本要足够“刁钻”训练样本的选择比模型参数更影响最终效果。正样本是从 INRIA 或自建数据集中裁剪出的行人图像统一缩放到 64×128 像素负样本是不含行人的任意图像块同样缩放到相同尺寸。负样本的关键在于多样性只放纯风景图是不行的要包含街道、树木、车辆、建筑边缘等容易产生假阳性的场景。数量比例上负样本至少是正样本的 2 到 3 倍最好能到 5 倍。一开始可以先随机采样一批负样本训练一个初始模型再用这个模型去扫描负样本图库把误检出来的 hard negative难例加入训练集继续训练这就是经典的 hard negative mining 流程在 Matlab 里通常要写一个循环迭代的过程。3.3 fitcsvm 训练代码与参数说明Matlab 训练 SVM 的标准函数是 fitcsvm示例代码% 假设 posFeatures 和 negFeatures 已分别提取并合并 % trainFeatures: N x M 的矩阵N 为样本数M 为特征维度 % trainLabels: N x 1 的标签向量1 表示行人0 表示非行人 trainFeatures [posFeatures; negFeatures]; trainLabels [ones(size(posFeatures,1), 1); zeros(size(negFeatures,1), 1)]; % 训练线性 SVM svmModel fitcsvm(trainFeatures, trainLabels, ... KernelFunction, linear, ... BoxConstraint, 1, ... Standardize, true, ... ClassNames, [0 1]); % 保存模型 save(svmModel.mat, svmModel);参数说明BoxConstraint 是惩罚系数控制误分类样本的惩罚力度。值越大训练集上的误分类越少但泛化能力可能下降值太小则容易出现欠拟合。默认值 1 通常够用如果训练集准确率上不去可以尝试调大到 5 或 10。Standardize 设为 true 表示对特征做标准化处理这在 HOG 特征数值范围不一致时尤其重要。ClassNames 指定标签的映射关系保证预测时输出的 score 正负号正确。3.4 训练完先看混淆矩阵再继续% 用训练集自身做验证 [predLabel, score] predict(svmModel, trainFeatures); acc sum(predLabel trainLabels) / length(trainLabels); C confusionmat(trainLabels, predLabel); disp([训练集准确率: , num2str(acc * 100), %]); disp(C);这一步只是验证流程走得通重点要看混淆矩阵中哪一类误分类多。如果大量正样本被分错说明正样本质量有问题裁剪不齐、标注不准如果负样本被大量分错说明难例挖掘不够需要补充更多难例。4. 滑动窗口检测从整图到行人框的完整流程4.1 滑动窗口与图像金字塔多尺度检测的基本思路训练好的 SVM 只能对固定尺寸64×128的图像块做分类。真实图片中行人大小不一所以要用图像金字塔解决尺度问题——把原图按比例逐层缩小或放大每层都用固定大小的检测窗口扫描窗口大小固定但图像本身在变。Matlab 中可以用 imresize 实现金字塔缩放每层缩放比例一般取 0.8 到 0.9层数根据目标最小尺寸决定。4.2 完整检测代码窗口滑动、特征提取与分类判断这段代码是检测部分的核心做了一个单尺度的滑动窗口示例function bboxes detectPedestrians(img, svmModel, cellSize, windowSize, step) % img: 输入灰度图 % svmModel: 训练好的 SVM 模型 % cellSize: HOG cell 大小与训练时一致 % windowSize: 检测窗口大小默认 [64 128] % step: 滑动步长默认 8 像素 [h, w] size(img); winW windowSize(1); winH windowSize(2); bboxes []; for y 1:step:h - winH 1 for x 1:step:w - winW 1 % 裁剪窗口并提取 HOG 特征 winImg imcrop(img, [x y winW-1 winH-1]); hog extractHOGFeatures(winImg, CellSize, cellSize); % 预测score 是 SVM 决策值 [predLabel, score] predict(svmModel, hog); if predLabel 1 score threshold bboxes [bboxes; x y winW winH score]; end end end end滑动步长 step 的取值要权衡速度和精度。step 越小窗口重叠越多检测越密但计算量成倍增加step 取 8 像素是比较常用的折中值。注意 predict 的输出 score 是决策值而不是概率阈值 threshold 需要自己定一般初始设为 0再根据实际误检情况调整。4.3 非极大值抑制让一个行人只出一个框滑动窗口会产生大量重叠的检测框同一个行人可能被框住十几次。非极大值抑制NMS的原理是如果两个框的交并比IoU超过阈值则保留得分更高的框删除得分低的框。在 Matlab 里可以用 vision.LocalMaximaFinder 或者自己写一个循环实现简单的 NMS。自己做的话逻辑不复杂先按得分降序排序依次取框删除所有与该框 IoU 大于 0.5 的其他框。5. 避坑指南HOGSVM 行人检测中常见的五个大坑5.1 误检率爆炸负样本种类不够现象是模型在训练集上表现很好但一到真实场景几十个误检框。原因几乎都是负样本太简单或者太少模型没有见过真正的“难例”。解决办法是把负样本图库扩充到包含街道、树木、建筑立面、车辆等复杂背景并且做 hard negative mining——用当前模型扫描图库把误检的图块加入训练集重新训练循环两三轮。5.2 检测框重叠严重漏了 NMS 或者 IoU 阈值设得不对现象是一个行人的位置被五六个框覆盖。原因是滑动窗口自然导致大量重叠框而 NMS 的 IoU 阈值太高比如 0.9导致抑制不彻底。建议把 IoU 阈值降到 0.4 到 0.5并且确保 NMS 在金字塔所有层做完之后统一执行一次而不是每层单独做再合并结果。5.3 小目标完全检测不到金字塔层数不够现象是距离远的行人图像中高度只有 50 像素左右完全没框。原因是滑动窗口固定为 64×128金字塔最上层缩放比例不够大。解决方法是把金字塔缩放步长设为 0.8多生成几层小尺度图像或者把滑动窗口改小到 48×96但这需要重新训练模型因为 HOG 特征维度会变。5.4 训练耗时极长样本数量太多且没有特征缓存现象是每轮迭代都要半小时以上调一次参数就等半天。原因是每次训练都重新提取所有样本的 HOG 特征这是完全重复的计算。解决办法是把所有样本的特征一次性提取并保存成 .mat 文件训练和调参时直接 load 特征矩阵只做 SVM 部分。这个习惯能节省至少 70% 的调参时间。5.5 score 正负号混乱ClassNames 顺序没对齐现象是 predict 输出的 score 完全不可用阈值设正设负都不对。原因是 fitcsvm 的 ClassNames 参数和 predict 返回的 score 列顺序没有对齐。Matlab 中 predict 返回的 score 矩阵第一列对应 ClassNames 中的第一个类。建议把 ClassNames 设为 [0 1]且训练和预测时保持一致这样 score 0 表示偏向正样本行人。6. 最后的 NMS 与难例挖掘让误检率再降一截的实用技巧到了这一步整个 HOGSVM 检测流程已经能跑通了但实战中往往需要再优化一步。我常用的两个技巧是重叠率阈值自适应和难例挖掘两轮迭代。重叠率阈值自适应的思路是检测框的得分越高NMS 时允许它保留更大的重叠范围得分低的框重叠阈值调小更容易被抑制。具体实现就是给 NMS 循环里的 IoU 阈值加上一个和 score 相关的系数。难例挖掘方面的经验是第一轮训练用随机负样本跑一遍完整检测流程把误检框对应的图像块收集起来大小缩放到 64×128加入负样本集重新训练一轮。第二轮训练后误检率通常能下降一半以上。如果还不行继续迭代第三轮收益会递减。另外有一个容易被忽略的点检测完成后的坐标还原。图像金字塔中每一层检测出的框坐标需要除以缩放比例映射回原图尺寸否则输出的框位置是错的。我血泪经验是映射时忘记了 subpixel 偏移导致框整体偏了几像素后来每次缩放都记录比例因子和位移强制校准一遍坐标再进入 NMS再也没出过偏差。希望这些细节能帮你的 HOGSVM 项目少走点弯路。本文还有配套的精品资源点击获取
返回列表