理解YOLO后处理操作:基于MATLAB实现

YOLO(You Only Look Once)目标检测模型的后处理,包括提取预测框、计算交并比(IoU)和非极大值抑制(NMS)。下文将逐个函数进行matlab实现,并解析对应函数的操作。

1.函数decode

功能

decode 函数的主要作用是将模型输出的原始检测结果(通常经过 sigmoid 或 softmax 的值)转换为实际的边界框坐标和置信度。这些值用于进一步的目标检测任务,如非极大值抑制(NMS)等。

代码解析

function output = decode(input, anchor)
    input_channel = size(input, 2);
    input_H = size(input, 3);
    input_W = size(input, 4);

%input: 经过模型处理后的输出张量,通常是一个 4D 张量,包含多个通道。
%anchor: 预定义的锚框(anchor boxes),用于预测目标边界框的大小和形状。
%获取输入的维度:

%input_channel:输入的通道数(通常是 85 的倍数,表示 80 个类别 + 5 个位置参数)。
%input_H 和 input_W:输入图像的高度和宽度。
    % 一个 grid cell 的大小
    stride_h = 416 / input_H;
    stride_w = 416 / input_W;
%网格单元大小:
stride_h 和 stride_w 用于计算每个网格单元的大小(YOLO 通常处理的输入图像大小为 416x416)。
    anchor_w = [anchor(1)/stride_w, anchor(3)/stride_w, anchor(5)/stride_w];
    anchor_h = [anchor(2)/stride_h, anchor(4)/stride_h, anchor(6)/stride_h];
%计算锚框的宽度和高度:
%将锚框的宽度和高度归一化到输入图像的网格大小。
    %% 处理 input 的数据
    output = zeros(1, input_channel, input_H, input_W);
%输出初始化:
%创建一个与输入相同大小的输出张量 output,用来存储解码后的信息。
    for channel = 1:85:input_channel
        for h = 1:input_H
            for w = 1:input_W
                output(1, channel, h, w) = (sigmoid(input(1, channel, h, w)) + w - 1) / input_W;
                output(1, channel + 1, h, w) = (sigmoid(input(1, channel + 1, h, w)) + h - 1) / input_H;
                output(1, channel + 2, h, w) = (exp(input(1, channel + 2, h, w)) * anchor_w(int8(channel/85 + 1))) / input_W;
                output(1, channel + 3, h, w) = (exp(input(1, channel + 3, h, w)) * anchor_h(int8(channel/85 + 1))) / input_H;
                output(1, channel + 4, h, w) = sigmoid(input(1, channel + 4, h, w));
                output(1, channel + 5:channel + 84, h, w) = sigmoid(input(1, channel + 5:channel + 84, h, w));
            end
        end
    end

循环遍历每个网格单元:根据输入的通道,逐个处理每个 grid cell 的数据。
位置坐标的计算:
output(1, channel, h, w): 计算边界框的 x 坐标。通过 sigmoid 激活函数对输入进行处理,然后将其转换到图像坐标系中。
output(1, channel + 1, h, w): 计算边界框的 y 坐标,处理方式相同。
宽度和高度的计算:
output(1, channel + 2, h, w): 计算边界框的宽度。使用指数函数(exp)处理输入,以获得框的尺寸,然后与相应的锚框宽度相乘。
output(1, channel + 3, h, w): 计算边界框的高度,方法类似。
置信度和类别:
output(1, channel + 4, h, w): 计算边界框的置信度。
output(1, channel + 5:channel + 84, h, w): 计算每个类别的概率。

2. 函数 get_pred_boxes

功能

该函数用于从输入数据中提取有效的预测边界框。它根据置信度阈值筛选出可能的目标位置,并返回有效的边界框信息。

代码解析

function output = get_pred_boxes(input)
    global conf_thres  % 使用全局变量 conf_thres,作为置信度阈值
%全局变量:conf_thres 用于设定置信度的阈值。
    input_channel = size(input, 2);  % 输入数据的通道数
    input_H = size(input, 3);  % 输入图像的高度
    input_W = size(input, 4);  % 输入图像的宽度
%尺寸获取:获取输入数据的通道数和图像的高度、宽度。
    max_boxes = 3 * input_H * input_W;  % 计算最大可能的边界框数
    output = zeros(max_boxes, 6);  % 输出矩阵,每行对应一个边界框,包含6个参数
    num = 0;  % 初始化有效边界框计数
