文章目录
ML.NET库学习011:基于YOLO目标检测算法的图像处理系统

项目主要目的和原理
本项目旨在实现基于YOLO(You Only Look Once)目标检测算法的图像处理系统,具体使用的是Tiny YOLO v2模型。该模型是一种轻量级的目标检测模型,适合在资源有限的环境中运行。
主要功能
- 加载数据:读取指定文件夹中的图像。
- 加载模型:使用ONNX格式加载预训练的YOLO模型。
- 目标检测:对输入图像进行推理,预测出目标的位置和类别。
- 后处理:解析模型输出结果,筛选置信度较高的边界框(bounding boxes)。
- 可视化:在原始图像上绘制检测到的目标,并保存结果。
主要原理
- YOLO算法:通过将输入图像划分为网格,每个网格负责预测特定区域内的目标。模型同时输出目标的位置、类别及其置信度。
- ONNX格式:用于跨框架部署深度学习模型,支持在多种环境中运行(如C#)。
项目结构
主要文件和类
- Main.cs:主程序入口,初始化路径变量并执行主要流程。
- ImageProcessor.cs:包含图像处理逻辑,包括加载、检测、绘制结果等方法。
- YOLOModel.cs:封装模型加载和推理功能。
关键技术
-
ONNX模型:
- 使用ONNX格式存储深度学习模型,支持跨平台部署。
- 通过ML.NET库在C#中加载和运行模型。
-
图像处理:
- 使用System.Drawing库进行图像绘制和操作。
- 在检测到的目标周围绘制边界框,并标注类别和置信度。
-
数据结构:
- ImageDataView:用于表示输入的图像数据,供模型推理使用。
- YoloBoundingBox:封装检测结果,包含目标标签、置信度及边界坐标。
实现步骤
1. 初始化
csharp
// 配置路径变量
string assetsPath = @"./Assets";
string modelFilePath = Path.Combine(assetsPath, "yolov2-tiny.onnx");
2. 加载数据
csharp
// 加载图像文件夹中的所有图像
var imageFiles = Directory.GetFiles(Path.Combine(assetsPath, "Images"), "*.jpg");
foreach (var imageFile in imageFiles)
{
var bitmap = new Bitmap(imageFile);
ProcessImage(bitmap); // 调用处理方法
}
3. 模型加载与推理
csharp
// 加载ONNX模型
var model = YoloModel.Load(modelFilePath);
foreach (var bitmap in images)
{
var predictions = model.Predict(bitmap); // 获取检测结果
ProcessPredictions(bitmap, predictions);
}
4. 结果可视化
csharp
private void ProcessPredictions(Bitmap image, List<YoloBoundingBox> predictions)
{
using (Graphics g = Graphics.FromImage(image))
{
foreach (var box in predictions)
{
// 绘制边界框和标签
DrawBoundingBox(g, box);
}
}
// 保存结果图像
string outputFilePath = Path.Combine(OutputFolderPath, image.FileName);
image.Save(outputFilePath, ImageFormat.Jpeg);
}
5. 边界框绘制
csharp
private void DrawBoundingBox(Graphics g, YoloBoundingBox box)
{
Font font = new Font("Arial", 10);
SolidBrush brush = new SolidBrush(Color.Black);
// 绘制矩形框
Pen pen = new Pen(box.Color, 2);
g.DrawRectangle(pen, box.X, box.Y, box.Width, box.Height);
// 绘制标签和置信度
string text = $"{box.Label} {box.Confidence:P2}";
SizeF textSize = g.MeasureString(text, font);
g.FillRectangle(brush, box.X, box.Y - textSize.Height, textSize.Width, textSize.Height);
g.DrawString(text, font, brush, box.X, box.Y - textSize.Height);
}
使用ONNX模型进行目标检测
随着深度学习技术的快速发展,目标检测已成为计算机视觉领域的重要任务。在实际应用中,高效、灵活的目标检测方法尤为重要。本文将详细解析如何使用**ONNX(Open Neural Network Exchange)**格式模型进行图像分类,并结合代码实现目标检测任务。
ONNX简介
-
什么是ONNX?
- ONNX 是一个开放的生态系统,旨在加速人工智能的民主化。
- 它提供了一个标准的表示方法,用于描述深度学习模型,使得不同框架(如TensorFlow、PyTorch等)之间的模型可以互相转换和共享。
- ONNX 的核心目标是简化模型部署流程,支持跨平台和多框架的应用。
-
ONNX的优势
- 跨框架兼容性:支持将模型从一个深度学习框架导出到另一个框架。
- 高效部署:通过标准化的表示方法,加速模型在不同硬件上的部署(如CPU、GPU等)。
项目目标
本文的目标是实现以下功能:
- 加载并使用预训练的ONNX模型进行图像分类。
- 对输入图像数据进行预处理(包括加载、调整大小和提取像素)。
- 执行模型推理,并从输出中提取结果。
使用ONNX模型进行目标检测代码解析
类结构与主要方法
以下是代码的核心类 OnnxModelScorer
的结构及功能:
类定义
csharp
public class OnnxModelScorer
{
// 私有字段:模型位置和图片文件夹路径
private string _modelLocation;
private string _imagesFolder;
public OnnxModelScorer(string modelLocation, string imagesFolder)
{
_modelLocation = modelLocation;
_imagesFolder = imagesFolder;
}
// 加载ONNX模型并构建评分管道
private ITransformer LoadModel()
{
// 实现细节见下文
}
// 使用模型对数据进行预测
private IEnumerable<float[]> PredictDataUsingModel(IDataView testData, ITransformer model)
{
// 实现细节见下文
}
// 公共接口:执行评分任务
public IEnumerable<float[]> Score(IDataView data)
{
var model = LoadModel();
return PredictDataUsingModel(data, model);
}
}
主要方法解析
-
构造函数
- 初始化模型路径和图片文件夹路径。
csharppublic OnnxModelScorer(string modelLocation, string imagesFolder) { _modelLocation = modelLocation; _imagesFolder = imagesFolder; }
-
LoadModel
方法- 加载ONNX模型并构建评分管道(包括图像预处理步骤)。
- 使用Microsoft ML库中的变换器完成数据预处理:
LoadImages
:从文件夹中加载图片。ResizeImages
:调整图片大小到指定尺寸(如224x224)。ExtractPixels
:将图像转换为像素矩阵。ApplyOnnxModel
:应用ONNX模型并执行推理。
csharpprivate ITransformer LoadModel() { Console.WriteLine("Read model"); Console.WriteLine($"Model location: {_modelLocation}"); Console.WriteLine($"Default parameters: image size=({ImageNetSettings.imageWidth},{ImageNetSettings.imageHeight})"); // 创建空的数据视图以获取输入数据模式 var data = mlContext.Data.LoadFromEnumerable(new List<ImageNetData>()); // 定义评分管道 var pipeline = mlContext.Transforms.LoadImages( outputColumnName: "image", imageFolder: _imagesFolder, inputColumnName: nameof(ImageNetData.ImagePath)) .Append(mlContext.Transforms.ResizeImages( outputColumnName: "image", imageWidth: ImageNetSettings.imageWidth, imageHeight: ImageNetSettings.imageHeight, inputColumnName: "image")) .Append(mlContext.Transforms.ExtractPixels( outputColumnName: "image")) .Append(mlContext.Transforms.ApplyOnnxModel( modelFile: _modelLocation, outputColumnNames: new[] { TinyYoloModelSettings.ModelOutput }, inputColumnNames: new[] { TinyYoloModelSettings.ModelInput })); // 拟合评分管道 var model = pipeline.Fit(data); return model; }
-
PredictDataUsingModel
方法- 使用已加载的模型对输入数据进行预测。
- 从模型输出中提取概率值。
csharpprivate IEnumerable<float[]> PredictDataUsingModel(IDataView testData, ITransformer model) { Console.WriteLine($"Images location: {_imagesFolder}"); Console.WriteLine(""); Console.WriteLine("=====Identify the objects in the images====="); Console.WriteLine(""); // 执行推理 var predictions = model.Transform(testData); return mlContext.Data.CreateEnumerable<float[]>(predictions, false).ToList(); }
-
Score
方法- 公共接口,用于执行完整的评分任务。
csharppublic IEnumerable<float[]> Score(IDataView data) { var model = LoadModel(); return PredictDataUsingModel(data, model); }
数据预处理
- 加载图片
- 使用
LoadImages
变换器从指定文件夹中加载图片。
- 使用
- 调整大小
- 使用
ResizeImages
将图片调整为统一尺寸(如224x224)。
- 使用
- 提取像素
- 使用
ExtractPixels
将图像转换为像素矩阵,以便输入模型。
- 使用
模型推理
- 应用ONNX模型
- 使用
ApplyOnnxModel
变换器加载并执行ONNX模型的推理过程。
- 使用
- 获取输出
- 从模型输出中提取概率值,并将其返回。
YOLO目标检测后处理
项目主要目的和原理
目标 :
YOLO(You Only Look Once)是一种实时目标检测算法,其核心目的是通过卷积神经网络直接预测边界框及其类别概率。模型输出的解析是将这些预测结果转化为可解释的目标检测结果的关键步骤。
原理 :
YOLO模型输出的是一个三维张量(特征图),每个位置包含多个候选边界框的信息,包括边界框的位置、置信度和类别概率。通过后处理步骤(如非极大值抑制NMS),我们可以过滤冗余的边界框并保留最优结果。
- 类结构与主要方法:
- 该类包含处理YOLO模型输出的主要逻辑,包括提取边界框、计算置信度以及执行非极大值抑制(NMS)等步骤。
- ParseOutputs方法:
- 输入 :模型输出的float数组
yoloModelOutputs
和置信度阈值threshold
。 - 功能:
- 遍历每个网格单元及其预测框,提取边界框参数、计算置信度,并映射到图像坐标系。
- 对满足条件的检测结果进行存储。
- 循环结构:
- 三重嵌套循环分别处理行、列和每个预测框,确保覆盖所有可能的目标检测结果。
- Channel计算:
channel = box * (CLASS_COUNT + BOX_INFO_FEATURE_COUNT)
:定位当前处理的预测框在模型输出数组中的起始位置。
- 边界框提取与映射:
ExtractBoundingBoxDimensions
方法从模型输出中获取边界框参数。MapBoundingBoxToCell
方法将相对坐标转换为图像绝对坐标,通常涉及网格单元大小和偏移量计算。
- 置信度与类别概率处理:
- 使用
GetConfidence
获取预测框的置信度,并检查是否高于阈值。 - 通过
ExtractClasses
提取类别概率分布,结合GetTopResult
确定最高概率类别及其分数。
- 结果存储:
- 将满足条件的检测结果以边界框形式添加到输出列表中,并设置对应的颜色信息。
- FilterBoundingBoxes方法(NMS):
- 输入 :待处理的目标框列表
boxes
和重叠阈值threshold
。 - 功能:
- 按置信度排序,逐个处理每个框,抑制与其重叠超过阈值的其他框。
- 实现细节:
- 通过双重循环比较每对框的重叠情况,使用交并比(IoU)判断是否需要抑制。
- 将标记为无效的框从结果列表中移除。
- 总结:
- 该代码实现了完整的YOLO检测后处理流程,包括坐标转换、置信度筛选和NMS优化,确保输出高质量的目标检测结果。
项目概述
主要功能:
- 解析YOLO模型输出的特征图,提取候选边界框及其属性(位置、置信度、类别)。
- 过滤低置信度和重叠的边界框,以获得最终检测结果。
实现的主要流程步骤:
- 解析输出:将模型输出张量转换为边界框列表,每个边界框包含其位置、置信度和类别信息。
- 过滤边界框:使用非极大值抑制(NMS)算法去除重叠的低置信度边界框。
关键技术:
- 数据结构设计:用于存储边界框及其属性的数据结构。
- 非极大值抑制(NMS):用于筛选最优边界框的核心算法。
- 输出解析逻辑:将模型输出转换为可解释结果的关键步骤。
主要功能和步骤
1. 解析输出(ParseOutputs)
功能解读 :
将YOLO模型输出的张量转换为边界框列表。每个边界框包含其位置、置信度和类别信息。
实现步骤:
- 输入数据结构 :模型输出是一个三维张量,形状为
(grid_height, grid_width, num_boxes_per_grid * (4 + 1 + num_classes))
。 - 提取边界框属性:遍历每个网格点,提取所有候选边界框的位置(中心坐标、宽度、高度)、置信度和类别概率。
- 计算总置信度:类别预测分数与边界盒存在概率相乘,得到最终置信度。
代码结构及语法解读:
python
def parse_outputs(outputs, num_classes, anchors):
boxes = []
grid_size = outputs.shape[0]
for i in range(grid_size):
for j in range(grid_size):
# 遍历每个网格点的所有边界框
for k in range(len(anchors)):
# 提取边界框的位置信息
tx, ty, tw, th = outputs[i][j][k*6:k*6+4]
# 计算中心坐标
x_center = (j + sigmoid(tx)) / grid_size * image_width
y_center = (i + sigmoid(ty)) / grid_size * image_height
# 计算宽度和高度
w = anchors[k][0] * exp(tw) / grid_size * image_width
h = anchors[k][1] * exp(th) / grid_size * image_height
# 提取置信度
box_confidence = sigmoid(outputs[i][j][k*6+4])
# 提取类别概率
class_probs = outputs[i][j][k*6+5 : k*6+5 + num_classes]
top_score, class_idx = max(class_probs), argmax(class_probs)
# 计算总置信度
total_confidence = box_confidence * top_score
boxes.append({
'x_center': x_center,
'y_center': y_center,
'width': w,
'height': h,
'class_idx': class_idx,
'confidence': total_confidence
})
return boxes
关键点分析:
- 模型输出的每个网格点包含多个候选边界框(由锚框决定)。
- 边界框的位置坐标需要通过模型预测值和网格点位置进行转换。
- 总置信度是类别概率与边界框存在概率的乘积,用于后续筛选。
2. 过滤边界框(FilterBoundingBoxes)
功能解读 :
使用非极大值抑制算法去除冗余的边界框,保留最优结果。
实现步骤:
- 按置信度排序:将所有边界框按总置信度从高到低排序。
- 逐个处理边界框:从最高置信度开始,标记其为有效边界框,并去除与其重叠度过高的其他边界框。
代码结构及语法解读:
python
def filter_bounding_boxes(boxes, iou_threshold):
# 按置信度排序
boxes_sorted = sorted(boxes, key=lambda x: -x['confidence'])
active_boxes = []
for box in boxes_sorted:
# 计算与已保留边界框的IOU
overlap = False
for active_box in active_boxes:
iou = compute_iou(box, active_box)
if iou > iou_threshold:
overlap = True
break
if not overlap:
active_boxes.append(box)
return active_boxes
def compute_iou(box1, box2):
# 计算两个边界框的交集面积
x1 = max(box1['x_center'] - box1['width']/2, box2['x_center'] - box2['width']/2)
y1 = max(box1['y_center'] - box1['height']/2, box2['y_center'] - box2['height']/2)
x2 = min(box1['x_center'] + box1['width']/2, box2['x_center'] + box2['width']/2)
y2 = min(box1['y_center'] + box1['height']/2, box2['y_center'] + box2['height']/2)
if x2 <= x1 or y2 <= y1:
return 0.0
intersection_area = (x2 - x1) * (y2 - y1)
union_area = (box1['width'] * box1['height']) + (box2['width'] * box2['height']) - intersection_area
return intersection_area / union_area
关键点分析:
- IOU(交并比)用于衡量两个边界框的重叠程度。
- 通过设置IOU阈值,可以控制筛选的严格程度。
技术总结
- 数据结构设计:使用字典存储边界框的属性信息,便于后续处理和计算。
- 非极大值抑制(NMS):核心算法用于去除冗余边界框,提升检测结果的质量。
- 输出解析逻辑:将模型输出转换为可解释的结果,是整个流程的关键步骤。
通过以上实现,可以有效地从YOLO模型的输出中提取并筛选出高质量的目标检测结果。
总结
本文详细解析了如何使用ONNX格式的深度学习模型进行图像分类任务。通过Microsoft ML库提供的工具,我们可以轻松实现以下功能:
- 加载并预处理输入图像。
- 使用ONNX模型执行推理。
- 从模型输出中提取结果。
这种方法不仅高效灵活,还支持跨框架和多硬件平台的应用,为实际部署提供了极大的便利。
本项目通过C#和ONNX实现了基于YOLO的目标检测系统。从图像加载到结果可视化,整个流程清晰且高效。特别适合需要在Windows环境下运行的场景,或者需要与现有C#代码集成的情况。
未来可以进一步优化模型性能、支持更多目标类别以及提升处理速度,以满足更复杂的需求。