c++調(diào)用實(shí)現(xiàn)yolov5轉(zhuǎn)onnx介紹
介紹
現(xiàn)在很多開發(fā)都是需要用c++做最后一步的移植部署,手寫吧,先不說你會(huì)不會(huì)浪費(fèi)時(shí)間,網(wǎng)上找吧,問題千奇百怪,所以給大家出這篇文章,做雷鋒教學(xué),話不多說,開始
訓(xùn)練模型.pt轉(zhuǎn)onnx
訓(xùn)練部分根據(jù)呼聲再?zèng)Q定要不要寫一份博客吧??!
注意事項(xiàng):
1.訓(xùn)練代碼一定要選擇yolov5 5.0版本
2. 進(jìn)入models/exprort.py;
3.將紅框區(qū)域換成你自己的訓(xùn)練完的模型
4.將版本換成12;
5.直接運(yùn)行即可,會(huì)生成出onnx的模型出來。
c++代碼解析
博主使用的是opencv4.5.3版本,已經(jīng)編譯好的,需要直接掃碼加我發(fā)你
main函數(shù)部分
讀取模型利用的是dnn::readNet,opencv其實(shí)挺強(qiáng)大的博主已經(jīng)讀過tf模型,torch模型后續(xù)都會(huì)出對(duì)應(yīng)博客,這里總共有三點(diǎn)改,輸入圖片path,輸入類別名class_names,net部分改成自己的模型
net.set這些參數(shù)都固定就好,有興趣的同學(xué)可以研究研究DNN_TARGET_CPU這個(gè)地方,是可以使用gpu和cuda的,但是博主還沒復(fù)現(xiàn)過
推理部分講解
void postprocess(cv::Mat& cv_src, std::vector<cv::Mat>& outs, const std::vector<std::string>& classes, int net_size) { float confThreshold = 0.1f; float nmsThreshold = 0.1f; std::vector<int> classIds; std::vector<float> confidences; std::vector<cv::Rect> boxes; int strides[] = { 8, 16, 32 }; std::vector<std::vector<int> > anchors = { { 10,13, 16,30, 33,23 }, { 30,61, 62,45, 59,119 }, { 116,90, 156,198, 373,326 } }; for (size_t k = 0; k < outs.size(); k++) { float* data = outs[k].ptr<float>(); int stride = strides[k]; int num_classes = outs[k].size[4] - 5; for (int i = 0; i < outs[k].size[2]; i++) { for (int j = 0; j < outs[k].size[3]; j++) { for (int a = 0; a < outs[k].size[1]; ++a) { float* record = data + a * outs[k].size[2] * outs[k].size[3] * outs[k].size[4] + i * outs[k].size[3] * outs[k].size[4] + j * outs[k].size[4]; float* cls_ptr = record + 5; for (int cls = 0; cls < num_classes; cls++) { float score = sigmoid(cls_ptr[cls]) * sigmoid(record[4]); if (score > confThreshold) { float cx = (sigmoid(record[0]) * 2.f - 0.5f + (float)j) * (float)stride; float cy = (sigmoid(record[1]) * 2.f - 0.5f + (float)i) * (float)stride; float w = pow(sigmoid(record[2]) * 2.f, 2) * anchors[k][2 * a]; float h = pow(sigmoid(record[3]) * 2.f, 2) * anchors[k][2 * a + 1]; float x1 = std::max(0, std::min(cv_src.cols, int((cx - w / 2.f) * (float)cv_src.cols / (float)net_size))); float y1 = std::max(0, std::min(cv_src.rows, int((cy - h / 2.f) * (float)cv_src.rows / (float)net_size))); float x2 = std::max(0, std::min(cv_src.cols, int((cx + w / 2.f) * (float)cv_src.cols / (float)net_size))); float y2 = std::max(0, std::min(cv_src.rows, int((cy + h / 2.f) * (float)cv_src.rows / (float)net_size))); classIds.push_back(cls); confidences.push_back(score); boxes.push_back(cv::Rect(cv::Point(x1, y1), cv::Point(x2, y2))); } } } } } } std::vector<int> indices; cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices); for (size_t i = 0; i < indices.size(); i++) { int idx = indices[i]; cv::Rect box = boxes[idx]; drawPred(classIds[idx], confidences[idx], box.x, box.y, box.x + box.width, box.y + box.height, cv_src, classes); } }
抬頭部分是兩大目標(biāo)檢測(cè)的閾值設(shè)置,然后anchors這些都不建議動(dòng),除非你在訓(xùn)練的時(shí)候用了你自己生成的anchors的話,就改成你自己的,然后根據(jù)訓(xùn)練推理后,會(huì)生成我們所對(duì)應(yīng)的坐標(biāo)框以及分?jǐn)?shù),將分?jǐn)?shù)和狂送到容器中,dnn中有nms等底層函數(shù)哦
cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
對(duì)應(yīng)輸入就可以了,然后得到我們的Box,index,和置信度,接下來就到了我們的畫圖環(huán)節(jié)。
darpred部分
void drawPred(int classId, float conf, int left, int top, int right, int bottom, cv::Mat& frame, const std::vector<std::string>& classes) { cv::rectangle(frame, cv::Point(left, top), cv::Point(right, bottom), cv::Scalar(0, 255, 0), 3); std::string label = cv::format("%.2f", conf); if (!classes.empty()) { CV_Assert(classId < (int)classes.size()); label = classes[classId] + ": " + label; } int baseLine; cv::Size labelSize = cv::getTextSize(label, cv::FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine); top = std::max(top, labelSize.height); cv::rectangle(frame, cv::Point(left, top - round(1.5 * labelSize.height)), cv::Point(left + round(1.5 * labelSize.width), top + baseLine), cv::Scalar(0, 255, 0), cv::FILLED); cv::putText(frame, label, cv::Point(left, top), cv::FONT_HERSHEY_SIMPLEX, 0.75, cv::Scalar(), 2); }
sigmod部分
inline float sigmoid(float x) { return 1.f / (1.f + exp(-x)); }
結(jié)尾
到此這篇關(guān)于c++調(diào)用實(shí)現(xiàn)yolov5轉(zhuǎn)onnx介紹的文章就介紹到這了,更多相關(guān)c++ yolov5轉(zhuǎn)onnx內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言通過三步翻轉(zhuǎn)法實(shí)現(xiàn)單詞倒置詳解
這篇文章主要為大家分享了用三步翻轉(zhuǎn)法將一句話的單詞進(jìn)行倒置的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05OpenCV實(shí)現(xiàn)馬賽克和毛玻璃濾鏡特效
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)馬賽克和毛玻璃濾鏡特效,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下方法2019-05-05C++條件及循環(huán)語句的綜合運(yùn)用實(shí)例
這篇文章主要介紹了C++條件及循環(huán)語句的綜合運(yùn)用實(shí)例,能夠幫助C++初學(xué)者更好地掌握C++的邏輯語句用法,需要的朋友可以參考下2015-09-09異步http listener 完全并發(fā)處理懲罰http懇求的小例子
異步http listener 完全并發(fā)處理懲罰http懇求的小例子,需要的朋友可以參考一下2013-05-05C++?MiniZip實(shí)現(xiàn)目錄壓縮與解壓的示例詳解
Zlib是一個(gè)開源的數(shù)據(jù)壓縮庫(kù),提供了一種通用的數(shù)據(jù)壓縮和解壓縮算法,本文主要為大家詳細(xì)介紹了如何利用Zlib實(shí)現(xiàn)目錄壓縮與解壓,需要的小伙伴可以參考下2023-11-11C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)
這篇文章主要介紹了C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10