使用OpenCV dnn c++加載YOLOv8生成的onnx文件進行目標檢測

? ? ? 在網上下載了60多幅包含西瓜和冬瓜的圖像組成melon數據集,使用?LabelMe? 工具進行標注,然后使用?labelme2yolov8?腳本將json文件轉換成YOLOv8支持的.txt文件,并自動生成YOLOv8支持的目錄結構,包括melon.yaml文件,其內容如下:

path: ../datasets/melon # dataset root dir
train: images/train # train images (relative to 'path')
val: images/val  # val images (relative to 'path')
test: # test images (optional)# Classes
names:0: watermelon1: wintermelon

? ? ? 使用以下python腳本進行訓練生成onnx文件

import argparse
import colorama
from ultralytics import YOLOdef parse_args():parser = argparse.ArgumentParser(description="YOLOv8 object detect")parser.add_argument("--yaml", required=True, type=str, help="yaml file")parser.add_argument("--epochs", required=True, type=int, help="number of training")args = parser.parse_args()return argsdef train(yaml, epochs):model = YOLO("yolov8n.pt") # load a pretrained modelresults = model.train(data=yaml, epochs=epochs, imgsz=640) # train the modelmetrics = model.val() # It'll automatically evaluate the data you trained, no arguments needed, dataset and settings rememberedmodel.export(format="onnx") #, dynamic=True) # export the model, cannot specify dynamic=True, opencv does not support# model.export(format="onnx", opset=12, simplify=True, dynamic=False, imgsz=640)model.export(format="torchscript") # libtorchif __name__ == "__main__":colorama.init()args = parse_args()train(args.yaml, args.epochs)print(colorama.Fore.GREEN + "====== execution completed ======")

? ? ? 使用OpenCV 4.9.0庫,生成庫的shell腳本build.sh如下:windows上包括cpu和gpu,cuda版本為11.8,cudnn版本為對應的v8.9.7版本,將cudnn的bin, include, lib/x64三個目錄內容分別拷貝對應cuda 11.8相應目錄下

#! /bin/bashif [ $# != 2 ]; thenecho "Error: requires two parameters: 1: windows windows_cuda or linux; 2: relese or debug"echo "For example: $0 windows debug"exit -1
fiif [ $1 != "windows" ] && [ $1 != "windows_cuda" ] && [ $1 != "linux" ]; thenecho "Error: the first parameter can only be windows or linux"exit -1
fiif [ $2 != "release"  ] && [ $2 != "debug" ]; thenecho "Error: the second parameter can only be release or debug"exit -1
fiif [[ ! -d "build" ]]; thenmkdir buildcd build
elsecd build
fiif [ $2 == "release" ]; thenbuild_type="Release"
elsebuild_type="Debug"
fi# copy the contents of the bin,include,lib/x64 cudnn directories to the corresponding CUDA directories
if [ $1 == "windows_cuda" ]; thencuda_options="-DWITH_CUDA=ON \-DWITH_CUDNN=ON \-DCUDA_FAST_MATH=ON \-DWITH_CUBLAS=ON"
elsecuda_options=""
fiif [ $1 == "windows" ] || [ $1 == "windows_cuda" ]; thencmake \-G"Visual Studio 17 2022" -A x64 \${cuda_options} \-DCMAKE_BUILD_TYPE=${build_type} \-DCMAKE_CONFIGURATION_TYPES=${build_type} \-DBUILD_SHARED_LIBS=ON \-DBUILD_opencv_world=ON \-DBUILD_PERF_TESTS=OFF \-DBUILD_TESTS=OFF \-DCMAKE_INSTALL_PREFIX=../install \-DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \..cmake --build . --target install --config $2
fiif [ $1 == "linux" ]; thencmake \-DCMAKE_C_COMPILER=/usr/bin/gcc \-DCMAKE_CXX_COMPILER=/usr/bin/g++ \-DCMAKE_BUILD_TYPE=${build_type} \-DBUILD_SHARED_LIBS=ON \-DBUILD_opencv_world=ON \-DBUILD_PERF_TESTS=OFF \-DBUILD_TESTS=OFF \-DCMAKE_INSTALL_PREFIX=../install \-DOPENCV_EXTRA_MODULES_PATH=../../opencv_contrib/modules \..make -j2make install
firc=$?
if [[ ${rc} != 0 ]]; thenecho -e "\033[0;31mError: there are some errors in the above operation, please check: ${rc}\033[0m"exit ${rc}
fi

