C++ 通过 OpenCV 调用 YOLOv8 ONNX 模子举行图像缺陷检测

一给  金牌会员 | 2024-12-6 22:09:20 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 994|帖子 994|积分 2982

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在现代盘算机视觉领域,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 模子,并用它对图片举行推理。
  1. #include <opencv2/opencv.hpp>
  2. #include <opencv2/dnn.hpp>
  3. #include <iostream>
  4. #include <filesystem>
  5. #include <fstream>
  6. #include <string>
  7. #include <vector>
  8. #include <ctime>
  9. namespace fs = std::filesystem;
  10. int main() {
  11.     // CUDA检查
  12.     std::cout << "OpenCV Version: " << CV_VERSION << std::endl;
  13.     std::cout << "CUDA Available: " << cv::cuda::getCudaEnabledDeviceCount() << std::endl;
  14.     // 输入和输出路径
  15.     std::string input_folder = "D:/BaiduNetdiskDownload/TEST";  // 替换为你的输入文件夹路径
  16.     std::string output_folder = "D:/BaiduNetdiskDownload/TEST_RESULTS";  // 替换为你的输出文件夹路径
  17.     // 创建输出文件夹
  18.     fs::create_directories(output_folder);
  19.     // 加载YOLOv8 ONNX模型
  20.     std::string modelPath = "D:/yolov8n.onnx";  // 替换为你的YOLOv8 ONNX模型路径
  21.     cv::dnn::Net net = cv::dnn::readNetFromONNX(modelPath);
  22.     if (net.empty()) {
  23.         std::cerr << "Failed to load the model!" << std::endl;
  24.         return -1;
  25.     }
  26.     // 设置置信度阈值
  27.     float confThreshold = 0.25f;
  28.     // 遍历文件夹中的图片
  29.     for (const auto& entry : fs::directory_iterator(input_folder)) {
  30.         if (entry.is_regular_file() && entry.path().extension() == ".jpg") {
  31.             std::string input_path = entry.path().string();
  32.             // 开始计时
  33.             clock_t start_time = clock();
  34.             
  35.             // 读取图像
  36.             cv::Mat img = cv::imread(input_path);
  37.             if (img.empty()) {
  38.                 std::cerr << "无法加载图片: " << input_path << std::endl;
  39.                 continue;
  40.             }
  41.             // 图像预处理:将图片调整为640x640并转换为blob
  42.             cv::Mat blob;
  43.             cv::dnn::blobFromImage(img, blob, 1.0, cv::Size(640, 640), cv::Scalar(0, 0, 0), true, false);
  44.             net.setInput(blob);
  45.             // 获取模型输出
  46.             std::vector<cv::Mat> outputs;
  47.             net.forward(outputs, net.getUnconnectedOutLayersNames());
  48.             // 检测结果处理
  49.             bool has_defect = false;  // 是否检测到缺陷
  50.             for (size_t i = 0; i < outputs.size(); ++i) {
  51.                 cv::Mat& output = outputs[i];
  52.                 for (int j = 0; j < output.rows; ++j) {
  53.                     float* data = (float*)output.data + j * output.cols;
  54.                     // 置信度
  55.                     float confidence = data[4];
  56.                     if (confidence > confThreshold) {
  57.                         // 类别ID
  58.                         int classId = -1;
  59.                         float* classScores = data + 5;
  60.                         cv::Point classIdPoint;
  61.                         double classConfidence;
  62.                         cv::minMaxLoc(cv::Mat(1, output.cols - 5, CV_32F, classScores), nullptr, &classConfidence, nullptr, &classIdPoint);
  63.                         classId = classIdPoint.x;
  64.                         // 边界框坐标
  65.                         int x1 = (int)(data[0] * img.cols);
  66.                         int y1 = (int)(data[1] * img.rows);
  67.                         int x2 = (int)(data[2] * img.cols);
  68.                         int y2 = (int)(data[3] * img.rows);
  69.                         // 保证边界框在图片范围内
  70.                         x1 = std::max(0, x1);
  71.                         y1 = std::max(0, y1);
  72.                         x2 = std::min(img.cols, x2);
  73.                         y2 = std::min(img.rows, y2);
  74.                         // 绘制矩形框
  75.                         cv::rectangle(img, cv::Point(x1, y1), cv::Point(x2, y2), cv::Scalar(0, 0, 255), 2);
  76.                         std::string label = "Class: " + std::to_string(classId) + " Conf: " + std::to_string(confidence);
  77.                         cv::putText(img, label, cv::Point(x1, y1 - 10), cv::FONT_HERSHEY_SIMPLEX, 0.7, cv::Scalar(255, 0, 0), 2);
  78.                         
  79.                         has_defect = true;  // 标记为有缺陷
  80.                     }
  81.                 }
  82.             }
  83.             // 仅保存有缺陷的图片
  84.             if (has_defect) {
  85.                 std::string save_path = output_folder + "/" + entry.path().filename().string();
  86.                 cv::imwrite(save_path, img);
  87.                 clock_t end_time = clock();
  88.                 double elapsed_time_ms = (double)(end_time - start_time) / CLOCKS_PER_SEC * 1000;
  89.                 std::cout << "图片: " << entry.path().filename() << " | 耗时: " << elapsed_time_ms << " 毫秒 | 已保存检测结果。" << std::endl;
  90.             } else {
  91.                 std::cout << "图片: " << entry.path().filename() << " 未检测到缺陷,跳过保存。" << std::endl;
  92.             }
  93.             // 释放内存
  94.             img.release();
  95.             blob.release();
  96.         }
  97.     }
  98.     std::cout << "检测完成!检测结果已保存到: " << output_folder << std::endl;
  99.     return 0;
  100. }
复制代码
代码说明


  • 加载 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 模子,你可以快速对一批图像举行目的检测,并保存检测到缺陷的图像。通过合理的内存管理和性能优化,本步伐可以大概高效地处理大量图像,并输出检测结果。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表