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定要不要寫一份博客吧?。?br />
注意事項(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ì)出對應(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)檢測的閾值設(shè)置,然后anchors這些都不建議動(dòng),除非你在訓(xùn)練的時(shí)候用了你自己生成的anchors的話,就改成你自己的,然后根據(jù)訓(xùn)練推理后,會(huì)生成我們所對應(yīng)的坐標(biāo)框以及分?jǐn)?shù),將分?jǐn)?shù)和狂送到容器中,dnn中有nms等底層函數(shù)哦
cv::dnn::NMSBoxes(boxes, confidences, confThreshold, nmsThreshold, indices);
對應(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)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
C語言通過三步翻轉(zhuǎn)法實(shí)現(xiàn)單詞倒置詳解
這篇文章主要為大家分享了用三步翻轉(zhuǎn)法將一句話的單詞進(jìn)行倒置的方法,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下2022-05-05
OpenCV實(shí)現(xiàn)馬賽克和毛玻璃濾鏡特效
這篇文章主要為大家詳細(xì)介紹了OpenCV實(shí)現(xiàn)馬賽克和毛玻璃濾鏡特效,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下方法2019-05-05
C++條件及循環(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-05
C++?MiniZip實(shí)現(xiàn)目錄壓縮與解壓的示例詳解
Zlib是一個(gè)開源的數(shù)據(jù)壓縮庫,提供了一種通用的數(shù)據(jù)壓縮和解壓縮算法,本文主要為大家詳細(xì)介紹了如何利用Zlib實(shí)現(xiàn)目錄壓縮與解壓,需要的小伙伴可以參考下2023-11-11
C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)
這篇文章主要介紹了C++中strstr函數(shù)的實(shí)現(xiàn)方法總結(jié)的相關(guān)資料,希望通過本文能幫助到大家,讓大家掌握這部分內(nèi)容,需要的朋友可以參考下2017-10-10