? ? ? 以下是使用opencv dnn接口加載onnx文件進行目標檢測的實現代碼:由變量cuda_enabled指定是執行cpu還是gpu

namespace {constexpr bool cuda_enabled{ false };
constexpr int image_size[2]{ 640, 640 }; // {height,width}, input shape (1, 3, 640, 640) BCHW and output shape(s) (1, 6, 8400)
constexpr float model_score_threshold{ 0.45 }; // confidence threshold
constexpr float model_nms_threshold{ 0.50 }; // iou threshold#ifdef _MSC_VER
constexpr char* onnx_file{ "../../../data/best.onnx" };
constexpr char* torchscript_file{ "../../../data/best.torchscript" };
constexpr char* images_dir{ "../../../data/images/predict" };
constexpr char* result_dir{ "../../../data/result" };
constexpr char* classes_file{ "../../../data/images/labels.txt" };
#else
constexpr char* onnx_file{ "data/best.onnx" };
constexpr char* torchscript_file{ "data/best.torchscript" };
constexpr char* images_dir{ "data/images/predict" };
constexpr char* result_dir{ "data/result" };
constexpr char* classes_file{ "data/images/labels.txt" };
#endifcv::Mat modify_image_size(const cv::Mat& img)
{auto max = std::max(img.rows, img.cols);cv::Mat ret = cv::Mat::zeros(max, max, CV_8UC3);img.copyTo(ret(cv::Rect(0, 0, img.cols, img.rows)));return ret;
}std::vector<std::string> parse_classes_file(const char* name)
{std::vector<std::string> classes;std::ifstream file(name);if (!file.is_open()) {std::cerr << "Error: fail to open classes file: " << name << std::endl;return classes;}std::string line;while (std::getline(file, line)) {auto pos = line.find_first_of(" ");classes.emplace_back(line.substr(0, pos));}file.close();return classes;
}auto get_dir_images(const char* name)
{std::map<std::string, std::string> images; // image name, image path + image namefor (auto const& dir_entry : std::filesystem::directory_iterator(name)) {if (dir_entry.is_regular_file())images[dir_entry.path().filename().string()] = dir_entry.path().string();}return images;
}void draw_boxes(const std::vector<std::string>& classes, const std::vector<int>& ids, const std::vector<float>& confidences,const std::vector<cv::Rect>& boxes, const std::string& name, cv::Mat& frame)
{if (ids.size() != confidences.size() || ids.size() != boxes.size() || confidences.size() != boxes.size()) {std::cerr << "Error: their lengths are inconsistent: " << ids.size() << ", " << confidences.size() << ", " << boxes.size() << std::endl;return;}std::cout << "image name: " << name << ", number of detections: " << ids.size() << std::endl;std::random_device rd;std::mt19937 gen(rd());std::uniform_int_distribution<int> dis(100, 255);for (auto i = 0; i < ids.size(); ++i) {auto color = cv::Scalar(dis(gen), dis(gen), dis(gen));cv::rectangle(frame, boxes[i], color, 2);std::string class_string = classes[ids[i]] + ' ' + std::to_string(confidences[i]).substr(0, 4);cv::Size text_size = cv::getTextSize(class_string, cv::FONT_HERSHEY_DUPLEX, 1, 2, 0);cv::Rect text_box(boxes[i].x, boxes[i].y - 40, text_size.width + 10, text_size.height + 20);cv::rectangle(frame, text_box, color, cv::FILLED);cv::putText(frame, class_string, cv::Point(boxes[i].x + 5, boxes[i].y - 10), cv::FONT_HERSHEY_DUPLEX, 1, cv::Scalar(0, 0, 0), 2, 0);}cv::imshow("Inference", frame);cv::waitKey(-1);std::string path(result_dir);path += "/" + name;cv::imwrite(path, frame);
}} // namespaceint test_yolov8_detect_opencv()
{// reference: ultralytics/examples/YOLOv8-CPP-Inferencenamespace fs = std::filesystem;auto net = cv::dnn::readNetFromONNX(onnx_file);if (net.empty()) {std::cerr << "Error: there are no layers in the network: " << onnx_file << std::endl;return -1;}if (cuda_enabled) {net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);} else {net.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);}if (!fs::exists(result_dir)) {fs::create_directories(result_dir);}auto classes = parse_classes_file(classes_file);if (classes.size() == 0) {std::cerr << "Error: fail to parse classes file: " << classes_file << std::endl;return -1;}std::cout << "classes: ";for (const auto& val : classes) {std::cout << val << " ";}std::cout << std::endl;for (const auto& [key, val] : get_dir_images(images_dir)) {cv::Mat frame = cv::imread(val, cv::IMREAD_COLOR);if (frame.empty()) {std::cerr << "Warning: unable to load image: " << val << std::endl;continue;}cv::Mat bgr = modify_image_size(frame);cv::Mat blob;cv::dnn::blobFromImage(bgr, blob, 1.0 / 255.0, cv::Size(image_size[1], image_size[0]), cv::Scalar(), true, false);net.setInput(blob);std::vector<cv::Mat> outputs;net.forward(outputs, net.getUnconnectedOutLayersNames());int rows = outputs[0].size[1];int dimensions = outputs[0].size[2];// yolov5 has an output of shape (batchSize, 25200, num classes+4+1) (Num classes + box[x,y,w,h] + confidence[c])// yolov8 has an output of shape (batchSize, num classes + 4,  8400) (Num classes + box[x,y,w,h])if (dimensions > rows) { // Check if the shape[2] is more than shape[1] (yolov8)rows = outputs[0].size[2];dimensions = outputs[0].size[1];outputs[0] = outputs[0].reshape(1, dimensions);cv::transpose(outputs[0], outputs[0]);}float* data = (float*)outputs[0].data;float x_factor = bgr.cols * 1.f / image_size[1];float y_factor = bgr.rows * 1.f / image_size[0];std::vector<int> class_ids;std::vector<float> confidences;std::vector<cv::Rect> boxes;for (auto i = 0; i < rows; ++i) {float* classes_scores = data + 4;cv::Mat scores(1, classes.size(), CV_32FC1, classes_scores);cv::Point class_id;double max_class_score;cv::minMaxLoc(scores, 0, &max_class_score, 0, &class_id);if (max_class_score > model_score_threshold) {confidences.push_back(max_class_score);class_ids.push_back(class_id.x);float x = data[0];float y = data[1];float w = data[2];float h = data[3];int left = int((x - 0.5 * w) * x_factor);int top = int((y - 0.5 * h) * y_factor);int width = int(w * x_factor);int height = int(h * y_factor);boxes.push_back(cv::Rect(left, top, width, height));}data += dimensions;}std::vector<int> nms_result;cv::dnn::NMSBoxes(boxes, confidences, model_score_threshold, model_nms_threshold, nms_result);std::vector<int> ids;std::vector<float> confs;std::vector<cv::Rect> rects;for (size_t i = 0; i < nms_result.size(); ++i) {ids.emplace_back(class_ids[nms_result[i]]);confs.emplace_back(confidences[nms_result[i]]);rects.emplace_back(boxes[nms_result[i]]);}draw_boxes(classes, ids, confs, rects, key, frame);}return 0;
}