%预分配输出:预分配一个矩阵 output 来存储预测框的信息,每个框有 6 个参数(x, y, w, h, 置信度, 类别索引)。
    for channel = 1:85:input_channel
        for h = 1:input_H
            for w = 1:input_W
                class_confidences = input(1, channel + 5:channel + 84, w, h);
                [max_class_conf, max_class_index] = max(class_confidences);
                conf = input(1, channel + 4, w, h);
                
                if (max_class_conf * conf > conf_thres)
%遍历通道:循环遍历每个检测通道,以提取类别置信度和对象存在的置信度。
                    num = num + 1;  % 更新有效边界框计数
                    output(num, 1:4) = input(1, channel:channel + 3, w, h);  % 边界框位置信息
                    output(num, 5) = max_class_conf * conf;  % 最终的置信度
                    output(num, 6) = max_class_index;  % 类别索引
                end
            end
        end
    end
    
    output = output(1:num, :);  % 只保留有效的边界框
end

有效框筛选:如果最大类别置信度与对象置信度的乘积大于阈值,更新输出框并记录有效框的数量。

3. 函数 calcu_IOU

功能

计算当前框与其他框之间的交并比(IoU),用于评估框的重叠情况。

代码解析

function output = calcu_IOU(now_box, oth_boxes)
    now_area = now_box(3) * now_box(4);  % 当前框的面积
    oth_area = oth_boxes(:, 3) .* oth_boxes(:, 4);  % 其他框的面积
面积计算:计算当前框和其他框的面积。
    w = min(now_box(1) + now_box(3)/2, oth_boxes(:, 1) + oth_boxes(:, 3)/2) - ...
        max(now_box(1) - now_box(3)/2, oth_boxes(:, 1) - oth_boxes(:, 3)/2);
    h = min(now_box(2) + now_box(4)/2, oth_boxes(:, 2) + oth_boxes(:, 4)/2) - ...
        max(now_box(2) - now_box(4)/2, oth_boxes(:, 2) - oth_boxes(:, 4)/2);
交集宽高计算:计算当前框与其他框的交集宽度和高度。
    and_area = (w > 0) .* (h > 0) .* (w .* h);  % 计算交集的面积
    output = and_area ./ (now_area + oth_area - and_area);  % 计算IoU

IoU计算:计算 IoU,并避免出现除以零的情况。

4. 函数 non_max_suppression

功能

执行非极大值抑制(NMS),以过滤掉重叠过多的预测框,保留置信度最高的框。

代码解析

function output = non_max_suppression(input_1, input_2, input_3)
    global nms_thres  % 使用全局变量 nms_thres 作为非极大值抑制的 IoU 阈值
%全局变量:使用 nms_thres 作为非极大值抑制的 IoU 阈值。
    box_info_1 = get_pred_boxes(input_1);  % 提取有效预测框
    box_info_2 = get_pred_boxes(input_2);
    box_info_3 = get_pred_boxes(input_3);
    
    box_info = cat(1, box_info_1, box_info_2, box_info_3);  % 合并三个预测框信息
    output = [];  % 初始化输出
%框信息提取:从三个不同输入中提取预测框信息并合并。
    for class = 1:80
        box_class = box_info(find(box_info(:,6) == class), :);  % 选择当前类别的框
        box_num = size(box_class, 1);
        
        if (box_num == 0)
            continue;  % 如果没有框则跳过
        end
        
        box_class = sortrows(box_class, 5, "descend");  % 按置信度排序
%类别处理:按类别处理每个框,并根据置信度进行排序。
        iterator = 1;
        while (iterator < box_num)
            now_box = box_class(iterator, :);  % 当前参考框
            iou = calcu_IOU(now_box(1,1:4), box_class(iterator+1:box_num, 1:4));  % 计算IoU
            
            delete_index = find(iou > nms_thres) + iterator;  % 找出需要删除的框
            box_class(delete_index, :) = [];  % 删除重叠框
            
            box_num = size(box_class, 1);
            iterator = iterator + 1;  % 继续下一个参考框
        end
        
        output = cat(1, output, box_class);  % 添加到最终输出中
    end
end

NMS实施:通过 IoU 检查并删除重叠的框,最终将结果返回。

后处理完整流程

1. 锚框设置和输出解码

yolo_anchor = [[116,90,156,198,373,326];[30,61,62,45,59,119];[10,13,16,30,33,23]];
x0_out = decode(x0_out,yolo_anchor(1,:));
x1_out = decode(x1_out,yolo_anchor(2,:));
x2_out = decode(x2_out,yolo_anchor(3,:));

