文章目录
- 前言
- 代码
- 报错解决方法
- 缺点
- 总结
前言
YOLO 是一种经典的一阶段目标检测算法,它将检测问题转化为回归问题。与 Faster R-CNN 不同,YOLO 不是提取 RoI,而是直接通过回归的方法生成每个类的边界框坐标和概率。与 Faster R-CNN相比,大大提高了检测速度。Glenn Jocher 于 2020年提出了 YOLO 的第五个版本,命名为 YOLOv5,其网络结构主要分为骨干模块、颈部模块和头部模块。主干模块基于Focus、BottleneckCSP(跨阶段部分网络)和空间金字塔池,并将其传输到颈部模块。颈部模块基于PANet(路径聚合网络)生成特征金字塔。它通过双向融合低级空间特征和高级语义特征来增强检测不同尺度物体的能力。头部模块通过将锚框应用于来自颈部模块的多尺度特征图来生成检测框、类别信息、坐标和置信度。也有使用matlab完成YOLOv5目标检测,本文将参考 cuixing158 作者的源码,giehub地址为: yoloV5-yoloX-matlab。
重点重点重点:为了代码运行不报错,安装 matlab 版本为 2021 及以上版本。
matlab安装教程大家可以参考这个教程: 手把手教你安装matlab软件
代码
运行效果如下:
我修改好的代码如下,直接复制即可运行,并解决运行会报错的问题解决一下,我也会把源码包放到公众号,末尾领取资料即可。代码整体流程是:
-
模型加载与初始化:
加载预训练的YOLOv5模型(yolov5s.onnx)。
设置相关参数,如输入尺寸(640x640)、阈值(0.3,0.5)。 -
图像读取与显示:
读取待检测的图像(‘images/2.jpg’)并显示原图。
-
图像预处理:
对图像进行大小调整(imresize), 将图像像素值缩放至[0,1]范围等
-
模型推理:
使用feval函数进行模型的前向推理,得到检测结果(outs),包括多个检测头的输出。
-
解码YOLOv5输出:
对YOLOv5的输出进行解码,得到每个检测框的坐标、置信度以及类别信息。
-
阈值过滤和非极大值抑制(NMS):
过滤掉低置信度的检测框,对过滤后的检测框进行NMS处理,去除重叠较大的检测框,只保留最强的框。
修改好的代码如下:
model = "./yolov5s.onnx";
customYoloV5FcnName = 'yolov5fcn';
inputSize = [640,640];
throushHold = 0.3;
nmsThroushHold = 0.5;
outs = cell(3,1); % 3个检测head输出
classesNames = categorical(readlines("coco.names"));
colors = randi(255,length(classesNames),3);
params = importONNXFunction(model,customYoloV5FcnName);image = imread('images/2.jpg'); % 修改为你需要识别的图片路径
imshow(image);
title('原始图像');[H,W,~] = size(image);% 图像预处理
img = imresize(image, inputSize);
img = rescale(img, 0, 1); % 转换到[0,1]
img = permute(img, [3,1,2]); % 改变维度顺序为 [C,H,W]
img = dlarray(reshape(img, [1, size(img)])); % n*c*h*w,[0,1],RGB顺序
if canUseGPU()img = gpuArray(img);
endt1 = tic;
[outs{:}] = feval(customYoloV5FcnName, img, params, ...'Training', false, ...'InputDataPermutation', 'none', ...'OutputDataPermutation', 'none'); % 预测图像
fprintf('yolov5预测耗时:%.2f 秒\n', toc(t1));outFeatures = yolov5Decode(outs, H, W);%% 阈值过滤+NMS处理scores = outFeatures(:, 5);
% 阈值过滤:只保留大于阈值的框
validIdxs = scores > throushHold;
outFeatures = outFeatures(validIdxs, :); % 提取边界框和对应的类别信息
allBBoxes = outFeatures(:, 1:4);
[maxScores, indxs] = max(outFeatures(:, 6:end), [], 2);
allScores = maxScores;
allLabels = classesNames(indxs);% 如果存在有效边界框,则进行NMS非极大值抑制
if ~isempty(allBBoxes)[bboxes, nmsScores, labels] = selectStrongestBboxMulticlass(allBBoxes, allScores, allLabels, ...'RatioType', 'Min', 'OverlapThreshold', nmsThroushHold);annotations = string(labels) + ": " + string(nmsScores);% 获取类别ID并为每个类别分配颜色[~, ids] = ismember(labels, classesNames);color = colors(ids, :);image = insertObjectAnnotation(image, 'rectangle', bboxes, cellstr(annotations), ...'Color', color, 'LineWidth', 3);
end% 显示结果图像
imshow(image);
title('检测结果图像');function outPutFeatures = yolov5Decode(featuremaps, oriHight, oriWidth, anchors)argumentsfeaturemaps (:,1) celloriHight (1,1) doubleoriWidth (1,1) doubleanchors (:,2) double = [10,13; 16,30; 33,23;...30,61; 62,46; 59,119;...116,90; 156,198; 373,326]end%% yolov5*.onnx known paramsinputSize = 640; % 输入网络图像大小,正方形图像输入na = 3; % 每个检测head对应anchor的数量nc = 80; % coco类别数量%% decodescaledX = inputSize./oriWidth;scaledY = inputSize./oriHight;outPutFeatures = [];numberFeaturemaps = length(featuremaps);for i = 1:numberFeaturemapscurrentFeatureMap = featuremaps{i}; % bs*[(4+1+nc)*na]*h*w大小currentAnchors = anchors(na*(i-1)+1:na*i, :); % na*2numY = size(currentFeatureMap, 3);numX = size(currentFeatureMap, 4);stride = inputSize ./ numX;% reshape currentFeatureMap到有意义的维度,bs*[(4+1+nc)*na]*h*w --> h*w*(5+nc)*na*bs% --> bs*na*h*w*(5+nc),最终的维度方式与yolov5官网兼容bs = size(currentFeatureMap, 1);h = numY;w = numX;disp(size(currentFeatureMap));currentFeatureMap = reshape(currentFeatureMap, bs, 5 + nc, na, h, w); % bs*(5+nc)*na*h*wcurrentFeatureMap = permute(currentFeatureMap, [1, 3, 4, 5, 2]); % bs*na*h*w*(5+nc)[~,~,yv,xv] = ndgrid(1:bs, 1:na, 0:h-1, 0:w-1); % yv, xv大小都为bs*na*h*w,注意顺序,后面做加法维度标签要对应gridXY = cat(5, xv, yv); % 第5维上扩展,大小为bs*na*h*w*2, x,y从1开始的索引currentFeatureMap = sigmoid(currentFeatureMap); % yolov5是对所有值进行归一化,与yolov3/v4不同currentFeatureMap(:,:,:,:,1:2) = (2 * currentFeatureMap(:,:,:,:,1:2) - 0.5 + gridXY) .* stride; % 大小为bs*na*h*w*2,预测对应xyanchor_grid = reshape(currentAnchors, 1, na, 1, 1, 2); % 此处anchor_grid大小为1*na*1*1*2,方便下面相乘currentFeatureMap(:,:,:,:,3:4) = (currentFeatureMap(:,:,:,:,3:4) * 2).^2 .* anchor_grid; % 大小为bs*na*h*w*2if nc == 1currentFeatureMap(:,:,:,:,6) = 1;endcurrentFeatureMap = reshape(currentFeatureMap, bs, [], 5 + nc); % bs*N*(5+nc)if isempty(outPutFeatures)outPutFeatures = currentFeatureMap;elseoutPutFeatures = cat(2, outPutFeatures, currentFeatureMap); % bs*M*(5+nc)endend%% 坐标转换到原始图像上% [cx, cy, w, h],yolov5.onnx基准图像大小(1*3*640*640)----> [x, y, w, h], 坐标基于原始图像大小(1*3*oriHight*oriWidth)outPutFeatures = extractdata(outPutFeatures); % bs*M*(5+nc), 为[x_center, y_center, w, h, Pobj, p1, p2,..., pn]outPutFeatures(:,:,[1,3]) = outPutFeatures(:,:,[1,3]) ./ scaledX; % x_center, widthoutPutFeatures(:,:,[2,4]) = outPutFeatures(:,:,[2,4]) ./ scaledY; % y_center, heightoutPutFeatures(:,:,1) = outPutFeatures(:,:,1) - outPutFeatures(:,:,3) / 2; % xoutPutFeatures(:,:,2) = outPutFeatures(:,:,2) - outPutFeatures(:,:,4) / 2; % youtPutFeatures = squeeze(outPutFeatures); % 如果是单张图像检测,则输出大小为M*(5+nc),否则是bs*M*(5+nc)if (canUseGPU())outPutFeatures = gather(outPutFeatures); % 推送到CPU上end
end
报错解决方法
第一次运行可能会报错
只需双击 onnxconverter.mlpkginstall 文件安装就行,安装页面需要登录邮箱,没有邮箱注册一个就行,我用的是qq邮箱。
缺点
目前还不能更换自己训练的模型,也可能作者是在旧版本yolov5中实现的,自己尝试更换,但是会出现很多目标框,还得向大佬学习matlab。
总结
我也会把源码包放到公众号,回复“matlab-yolov5”即可获取源码,关注我,带你不挂科!!!