? ? ? labels.txt文件內容如下:僅2類

watermelon 0
wintermelon 1

? ? ? 執行結果如下圖所示:

? ? ? 其中一幅圖像的檢測結果如下圖所示:

? ? ? GitHub:https://github.com/fengbingchun/NN_Test

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/15304.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/15304.shtml
英文地址,請注明出處:http://en.pswp.cn/web/15304.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

信息系統管理工程師問答題

信息系統管理工程師問答題 系統管理安全兩方面 安全測試 入侵檢測系統的功能 用戶標識與驗證常用的3種方法 (1) 要求用戶輸入一些保密信息&#xff0c;例如用戶名稱和密碼&#xff1b; (2) 采用物理識別設備&#xff0c;例如訪問卡、鑰匙或令牌&#xff1b; (3) 采用生物統計學…

Python怎樣定位并刪除Sql語句中不確定的查詢條件

1.問題場景描述: 在sql語句中經常會有查詢條件是:查找多個訂單簽訂日期范圍的數據,但具體的日期范圍是不確定,我們如何來查找定位 例如:查詢條件語句的部分如下圖: 目標是: 1)定位字符串:t_contract_order.sign_date 2)最終得到結果: 解決問題思路: 1)定位要找的字符串起始位置…

【學習心得】PyTorch的知識要點復習(持續更新)