锚框(Anchors):yolo_anchor 中的三个数组定义了三个尺度的锚框,分别对应不同大小的目标。
解码输出:调用 decode 函数对模型输出的 x0_out、x1_out 和 x2_out 进行解码,以获取边界框的真实坐标和类别信息。

2. 非极大值抑制

result = non_max_suppression(x0_out,x1_out,x2_out);

非极大值抑制(NMS):non_max_suppression 函数用于去除重叠度过高的边界框,只保留得分最高的边界框。此步骤可以显著提高检测精度,减少重复的检测结果。

3. 类别和颜色定义

classes = ["person","bicycle","car","motorbike","aeroplane","bus","train","truck","boat","traffic light","fire hydrant",...
"stop sign","parking meter","bench","bird","cat","dog","horse","sheep","cow","elephant","bear","zebra","giraffe","backpack",...
"umbrella","handbag","tie","suitcase","frisbee","skis","snowboard","sports ball","kite","baseball bat","baseball glove"...
,"skateboard","surfboard","tennis racket","bottle","wineglass","cup","fork","knife","spoon","bowl","banana","apple","sandwich",...
"orange","broccoli","carrot","hot dog","pizza","donut","cake","chair","sofa","pottedplant","bed","diningtable"...
,"toilet","tvmonitor","laptop","mouse","remote","keyboard","cell phone","microwave","oven","toaster","sink",...
"refrigerator","book","clock","vase","scissors","teddy bear","hair drier","toothbrush"];

num_classes = 80;
color_map = lines(num_classes);  % 生成色相饱和度值的颜色

类别定义:classes 是一个字符串数组,包含 YOLO 模型可以检测的 80 种物体类别。
颜色映射:color_map 使用 lines(num_classes) 生成不同的颜色以便于在图像中区分不同的检测类别。

4. 绘制边界框和标签

for i = 1:size(result, 1)
    hold on
    
    % 计算矩形框的属性
    leftup_x = image_w * (result(i, 1) - result(i, 3) / 2);
    leftup_y = image_h * (result(i, 2) - result(i, 4) / 2);
    box_w = image_w * result(i, 3);
    box_h = image_h * result(i, 4);
    
    % 获取类别索引并确定颜色
    class_idx = int8(result(i, 6));  % 将类别索引转为整型

    rectangle_color = color_map(class_idx, :);  % 使用对应类别的颜色

    % 绘制矩形框
    rectangle('Position', [leftup_x leftup_y box_w box_h], ...
              'LineWidth', 2, ...
              'EdgeColor', rectangle_color);
    
    % 在矩形框上方添加类别标签
    text(leftup_x, leftup_y - 10, classes{class_idx}, ...  % 注意用大括号获取字符串
         'FontSize', 12, ...
         'Color', 'white');
end

循环遍历每个检测结果:对于 result 中的每一行(即每个检测到的目标),进行以下处理:
计算矩形框的左上角坐标:根据边界框中心点 (result(i, 1), result(i, 2)) 和宽高 (result(i, 3), result(i, 4)) 计算左上角的坐标。
获取类别索引:class_idx 从结果中获取类别索引并转换为整数,以便于从 color_map 中查找颜色。
绘制矩形框:使用 rectangle 函数绘制边界框,设置边框的宽度和颜色。
添加类别标签:在矩形框的上方绘制目标的类别名称。

总结

上述描述实现了 YOLO 模型的后处理过程,包括解码模型输出、执行非极大值抑制、生成颜色映射以及在图像上绘制目标边界框和标签。这是目标检测的关键步骤,帮助将模型的预测结果以可视化的方式呈现出来。理解这些步骤对于在实际应用中使用 YOLO 进行目标检测非常重要。
最后在文章末尾贴出实现YOLO算法的部分结果:
在这里插入图片描述
在这里插入图片描述
本文旨在介绍在MATLAB中实现已训练好的神经网络模型的过程,帮助同学们梳理神经网络的计算步骤。这些步骤不仅对于在PC以外的其他平台部署神经网络有一定的指导意义,也能帮助那些对深度学习不太了解的同学更好地理解深度学习模块所执行的具体操作及其实现方式。选择MATLAB作为工具,是因为其语法相对简单,并且在学术界和大学中得到广泛应用,适合初学者入门。
对于那些希望在其他框架(如PyTorch或TensorFlow)中部署深度学习模型的同学,建议参考相关博客和文档,搭建适合自己的深度学习环境,探索更复杂的训练过程与模型优化策略。
希望本教程能为大家打开深度学习的第一扇门,祝愿大家在学习和实践的旅程中取得优异的成绩,开启探索深度学习的精彩之旅!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值