马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。
您需要 登录 才可以下载或查看,没有账号?立即注册
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 模子,并用它对图片举行推理。
- #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 模子,你可以快速对一批图像举行目的检测,并保存检测到缺陷的图像。通过合理的内存管理和性能优化,本步伐可以大概高效地处理大量图像,并输出检测结果。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。 |