PyTorch知識要點復習&#xff0c;目的是為了鞏固PyTorch基礎、快速回顧、深化理解PyTorch框架。這篇文章會持續更新。 一、本文的一些說明 知識點梳理&#xff1a;我將PyTorch的核心概念和高級技巧進行了系統化的整理&#xff0c;從基礎的張量操作到復雜的模型構建與訓練。這樣…

【Linux】進程終止與進程等待

目錄 進程終止 errno exit和_exit 進程等待 wait和waitpid 宏&#xff1a;WIFEXITED 非阻塞等待 進程終止 下面要談的一個話題就是進程終止&#xff0c;就是說一個進程退出了&#xff0c;可能有三種情況 1.進程代碼執行完&#xff0c;結果是正確的 2.進程代碼執行完&…

【九十二】【算法分析與設計】875. 愛吃香蕉的珂珂,410. 分割數組的最大值,機器人跳躍問題,二分答案法

875. 愛吃香蕉的珂珂 - 力扣&#xff08;LeetCode&#xff09; 珂珂喜歡吃香蕉。這里有 n 堆香蕉&#xff0c;第 i 堆中有 piles[i] 根香蕉。警衛已經離開了&#xff0c;將在 h 小時后回來。 珂珂可以決定她吃香蕉的速度 k &#xff08;單位&#xff1a;根/小時&#xff09;。每…

【活動】開源與閉源大模型:探索未來趨勢的雙軌道路

&#x1f308;個人主頁: 鑫寶Code &#x1f525;熱門專欄: 閑話雜談&#xff5c; 炫酷HTML | JavaScript基礎 ?&#x1f4ab;個人格言: "如無必要&#xff0c;勿增實體" 文章目錄 開源與閉源大模型&#xff1a;探索未來趨勢的雙軌道路引言一、開源大模型&#…

翻譯《The Old New Thing》- The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag

The importance of the FORMAT_MESSAGE_IGNORE_INSERTS flag - The Old New Thing (microsoft.com)https://devblogs.microsoft.com/oldnewthing/20071128-00/?p24353 Raymond Chen 2007年11月28日 FORMAT_MESSAGE_IGNORE_INSERTS 標志的重要性 簡要 文章討論了使用FormatMes…

評估企業的業務是否存在高風險的六個步驟

風險的幽靈使得組織別無選擇&#xff0c;只能改善各種網絡風險的總體管理。以下是一個基于信息安全論壇的IRAM2方法論的分步過程&#xff0c;網絡安全和風險從業者可以利用它來評估和管理信息風險。 第1步&#xff1a;范圍界定練習 范圍界定練習的目標是提供一個以業務為中心…

基于springboot+vue的招聘信息管理系統

開發語言&#xff1a;Java框架&#xff1a;springbootJDK版本&#xff1a;JDK1.8服務器&#xff1a;tomcat7數據庫&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09;數據庫工具&#xff1a;Navicat11開發軟件&#xff1a;eclipse/myeclipse/ideaMaven包&#xff1a;…

K8s的常用命令以及yaml文件的創建

目錄 一、聲明式管理方法&#xff1a;YAML文件 1、yaml文件簡介 2、yaml和json的主要區別&#xff1a; 3、YAML的語法格式 4、yaml文件組成部分 ①控制器定義 5、查看api資源版本標簽 6、編寫nginx-deployment.yaml資源配置清單 6.1創建資源對象 6.2查看創建的pod資源…

