C++ 通过 OpenCV 调用 YOLOv8 ONNX 模型进行图像缺陷检测
在现代计算机视觉领域,YOLO(You Only Look Once)是一种高效的物体检测方法,广泛应用于实时目标检测。YOLOv8 采用更为高效的架构和算法,提供更精确的检测结果。在本文中,我们将介绍如何使用 OpenCV 和 C++ 通过 ONNX 模型进行 YOLOv8 目标检测。
1. 下载 OpenCV
- 访问 OpenCV 官网:https://opencv.org/releases/。
- 下载适用于 Windows 的 OpenCV 版本。推荐下载的是
.exe
安装包,通常是opencv-4.x.x-vc15.exe
(对于 Visual Studio 2015+ 的版本)。 - 安装并解压 OpenCV 至指定目录(例如
C:\opencv
)。
2. 在 Visual Studio 中配置 OpenCV
安装 OpenCV 后,配置 Visual Studio:
附加包含目录:添加 OpenCV 的 include
目录,例如:
附加库目录:添加 OpenCV 的 lib
目录,例如:
链接 OpenCV 库:
- 选择 链接器 -> 输入 -> 附加依赖项,并添加 OpenCV 的库文件(例如
opencv_world410d.lib
或opencv_world410.lib
,取决于 Debug 或 Release 模式)。 - 对于 Debug 模式,通常需要使用带有
d
后缀的版本(例如opencv_world410d.lib
)。
使用 C++17 标准:
3. 编写 C++ 代码使用 OpenCV 加载和测试模型
假设你已经下载了一个预训练的深度学习模型(如 .onnx
格式的模型),下面是一个使用 OpenCV dnn
模块来加载模型并进行图片检测的示例代码。
以下示例代码展示了如何加载一个 .onnx
模型,并用它对图片进行推理。
#include <opencv2/opencv.hpp>
#include <opencv2/dnn.hpp>
#include <iostream>
#include <filesystem>
#include <fstream>
#include <string>
#include <vector>
#include <ctime>
namespace fs = std::filesystem;
int main() {
// CUDA检查
std::cout << "OpenCV Version: " << CV_VERSION << std::endl;
std::cout << "CUDA Available: " << cv::cuda::getCudaEnabledDeviceCount() << std::endl;
// 输入和输出路径
std::string input_folder = "D:/BaiduNetdiskDownload/TEST"; // 替换为你的输入文件夹路径
std::string output_folder = "D:/BaiduNetdiskDownload/TEST_RESULTS"; // 替换为你的输出文件夹路径
// 创建输出文件夹
fs::create_directories(output_folder);
// 加载YOLOv8 ONNX模型
std::string modelPath = "D:/yolov8n.onnx"; // 替换为你的YOLOv8 ONNX模型路径
cv::dnn::Net net = cv::dnn::readNetFromONNX(modelPath);
if (net.empty()) {
std::cerr << "Failed to load the model!" << std::endl;
return -1;
}
// 设置置信度阈值
float confThreshold = 0.25f;
// 遍历文件夹中的图片
for (const auto& entry : fs::directory_iterator(input_folder)) {
if (entry.is_regular_file() && entry.path().extension() == ".jpg") {
std::string input_path = entry.path().string();
// 开始计时
clock_t start_time = clock();
// 读取图像
cv::Mat img = cv::imread(input_path);
if (img.empty()) {
std::cerr << "无法加载图片: " << input_path << std::endl;
continue;
}
// 图像预处理:将图片调整为640x640并转换为blob
cv::Mat blob;
cv::dnn::blobFromImage(img, blob, 1.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
net.setInput(blob);
// 获取模型输出
std::vector<cv::Mat> outputs;
net.forward(outputs, net.getUnconnectedOutLayersNames());
// 检测结果处理
bool has_defect = false; // 是否检测到缺陷
for (size_t i = 0; i < outputs.size(); ++i) {
cv::Mat& output = outputs[i];
for (int j = 0; j < output.rows; ++j) {
float* data = (float*)output.data + j * output.cols;
// 置信度
float confidence = data[4];
if (confidence > confThreshold) {
// 类别ID
int classId = -1;
float* classScores = data + 5;
cv::Point classIdPoint;
double classConfidence;
cv::minMaxLoc(cv::Mat(1, output.cols - 5, CV_32F, classScores), nullptr, &classConfidence, nullptr, &classIdPoint);
classId = classIdPoint.x;
// 边界框坐标
int x1 = (int)(data[0] * img.cols);
int y1 = (int)(data[1] * img.rows);
int x2 = (int)(data[2] * img.cols);
int y2 = (int)(data[3] * img.rows);
// 保证边界框在图片范围内
x1 = std::max(0, x1);
y1 = std::max(0, y1);
x2 = std::min(img.cols, x2);
y2 = std::min(img.rows, y2);
// 绘制矩形框
cv::rectangle(img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 0, 255), 2);
std::string label = "Class: " + std::to_string(classId) + " Conf: " + std::to_string(confidence);
cv::putText(img, label, cv::Point(x1, y1 - 10), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255, 0, 0), 2);
has_defect = true; // 标记为有缺陷
}
}
}
// 仅保存有缺陷的图片
if (has_defect) {
std::string save_path = output_folder + "/" + entry.path().filename().string();
cv::imwrite(save_path, img);
clock_t end_time = clock();
double elapsed_time_ms = (double)(end_time - start_time) / CLOCKS_PER_SEC * 1000;
std::cout << "图片: " << entry.path().filename() << " | 耗时: " << elapsed_time_ms << " 毫秒 | 已保存检测结果。" << std::endl;
} else {
std::cout << "图片: " << entry.path().filename() << " 未检测到缺陷,跳过保存。" << std::endl;
}
// 释放内存
img.release();
blob.release();
}
}
std::cout << "检测完成!检测结果已保存到: " << output_folder << std::endl;
return 0;
}
代码说明
-
加载 YOLOv8 模型:使用
cv::dnn::readNetFromONNX()
函数加载 YOLOv8 的 ONNX 模型。如果模型加载失败,程序会输出错误信息并退出。 -
图像预处理:通过
cv::dnn::blobFromImage()
将输入图像转换为适合 YOLO 模型的输入格式(大小调整为 640x640,且进行归一化)。然后使用net.setInput()
将图像输入到神经网络中。 -
推理与输出:使用
net.forward()
获取模型的输出(即检测结果)。每个输出包含了预测的边界框、置信度和类别。 -
检测与标注:遍历每个输出,提取出置信度大于设定阈值的检测框,并绘制边界框和类别标签。
-
保存结果:如果检测到缺陷,程序会保存处理后的图像到指定输出目录。保存的文件名与输入文件名相同。
-
释放内存:在每次处理完图像后,显式调用
img.release()
和blob.release()
释放内存,避免内存泄漏。
性能优化
-
CUDA 加速:如果你的计算机支持 CUDA,并且 OpenCV 已经配置了 CUDA 支持,你可以通过 CUDA 加速 DNN 推理过程。可以通过
cv::cuda::getCudaEnabledDeviceCount()
检查可用的 GPU 数量。 -
图像和内存管理:通过显式调用
release()
释放图像和 blob 对象的内存,确保内存不会泄漏,特别是在处理大量图像时尤为重要。
总结
通过 OpenCV 和 C++ 调用 YOLOv8 ONNX 模型,你可以快速对一批图像进行目标检测,并保存检测到缺陷的图像。通过合理的内存管理和性能优化,本程序能够高效地处理大量图像,并输出检测结果。
原文地址:https://blog.csdn.net/m0_58648890/article/details/144193186
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!