yolov5分割+检测c++ qt 中部署,以opencv方式(详细代码(全)+复制可用)

1:版本说明:

qt 5.12.10

opencv 4.5.3 (yolov5模型部署要求opencv>4.5.0)

2:检测的代码

yolo.h
#pragma once
#include<iostream>
#include<cmath>
#include<vector>
#include <opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>class yolo
{
public:yolo() {}~yolo(){}bool readModel(cv::dnn::Net &net,std::string &netpath, bool isCuda);struct Output{int id;//结果类别idfloat confidence;//结果置信度cv::Rect box;//矩形框int ship_id;//船的idint truck_id;//人的idint person_id;//人的idint  staring_id;//车的idint  forklift_id;//车的idint unload_car_id;//船的idint load_car_id;//人的idint  private_car_id;//车的id};struct Output_max_confidence{int id;//结果类别idfloat confidence;//结果置信度cv::Rect box;//矩形框};int ship_num;//总人数int  car_trucks_num;//总车数int person_num;//总船数int stacking_area_num;//总人数int  car_forklift_num;//总车数int unload_car_num;//总船数int load_car_num;//总人数int  car_private_num;//总车数bool Detect(cv::Mat &SrcImg, cv::dnn::Net &net, std::vector<Output> &output);void drawPred(cv::Mat &img, std::vector<Output> result, std::vector<cv::Scalar> color);//参数为私有参数,当然也可以是设置成公开或者保护。Output_max_confidence get_only_one_max_confidence(std::vector<Output> result);float findMax(std::vector<float> vec);int getPositionOfMax(std::vector<float> vec, int max);
\void drawRect(cv::Mat &img, yolo::Output_max_confidence result);
private://计算归一化函数float Sigmoid(float x) {return static_cast<float>(1.f / (1.f + exp(-x)));}//anchorsconst float netAnchors[3][6] = { { 10.0, 13.0, 16.0, 30.0, 33.0, 23.0 },{ 30.0, 61.0, 62.0, 45.0, 59.0, 119.0 },{ 116.0, 90.0, 156.0, 198.0, 373.0, 326.0 } };//strideconst float netStride[3] = { 8.0, 16.0, 32.0 };const int netWidth = 640; //网络模型输入大小const int netHeight = 640;float nmsThreshold = 0.02;float boxThreshold = 0.05;float classThreshold = 0.45;//类名
//    std::vector<std::string> className = { "car", "person"};
//    std::vector<std::string> className = { "person", "bicycle", "car", "motorcycle", "airplane", "bus", "train", "truck", "boat", "traffic light",
//                                           "fire hydrant", "stop sign", "parking meter", "bench", "bird", "cat", "dog", "horse", "sheep", "cow",
//                                           "elephant", "bear", "zebra", "giraffe", "backpack", "umbrella", "handbag", "tie", "suitcase", "frisbee",
//                                           "skis", "snowboard", "sports ball", "kite", "baseball bat", "baseball glove", "skateboard", "surfboard",
//                                           "tennis racket", "bottle", "wine glass", "cup", "fork", "knife", "spoon", "bowl", "banana", "apple",
//                                           "sandwich", "orange", "broccoli", "carrot", "hot dog", "pizza", "donut", "cake", "chair", "couch",
//                                           "potted plant", "bed", "dining table", "toilet", "tv", "laptop", "mouse", "remote", "keyboard", "cell phone",
//                                           "microwave", "oven", "toaster", "sink", "refrigerator", "book", "clock", "vase", "scissors", "teddy bear",
//                                           "hair drier", "toothbrush"};std::vector<std::string> className = { "ship","car_trucks","person","stacking_area","car_forklift","unload_car","load_car","car_private"};//"car","person"};
yolo.cpp
#include "yolo.h"
#include<iostream>
#include<cmath>
#include<vector>
#include <opencv2/opencv.hpp>
#include<opencv2/dnn.hpp>
using namespace std;
using namespace cv;
using namespace dnn;
#pragma execution_character_set("utf-8");
bool yolo::readModel(Net &net, string &netPath, bool isCuda = false) {try {net = readNetFromONNX(netPath);cout<<"load net successfull!"<<endl;}catch (const std::exception&) {return false;}//cudaif (isCuda) {net.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);}//cpuelse {net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);}return true;
}bool yolo::Detect(Mat &SrcImg, Net &net, vector<Output> &output) {Mat blob;int col = SrcImg.cols;int row = SrcImg.rows;int maxLen = MAX(col, row);Mat netInputImg = SrcImg.clone();if (maxLen > 1.2*col || maxLen > 1.2*row) {Mat resizeImg = Mat::zeros(maxLen, maxLen, CV_8UC3);SrcImg.copyTo(resizeImg(Rect(0, 0, col, row)));netInputImg = resizeImg;}blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(104, 117, 123), true, false);blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(0, 0,0), true, false);//如果训练集未对图片进行减去均值操作,则需要设置为这句//blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(netWidth, netHeight), cv::Scalar(114, 114,114), true, false);net.setInput(blob);std::vector<cv::Mat> netOutputImg;//vector<string> outputLayerName{"345","403", "461","output" };//net.forward(netOutputImg, outputLayerName[3]); //获取output的输出net.forward(netOutputImg, net.getUnconnectedOutLayersNames());//接上面std::vector<int> classIds;//结果id数组std::vector<float> confidences;//结果每个id对应置信度数组std::vector<cv::Rect> boxes;//每个id矩形框std::vector<int> ship_id;//记录下人数的id号码----补充std::vector<int> trucks_id;//记录下车数的id号码----补充std::vector<int> person_id;//记录下人数的id号码----补充std::vector<int> stacking_id;//记录下车数的id号码----补充std::vector<int> forklift_id;//记录下人数的id号码----补充std::vector<int> unload_car_id;//记录下车数的id号码----补充std::vector<int> load_car_id;//记录下人数的id号码----补充std::vector<int> car_private_id;//记录下车数的id号码----补充float ratio_h = (float)netInputImg.rows / netHeight;float ratio_w = (float)netInputImg.cols / netWidth;int net_width = className.size() + 5;  //输出的网络宽度是类别数+5float* pdata = (float*)netOutputImg[0].data;for (int stride = 0; stride < 3; stride++) {    //strideint grid_x = (int)(netWidth / netStride[stride]);int grid_y = (int)(netHeight / netStride[stride]);for (int anchor = 0; anchor < 3; anchor++) { //anchorsconst float anchor_w = netAnchors[stride][anchor * 2];const float anchor_h = netAnchors[stride][anchor * 2 + 1];for (int i = 0; i < grid_y; i++) {for (int j = 0; j < grid_y; j++) {//float box_score = Sigmoid(pdata[4]);//获取每一行的box框中含有某个物体的概率 yolo5.0float box_score = pdata[4];//获取每一行的box框中含有某个物体的概率 yolo6.0if (box_score > boxThreshold) {//为了使用minMaxLoc(),将85长度数组变成Mat对象cv::Mat scores(1, className.size(), CV_32FC1, pdata + 5);Point classIdPoint;double max_class_socre;minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);//max_class_socre = Sigmoid((float)max_class_socre);  //yolo 5.0max_class_socre = (float)max_class_socre;    //yolo 6.0if (max_class_socre > classThreshold) {//rect [x,y,w,h]//yolov5 5.0格式//float x = (Sigmoid(pdata[0]) * 2.f - 0.5f + j) * netStride[stride];  //x//float y = (Sigmoid(pdata[1]) * 2.f - 0.5f + i) * netStride[stride];   //y//float w = powf(Sigmoid(pdata[2]) * 2.f, 2.f) * anchor_w;   //w//float h = powf(Sigmoid(pdata[3]) * 2.f, 2.f) * anchor_h;  //h//yolov5 6.0格式:float x = pdata[0];// (Sigmoid(pdata[0]) * 2.f - 0.5f + j) * netStride[stride];  //xfloat y = pdata[1];// (Sigmoid(pdata[1]) * 2.f - 0.5f + i) * netStride[stride];   //yfloat w = pdata[2];// powf(Sigmoid(pdata[2]) * 2.f, 2.f) * anchor_w;   //wfloat h = pdata[3];// powf(Sigmoid(pdata[3]) * 2.f, 2.f) * anchor_h;  //hint left = (x - 0.5*w)*ratio_w;int top = (y - 0.5*h)*ratio_h;classIds.push_back(classIdPoint.x);confidences.push_back(max_class_socre*box_score);boxes.push_back(Rect(left, top, int(w*ratio_w), int(h*ratio_h)));}}pdata += net_width;//指针移到下一行}}}}//接上面执行非最大抑制以消除具有较低置信度的冗余重叠框(NMS)vector<int> nms_result;int ship_id_ini=0;//初始化人数,int trucks_id_ini=0;//初始化人数,int person_id_ini=0;//初始化车辆数int stacking_id_ini=0;//初始化车辆数int forklift_id_ini=0;//初始化车辆数int unload_car_id_ini=0;//初始化车辆数int load_car_id_ini=0;//初始化车辆数int car_private_id_ini=0;//初始化车辆数NMSBoxes(boxes, confidences, classThreshold, nmsThreshold, nms_result);for (int i = 0; i < nms_result.size(); i++) {int idx = nms_result[i];Output result;result.id = classIds[idx];result.confidence = confidences[idx];result.box = boxes[idx];output.push_back(result);if(result.id==0)//当类别数等于船的时候{result.ship_id=ship_id_ini;//当船等于ship_id_ini=ship_id_ini+1;}if(result.id==1)//当类别数等于车的时候{result.truck_id=trucks_id_ini;//当车数等于trucks_id_ini=trucks_id_ini+1;}if(result.id==2)//当类别数等于人的时候{result.person_id=person_id_ini;//当人数等于person_id_ini=person_id_ini+1;}if(result.id==3)//当类别数等于人的时候{result.staring_id=stacking_id_ini;//当人数等于stacking_id_ini=stacking_id_ini+1;}if(result.id==4)//当类别数等于人的时候{result.forklift_id=forklift_id_ini;//当人数等于forklift_id_ini=forklift_id_ini+1;}if(result.id==5)//当类别数等于人的时候{result.unload_car_id=unload_car_id_ini;//当人数等于unload_car_id_ini=unload_car_id_ini+1;}if(result.id==6)//当类别数等于人的时候{result.load_car_id=load_car_id_ini;//当人数等于load_car_id_ini=load_car_id_ini+1;}if(result.id==7)//当类别数等于人的时候{result.private_car_id=car_private_id_ini;//当人数等于car_private_id_ini=car_private_id_ini+1;}}ship_num=ship_id_ini;car_trucks_num=trucks_id_ini;person_num=person_id_ini;stacking_area_num=stacking_id_ini;car_forklift_num=forklift_id_ini ;//总车数unload_car_num=unload_car_id_ini;//总船数load_car_num=load_car_id_ini;//总人数car_private_num=car_private_id_ini;//总车数if (output.size())return true;elsereturn false;}//这个括号是最后void yolo::drawPred(Mat &img, vector<Output> result, vector<Scalar> color)
{for (int i = 0; i < result.size(); i++){int left, top;left = result[i].box.x;top = result[i].box.y;int color_num = i;rectangle(img, result[i].box, color[result[i].id], 2, 8);//      string label = className[result[i].id] + ":" + to_string(result[i].confidence)+" id:"+to_string(result[i].person_id);string label;if(result[i].id==0){label = className[result[i].id] ;}if(result[i].id==1){label = className[result[i].id] ;}if(result[i].id==2){label = className[result[i].id] ;}if(result[i].id==3){label = className[result[i].id] ;}if(result[i].id==4){label = className[result[i].id] ;}if(result[i].id==5){label = className[result[i].id] ;}if(result[i].id==6){label = className[result[i].id] ;}if(result[i].id==7){label = className[result[i].id];}int baseLine;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);top = max(top, labelSize.height);//rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 1, color[result[i].id], 2);}//imshow("res", img);//imwrite("./result.jpg", img);//waitKey();//destroyAllWindows();
}//这个是针对悍马的画框
void yolo::drawRect(cv::Mat &img, yolo::Output_max_confidence result)
{int left, top;left = result.box.x;top = result.box.y;rectangle(img, result.box,Scalar(0,0,255) , 2, 8);//      string label = className[result[i].id] + ":" + to_string(result[i].confidence)+" id:"+to_string(result[i].person_id);string label;if(result.id==0){label = className[result.id];}int baseLine;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);top = max(top, labelSize.height);//rectangle(frame, Point(left, top - int(1.5 * labelSize.height)), Point(left + int(1.5 * labelSize.width), top + baseLine), Scalar(0, 255, 0), FILLED);putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 2,Scalar(0,0,255), 2);}float yolo::findMax(std::vector<float> vec) {float max = -999;for (auto v : vec) {if (max < v) max = v;}return max;
}int yolo::getPositionOfMax(std::vector<float> vec, int max) {auto distance = find(vec.begin(), vec.end(), max);return distance - vec.begin();
}//返回一个最大置信度的框
yolo::Output_max_confidence yolo::get_only_one_max_confidence(std::vector<Output> result)
{std::vector<float>confidence;for (int i = 0; i < result.size(); i++){confidence.push_back(result.at(i).confidence);//        cout<<"result.at(i).confidence"<<result.at(i).confidence<<endl;}float maxConfidence=findMax(confidence);int position = result.size()-getPositionOfMax(confidence, maxConfidence);//    cout<<"max_confidengce"<<maxConfidence<<"position:"<<position<<endl;Output_max_confidence o_m_c;o_m_c.confidence=maxConfidence;o_m_c.id=position;o_m_c.box=result.at(position).box;return o_m_c ;}
检测的调用代码测试案例

这段调用的例子,只要把frame 改成你们自己的图片即可

yolo test;    //创建yolo类
cv::dnn::Net net; //创建yolo网络
vector< cv::Scalar> color;//Bounding Box颜色 
QString Filename_onnx="quanjingbest.onnx";
cv::String filename_onnx=Filename_onnx.toStdString();
vector<yolo::Output>result_video;
test.readModel(net,filename_onnx,false);
for (int i = 0; i < 80; i++) {int b = rand() % 256;int g = rand() % 256;int r = rand() % 256;color.push_back( cv::Scalar(b, g, r));}cv::Mat frame=cv::imread("D://1.jpg");
if(test.Detect(frame, net, result_video))          //调用YOLO模型检测test.drawPred(frame, result_video, color);
cv::imshow("a",frame);
cv::waitKey(1);

4:分割的主要代码

YoloSeg.h
#ifndef YOLO_SEG_H
#define YOLO_SEG_H#pragma once
#include<iostream>
#include<opencv2/opencv.hpp>
#include "yolov5_seg_utils.h"class YoloSeg {
public:YoloSeg() {}~YoloSeg() {}/** \brief Read onnx-model* \param[out] read onnx file into cv::dnn::Net* \param[in] modelPath:onnx-model path* \param[in] isCuda:if true and opencv built with CUDA(cmake),use OpenCV-GPU,else run it on cpu.*/bool ReadModel(cv::dnn::Net& net, std::string& netPath, bool isCuda);/** \brief  detect.* \param[in] srcImg:a 3-channels image.* \param[out] output:detection results of input image.*/bool Detect(cv::Mat& srcImg, cv::dnn::Net& net, std::vector<OutputSeg>& output);#if(defined YOLO_P6 && YOLO_P6==true)const int _netWidth = 1280;  //ONNX图片输入宽度const int _netHeight = 1280; //ONNX图片输入高度const int _segWidth = 320;  //_segWidth=_netWidth/mask_ratioconst int _segHeight = 320;const int _segChannels = 32;
#elseconst int _netWidth = 640;   //ONNX图片输入宽度const int _netHeight = 640;  //ONNX图片输入高度const int _segWidth = 160;    //_segWidth=_netWidth/mask_ratioconst int _segHeight = 160;const int _segChannels = 32;#endif // YOLO_P6float _classThreshold = 0.25;float _nmsThreshold = 0.45;float _maskThreshold = 0.5;public:std::vector<std::string> _className = { "steel"};//类别名,换成自己的模型需要修改此项
};#endif // YOLO_SEG_H
YoloSeg.cpp
#include "yolo_seg.h"#include"yolo_seg.h"
using namespace std;
using namespace cv;
using namespace cv::dnn;bool YoloSeg::ReadModel(Net& net, string& netPath, bool isCuda = false) {try {net = readNet(netPath);
#if CV_VERSION_MAJOR==4 &&CV_VERSION_MINOR==7&&CV_VERSION_REVISION==0net.enableWinograd(false);  //bug of opencv4.7.x in AVX only platform ,https://github.com/opencv/opencv/pull/23112 and https://github.com/opencv/opencv/issues/23080//net.enableWinograd(true);		//If your CPU supports AVX2, you can set it true to speed up
#endif}catch (const std::exception&) {return false;}if (isCuda) {//cudanet.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);net.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA); //or DNN_TARGET_CUDA_FP16}else {//cpucout << "Inference device: CPU" << endl;net.setPreferableBackend(cv::dnn::DNN_BACKEND_DEFAULT);net.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);}return true;
}bool YoloSeg::Detect(Mat& srcImg, Net& net, vector<OutputSeg>& output) {Mat blob;output.clear();int col = srcImg.cols;int row = srcImg.rows;Mat netInputImg;Vec4d params;LetterBox(srcImg, netInputImg, params, cv::Size(_netWidth, _netHeight));blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(0, 0, 0), true, false);//**************************************************************************************************************************************************///如果在其他设置没有问题的情况下但是结果偏差很大,可以尝试下用下面两句语句// If there is no problem with other settings, but results are a lot different from  Python-onnx , you can try to use the following two sentences////$ blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(104, 117, 123), true, false);//$ blobFromImage(netInputImg, blob, 1 / 255.0, cv::Size(_netWidth, _netHeight), cv::Scalar(114, 114,114), true, false);//****************************************************************************************************************************************************/net.setInput(blob);std::vector<cv::Mat> net_output_img;//*********************************************************************************************************************************//net.forward(net_output_img, net.getUnconnectedOutLayersNames());//opencv4.5.x和4.6.x这里输出不一致,推荐使用下面的固定名称输出// 如果使用net.forward(net_output_img, net.getUnconnectedOutLayersNames()),需要确认下net.getUnconnectedOutLayersNames()返回值中output0在前,output1在后,否者出错//// The outputs of opencv4.5.x and 4.6.x are inconsistent.Please make sure "output0" is in front of "output1" if you use net.forward(net_output_img, net.getUnconnectedOutLayersNames())//*********************************************************************************************************************************vector<string> output_layer_names{ "output0","output1" };net.forward(net_output_img, output_layer_names); //获取output的输出std::vector<int> class_ids;//结果id数组std::vector<float> confidences;//结果每个id对应置信度数组std::vector<cv::Rect> boxes;//每个id矩形框std::vector<vector<float>> picked_proposals;  //output0[:,:, 5 + _className.size():net_width]===> for maskint net_width = _className.size() + 5 + _segChannels;// 80 + 5 + 32 = 117int out0_width= net_output_img[0].size[2];//    assert(net_width == out0_width, "Error Wrong number of _className or _segChannels");  //模型类别数目不对或者_segChannels设置错误int net_height = net_output_img[0].size[1];// 25200float* pdata = (float*)net_output_img[0].data;for (int r = 0; r < net_height; r++) {    //linesfloat box_score = pdata[4];if (box_score >= _classThreshold) {cv::Mat scores(1, _className.size(), CV_32FC1, pdata + 5); //  可是 后面不只是有80个类别的概率;Point classIdPoint;double max_class_socre;minMaxLoc(scores, 0, &max_class_socre, 0, &classIdPoint);max_class_socre = (float)max_class_socre;if (max_class_socre >= _classThreshold) {vector<float> temp_proto(pdata + 5 + _className.size(), pdata + net_width); // Mask Coeffcients,mask的掩码系数picked_proposals.push_back(temp_proto);//rect [x,y,w,h]float x = (pdata[0] - params[2]) / params[0];  //xfloat y = (pdata[1] - params[3]) / params[1];  //yfloat w = pdata[2] / params[0];  //wfloat h = pdata[3] / params[1];  //hint left = MAX(int(x - 0.5 * w + 0.5), 0);int top = MAX(int(y - 0.5 * h + 0.5), 0);class_ids.push_back(classIdPoint.x);confidences.push_back(max_class_socre * box_score);boxes.push_back(Rect(left, top, int(w + 0.5), int(h + 0.5)));}}pdata += net_width;//下一行}//NMSvector<int> nms_result;cv::dnn::NMSBoxes(boxes, confidences, _classThreshold, _nmsThreshold, nms_result);std::vector<vector<float>> temp_mask_proposals;Rect holeImgRect(0, 0, srcImg.cols, srcImg.rows);for (int i = 0; i < nms_result.size(); ++i) {int idx = nms_result[i];OutputSeg result;result.id = class_ids[idx];result.confidence = confidences[idx];result.box = boxes[idx] & holeImgRect;temp_mask_proposals.push_back(picked_proposals[idx]);output.push_back(result);}MaskParams mask_params;mask_params.params = params;mask_params.srcImgShape = srcImg.size();for (int i = 0; i < temp_mask_proposals.size(); ++i) {GetMask2(Mat(temp_mask_proposals[i]).t(), net_output_img[1], output[i], mask_params); // 注意这里是net_output_img[1],为原型mask}//******************** ****************// 老版本的方案,如果上面GetMask2出错,建议使用这个。// If the GetMask2() still reports errors , it is recommended to use GetMask().// Mat mask_proposals;//for (int i = 0; i < temp_mask_proposals.size(); ++i)//	mask_proposals.push_back(Mat(temp_mask_proposals[i]).t());//GetMask(mask_proposals, net_output_img[1], output, mask_params);//*****************************************************/if (output.size())return true;elsereturn false;
}
yolov5_seg_utils.h
#ifndef YOLOV5_SEG_UTILS_H
#define YOLOV5_SEG_UTILS_H#pragma once
#include<iostream>
#include <numeric>
#include<opencv2/opencv.hpp>#define YOLO_P6 false //是否使用P6模型
#define ORT_OLD_VISON 12  //ort1.12.0 之前的版本为旧版本APIstruct OutputSeg {int id;             //结果类别idfloat confidence;   //结果置信度cv::Rect box;       //矩形框cv::Mat boxMask;       //矩形框内mask,节省内存空间和加快速度
};
struct MaskParams {int segChannels = 32;int segWidth = 160;int segHeight = 160;int netWidth = 640;int netHeight = 640;float maskThreshold = 0.5;cv::Size srcImgShape;cv::Vec4d params;};
bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize);
void DrawPred(cv::Mat& img, std::vector<OutputSeg> result, std::vector<std::string> classNames, std::vector<cv::Scalar> color);
void LetterBox(const cv::Mat& image, cv::Mat& outImage,cv::Vec4d& params, //[ratio_x,ratio_y,dw,dh]const cv::Size& newShape = cv::Size(640, 640),bool autoShape = false,bool scaleFill = false,bool scaleUp = true,int stride = 32,const cv::Scalar& color = cv::Scalar(114, 114, 114));
void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams);
void GetMask2(const cv::Mat& maskProposals, const cv::Mat& maskProtos, OutputSeg& output, const MaskParams& maskParams);#endif // YOLOV5_SEG_UTILS_H
 yolov5_seg_utils.cpp
#include "yolov5_seg_utils.h"#pragma once
#include "yolov5_seg_utils.h"
using namespace cv;
using namespace std;
bool CheckParams(int netHeight, int netWidth, const int* netStride, int strideSize) {if (netHeight % netStride[strideSize - 1] != 0 || netWidth % netStride[strideSize - 1] != 0){cout << "Error:_netHeight and _netWidth must be multiple of max stride " << netStride[strideSize - 1] << "!" << endl;return false;}return true;
}void LetterBox(const cv::Mat& image, cv::Mat& outImage, cv::Vec4d& params, const cv::Size& newShape,bool autoShape, bool scaleFill, bool scaleUp, int stride, const cv::Scalar& color)
{if (false) {int maxLen = MAX(image.rows, image.cols);outImage = Mat::zeros(Size(maxLen, maxLen), CV_8UC3);image.copyTo(outImage(Rect(0, 0, image.cols, image.rows)));params[0] = 1;params[1] = 1;params[3] = 0;params[2] = 0;}cv::Size shape = image.size();float r = std::min((float)newShape.height / (float)shape.height,(float)newShape.width / (float)shape.width);if (!scaleUp)r = std::min(r, 1.0f);float ratio[2]{ r, r };int new_un_pad[2] = { (int)std::round((float)shape.width * r),(int)std::round((float)shape.height * r) };auto dw = (float)(newShape.width - new_un_pad[0]);auto dh = (float)(newShape.height - new_un_pad[1]);if (autoShape){dw = (float)((int)dw % stride);dh = (float)((int)dh % stride);}else if (scaleFill){dw = 0.0f;dh = 0.0f;new_un_pad[0] = newShape.width;new_un_pad[1] = newShape.height;ratio[0] = (float)newShape.width / (float)shape.width;ratio[1] = (float)newShape.height / (float)shape.height;}dw /= 2.0f;dh /= 2.0f;if (shape.width != new_un_pad[0] && shape.height != new_un_pad[1]){cv::resize(image, outImage, cv::Size(new_un_pad[0], new_un_pad[1]));}else {outImage = image.clone();}int top = int(std::round(dh - 0.1f));int bottom = int(std::round(dh + 0.1f));int left = int(std::round(dw - 0.1f));int right = int(std::round(dw + 0.1f));params[0] = ratio[0];params[1] = ratio[1];params[2] = left;params[3] = top;cv::copyMakeBorder(outImage, outImage, top, bottom, left, right, cv::BORDER_CONSTANT, color);
}void GetMask(const cv::Mat& maskProposals, const cv::Mat& maskProtos, std::vector<OutputSeg>& output, const MaskParams& maskParams) {//cout << maskProtos.size << endl;int seg_channels = maskParams.segChannels;int net_width = maskParams.netWidth;int seg_width = maskParams.segWidth;int net_height = maskParams.netHeight;int seg_height = maskParams.segHeight;float mask_threshold = maskParams.maskThreshold;Vec4f params = maskParams.params;Size src_img_shape = maskParams.srcImgShape;Mat protos = maskProtos.reshape(0, { seg_channels,seg_width * seg_height });Mat matmul_res = (maskProposals * protos).t();Mat masks = matmul_res.reshape(output.size(), { seg_width,seg_height });vector<Mat> maskChannels;split(masks, maskChannels);for (int i = 0; i < output.size(); ++i) {Mat dest, mask;//sigmoidcv::exp(-maskChannels[i], dest);dest = 1.0 / (1.0 + dest);Rect roi(int(params[2] / net_width * seg_width), int(params[3] / net_height * seg_height), int(seg_width - params[2] / 2), int(seg_height - params[3] / 2));dest = dest(roi);resize(dest, mask, src_img_shape, INTER_NEAREST);//cropRect temp_rect = output[i].box;mask = mask(temp_rect) > mask_threshold;output[i].boxMask = mask;}
}
void GetMask2(const Mat& maskProposals, const Mat& mask_protos, OutputSeg& output, const MaskParams& maskParams) {int seg_channels = maskParams.segChannels;int net_width = maskParams.netWidth;int seg_width = maskParams.segWidth;int net_height = maskParams.netHeight;int seg_height = maskParams.segHeight;float mask_threshold = maskParams.maskThreshold;Vec4f params = maskParams.params;Size src_img_shape = maskParams.srcImgShape;Rect temp_rect = output.box;// 把已经到原图的检测框坐标信息  映射到  获得mask原型分支的输入尺寸上【160, 160】int rang_x = floor((temp_rect.x * params[0] + params[2]) / net_width * seg_width);int rang_y = floor((temp_rect.y * params[1] + params[3]) / net_height * seg_height);int rang_w = ceil(((temp_rect.x + temp_rect.width) * params[0] + params[2]) / net_width * seg_width) - rang_x;int rang_h = ceil(((temp_rect.y  + temp_rect.height) * params[0] + params[3]) / net_width * seg_height) - rang_y;//rang_w = MAX(rang_w, 1);rang_h = MAX(rang_h, 1);if (rang_x + rang_w > seg_width){if (seg_width - rang_x > 0)rang_w =seg_width -rang_x;elserang_x -= 1;}if (rang_y + rang_h > seg_height) {if (seg_height - rang_y > 0)rang_h = seg_height - rang_y;elserang_y -= 1;}vector<Range> roi_ranges;roi_ranges.push_back(Range(0,1));roi_ranges.push_back(Range::all());roi_ranges.push_back(Range(rang_y, rang_h+rang_y));roi_ranges.push_back(Range(rang_x, rang_w+rang_x));// 裁剪mask原型Mat temp_mask_protos = mask_protos(roi_ranges).clone(); // 剪裁原型,保存检测框内部的原型,其余位置清零,  以此来获得感兴趣区域(roi)Mat protos = temp_mask_protos.reshape(0, { seg_channels, rang_w*rang_h});// 检测至检测框大小?// mask系数与mask原型做矩阵乘法Mat matmul_res = (maskProposals * protos).t(); // mask系数【1,32】 与 mask原型【32, h*w】进行矩阵相称Mat masks_feature = matmul_res.reshape(1,{rang_h, rang_w}); //【1,h,w】Mat dest, mask;// sigmodcv::exp(-masks_feature, dest);dest = 1.0 / (1.0 + dest);// 检测框坐标 映射到 原图尺寸int left = floor((net_width / seg_width * rang_x - params[2]) / params[0]);int top = floor((net_width / seg_height * rang_y - params[3]) / params[1]);int width = ceil(net_width / seg_height * rang_w / params[0]);int height = ceil(net_height / seg_height * rang_h / params[1]);// 检测框mask缩放到原图尺寸resize(dest, mask, Size(width, height), INTER_NEAREST);// 阈值化mask = mask(temp_rect - Point(left, top)) > mask_threshold;output.boxMask = mask;
}void DrawPred(Mat& img, vector<OutputSeg> result, std::vector<std::string> classNames, vector<Scalar> color) {Mat mask = img.clone();for (int i=0; i< result.size(); i++){int left, top;left = result[i].box.x;top = result[i].box.y;int color_num =i;// 目标画框rectangle(img, result[i].box, color[result[i].id], 2, 8);// 目标mask,这里非目标像素值为0mask(result[i].box).setTo(color[result[i].id], result[i].boxMask);string label = classNames[result[i].id] + ":" + to_string(result[i].confidence);// 框左上角打印信息int baseLine;Size labelSize = getTextSize(label, FONT_HERSHEY_SIMPLEX, 0.5, 1, &baseLine);top = max(top, labelSize.height);putText(img, label, Point(left, top), FONT_HERSHEY_SIMPLEX, 0.5, color[result[i].id], 2);}addWeighted(img, 0.5, mask, 0.5, 0, img);
}
分割的调用代码测试案例

void frmMain::test_yoloseg()
{string model_path = "20231001segquanjing.onnx";YoloSeg test;Net net;if (test.ReadModel(net, model_path, true)) {cout << "read net ok!" << endl;}else {return ;}vector<OutputSeg> result;cv::Mat img_seg_test=cv::imread("E:/data_seg/quanjingCameraPicture2/1/segdata2278.jpg");bool find = test.Detect(img_seg_test, net, result);if (find) {DrawPred(img_seg_test, result, test._className, color);}else {cout << "Detect Failed!"<<endl;}string label = "steel:" ; //msputText(img_seg_test, label, Point(30,30), FONT_HERSHEY_SIMPLEX,0.5, Scalar(0,0,255), 2, 8);QPixmap img_test_xmap= my_publiction.cvMatToQPixmap(img_seg_test);// 设置QLabel的最小尺寸ui->lab1->setMinimumSize(600, 600);ui->lab1->setScaledContents(true);img_test_xmap = img_test_xmap.scaled( ui->lab1->width(),  ui->lab1->height(), Qt::KeepAspectRatio,Qt::SmoothTransformation); // 将图像缩放到QLabel的大小ui->lab1->setPixmap(img_test_xmap);
//    imshow("result", img_seg_test);}

 分割的效果图如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/91966.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

毅速课堂:3D打印随形水路在小零件注塑中优势明显

小零件注塑中的冷却不均匀问题常常导致烧焦现象的发生。这主要是因为传统机加工方法无法制造出足够细小的水路&#xff0c;以适应小零件的复杂形状。而3D打印技术的引入&#xff0c;尤其是随形水路的设计&#xff0c;为解决这一问题提供了新的解决方案。 3D打印随形水路技术的优…

TS编译选项——编译TS文件同时对JS文件进行编译

一、允许对JS文件进行编译 我们在默认情况下编译TS项目时是不能编译js文件的&#xff0c;如下图中的hello.js文件并未编译到dist目录下&#xff08;这里配置了编译文件放到dist目录下&#xff09; 如果我们想要实现编译TS文件同时对JS文件进行编译&#xff0c;就需要在tsconfi…

使用U3D、pico开发VR(二)——添加手柄摇杆控制移动

一、将unity 与visual studio 相关联 1.Edit->Preference->External tool 选择相应的版本 二、手柄遥控人物转向和人物移动 1.添加Locomotion System组件 选择XR Origin&#xff1b; 2.添加Continuous Move Provider&#xff08;Action-based&#xff09;组件 1>…

编程每日一练(多语言实现)基础篇:求总数问题

文章目录 一、实例描述二、技术要点三、代码实现3.1 C 语言实现3.2 Python 语言实现3.3 Java 语言实现3.4 JavaScript 语言实现 一、实例描述 集邮爱好者把所有的邮票存放在三个集邮册中&#xff0c;在A册内存放全部的十分之二&#xff0c;在B册内存放不知道是全部的七分之几&…

MyBatis的一级缓存和二级缓存:原理和作用

MyBatis的一级缓存和二级缓存&#xff1a;原理和作用 引言 在数据库访问中&#xff0c;缓存是一种重要的性能优化手段&#xff0c;它可以减少数据库查询的次数&#xff0c;加快数据访问速度。MyBatis作为一款流行的Java持久层框架&#xff0c;提供了一级缓存和二级缓存来帮助…

基于Java的大学生就业招聘系统设计与实现(源码+lw+部署文档+讲解等)

文章目录 前言具体实现截图论文参考详细视频演示为什么选择我自己的网站自己的小程序&#xff08;小蔡coding&#xff09;有保障的售后福利 代码参考源码获取 前言 &#x1f497;博主介绍&#xff1a;✌全网粉丝10W,CSDN特邀作者、博客专家、CSDN新星计划导师、全栈领域优质创作…

【数据结构】排序算法(一)—>插入排序、希尔排序、选择排序、堆排序

&#x1f440;樊梓慕&#xff1a;个人主页 &#x1f3a5;个人专栏&#xff1a;《C语言》《数据结构》《蓝桥杯试题》《LeetCode刷题笔记》《实训项目》 &#x1f31d;每一个不曾起舞的日子&#xff0c;都是对生命的辜负 目录 前言 1.直接插入排序 2.希尔排序 3.直接选择排…

OpenCV之分水岭算法(watershed)

Opencv 中 watershed函数原型&#xff1a; void watershed( InputArray image, InputOutputArray markers ); 第一个参数 image&#xff0c;必须是一个8bit 3通道彩色图像矩阵序列&#xff0c;第一个参数没什么要说的。关键是第二个参数 markers&#xff0c;Opencv官方文档的说…

全网最全Python系列教程(非常详细)---集合讲解(学Python入门必收藏)

&#x1f9e1;&#x1f9e1;&#x1f9e1;这篇是关于Python中集合的讲解&#xff0c;涉及到以下内容&#xff0c;欢迎点赞和收藏&#xff0c;你点赞和收藏是我更新的动力&#x1f9e1;&#x1f9e1;&#x1f9e1; 1、集合是什么&#xff1f; 2、集合应该怎么去定义&#xff1f…

搭建前端框架

在终端进入web目录&#xff0c;然后创建vuecrud工程 创建工程并引入ElementUI和axios手把手教学>传送门:VueCLI脚手架搭建

力扣 -- 718. 最长重复子数组

解题步骤&#xff1a; 参考代码&#xff1a; class Solution { public:int findLength(vector<int>& nums1, vector<int>& nums2) {int m nums1.size();int n nums2.size();//多开一行&#xff0c;多开一列vector<vector<int>> dp(m 1, ve…

Ghostscript 在 Linux 和 Windows 系统的应用与问题解决

&#x1f337;&#x1f341; 博主猫头虎&#xff08;&#x1f405;&#x1f43e;&#xff09;带您 Go to New World✨&#x1f341; &#x1f984; 博客首页——&#x1f405;&#x1f43e;猫头虎的博客&#x1f390; &#x1f433; 《面试题大全专栏》 &#x1f995; 文章图文…

背诵不等于理解,深度解析大模型背后的知识储存与提取

自然语言模型的背诵 (memorization) 并不等于理解。即使模型能完整记住所有数据&#xff0c;也可能无法通过微调 (finetune) 提取这些知识&#xff0c;无法回答简单的问题。 随着模型规模的增大&#xff0c;人们开始探索大模型是如何掌握大量知识的。一种观点认为这归功于 “无…

【ARMv8 SIMD和浮点指令编程】NEON 加载指令——如何将数据从内存搬到寄存器(其它指令)?

除了基础的 LDx 指令,还有 LDP、LDR 这些指令,我们也需要关注。 1 LDNP (SIMD&FP) 加载 SIMD&FP 寄存器对,带有非临时提示。该指令从内存加载一对 SIMD&FP 寄存器,向内存系统发出访问是非临时的提示。用于加载的地址是根据基址寄存器值和可选的立即偏移量计算…

计算机网络(一):概述

参考引用 计算机网络微课堂-湖科大教书匠计算机网络&#xff08;第7版&#xff09;-谢希仁 1. 计算机网络在信息时代的作用 计算机网络已由一种通信基础设施发展成为一种重要的信息服务基础设施计算机网络已经像水、电、煤气这些基础设施一样&#xff0c;成为我们生活中不可或…

网络协议--概述

1.2 分层 网络协议通常分不同层次进行开发&#xff0c;每一层分别负责不同的通信功能。一个协议族&#xff0c;比如TCP/IP&#xff0c;是一组不同层次上的多个协议的组合。 TCP/IP通常被认为是一个四层协议系统&#xff0c;如图1-1所示。每一层负责不同的功能&#xff1a; 1.链…

【Vue.js】使用Element中的Mock.js搭建首页导航左侧菜单---【超高级教学】

一&#xff0c;Mock.js 1.1 认识Mock.js Mock.js是一个用于前端开发中生成随机数据、模拟接口响应的 JavaScript 库。模拟数据的生成器&#xff0c;用来帮助前端调试开发、进行前后端的原型分离以及用来提高自动化测试效率 总结来说&#xff0c;Element中的Mock.js是一个用于…

ClassNotFoundException与NoClassDefFoundError

如果这springboot服务启动时两个报错同时出现&#xff0c;那大概率是依赖间冲突导致的 查资料发现是springcloud的依赖版本和springboot的依赖版本不兼容&#xff0c;顺藤摸瓜找到springcloud jar包中调用org.springframework.boot.context.properties.ConfigurationProperties…

《MySQL高级篇》十六、主从复制

文章目录 1、主从复制概述1.1 如何提升数据库并发能力1.2 主从复制的作用 2、主从复制的原理2.1 原理剖析2.2 复制的基本原则 3、一主一从架构搭建3.1 准备工作3.2 主机配置文件3.3 从机配置文件3.4 主机&#xff1a;建立账户并授权3.5 从机&#xff1a;配置需要复制的主机3.6 …

为何每个开发者都在谈论Go?

目录 一、引言Go的历史回顾关键时间节点 使用场景Go的语言地位技术社群与企业支持资源投入和生态系统 二、简洁的语法结构基本组成元素变量声明与初始化代码示例 类型推断函数与返回值代码示例输出 接口与结构体&#xff1a;组合而非继承错误处理&#xff1a;明确而不是异常小结…