使用python將一段文本寫入一個txt文件中且先格式化文件名

有一段文本內容&#xff0c;有“標題”和“內容”組成。 任務&#xff1a;要將這段文本&#xff0c;存放到一個txt文件中&#xff0c;文件名為當天的日期加上“標題”內容。因為“標題”內可能有/<>之類的&#xff0c;還需要格式化一下。 已經將上述功能都寫成了函數&a…

安卓手機APP開發__近距離無線通信(NFC)概述

安卓手機&#xff21;&#xff30;&#xff30;開發&#xff3f;&#xff3f;近距離無線通信(NFC)概述 概述 近距離無線通信 (NFC) 是一組近距離無線技術&#xff0c;距離通常不超過 4 厘米才能 發起連接。通過 NFC&#xff0c;您可以在 NFC 標簽和 Android 設備之間&#xf…

【Redis】 String類型的內部編碼與使用環境

文章目錄 &#x1f343;前言&#x1f334;內部編碼&#x1f384;典型使用場景&#x1f6a9;緩存功能&#x1f6a9;計數&#xff08;Counter&#xff09;功能&#x1f6a9;共享會話&#xff08;Session&#xff09;&#x1f6a9;驗證碼功能 ?總結 &#x1f343;前言 本篇文章重…

Unity-Sprite Atlas+UGUI系統的運行原理

每日一句&#xff1a;別聽世俗耳語&#xff0c;看自己的風景就好 目錄 SA的原理&#xff1a; SA的優點&#xff1a; SA的缺點&#xff1a; DrawCall是什么&#xff1f; 批處理是什么&#xff1f; 我們先了解一下UGUI系統的運行原理吧&#xff01; 提到圖集優化&#xff0…

cocosCreator動態生成二維碼

cocosCreator 版本&#xff1a;3.7.2 開發語言&#xff1a;typeScript 我們在游戲開發中&#xff0c;經常會生成一個專屬于玩家個人的二維碼&#xff0c;比如說推廣、充值等功能。 接到這個任務&#xff0c;在網上找了下&#xff0c;還是有很多教程的。但是這些教程大部分都是用…

Ollydbg動態分析MessageBoxA輸出hellow world

一、目的 找到main函數找到調用的MessageBoxA函數 測試源碼 #include <iostream> #include <windows.h>int main() {MessageBoxA(NULL, "Hellow World", "Title", MB_OK);return 1; }二、快捷鍵 指令快捷鍵說明RestartCtrlF2重新開始調試S…

buu[HCTF 2018]WarmUp(代碼審計)

buu[HCTF 2018]WarmUp&#xff08;代碼審計&#xff09; 題目 訪問source.php <?phphighlight_file(__FILE__);class emmm{public static function checkFile(&$page){$whitelist ["source">"source.php","hint">"hint.php…

MySQL基礎學習: SET FOREIGN_KEY_CHECKS = 0

文章目錄 一、介紹二、使用方法三、注意事項 一、介紹 在MySQL中&#xff0c;SET FOREIGN_KEY_CHECKS 0; 是一個特殊的命令&#xff0c;用于臨時禁用外鍵約束檢查。這在你執行一些涉及多個表并且可能違反外鍵約束的批量操作時非常有用。 為什么需要禁用外鍵約束檢查&#xf…

電腦鍵盤如何練習盲打?

電腦鍵盤如何練習盲打&#xff1f;盲打很簡單&#xff0c;跟著我做&#xff0c;今天教會你。 請看【圖1】&#xff1a; 【圖1】中&#xff0c;紅色方框就是8個基準鍵位&#xff0c;打字時我們左右手的8個手指就是放在這8個基準鍵位上&#xff0c;F鍵和J鍵上各有一個小突起&…

Spring6基礎筆記

Spring6 Log4j2 1、概述 1.1、Spring是什么&#xff1f; Spring 是一款主流的 Java EE 輕量級開源框架 &#xff0c;Spring 由“Spring 之父”Rod Johnson 提出并創立&#xff0c;其目的是用于簡化 Java 企業級應用的開發難度和開發周期。Spring的用途不僅限于服務器端的開發…