0


yolov5 opencv dnn部署 github代码

yolov5 opencv dnn部署 github代码

源码地址

  1. yolov5官网还提供的dnn、tensorrt推理链接
  2. 本人使用的opencv c++ github代码,代码作者非本人,也是上面作者推荐的链接之一

实现推理源码中作者的yolov5s.onnx

推理条件

实现推理code中作者的yolov5s.onnx
windows 10
Visual Studio 2019
Nvidia GeForce GTX 1070
opencv 4.5.5、opencv4.7.0 (注意 4.7.0代码不适用,如果要使用opencv4.7.0来进行推理,可能会出现下面的问题图1 problem中的问题)(但是,如果添加了之后,4.7.0的推理速度会比4.5.5的速度慢了不少)
请添加图片描述

      图 
     
    
      1 
     
    
      p 
     
    
      r 
     
    
      o 
     
    
      b 
     
    
      l 
     
    
      e 
     
    
      m 
     
    
   
     图1 problem 
    
   
 图1problem

解决方法请添加图片描述

      图 
     
    
      1 
     
    
      s 
     
    
      o 
     
    
      l 
     
    
      v 
     
    
      t 
     
    
      i 
     
    
      o 
     
    
      n 
     
    
   
     图1 solvtion 
    
   
 图1solvtion
python部署(因为python比较简单就直接介绍了)

一、直接用VScode打开代码
二、然后在终端输入命令

python python/yolo.py

请添加图片描述
三、结果如下图所示
请添加图片描述

c++部署

当然不管是使用opencv dnn的cpu还是gpu都得创建相应的环境,这里先不做介绍,以后有时间再介绍。
一、使用VS2019创建一个新的项目,这里不做过多赘述
二、该项目搭建公共的opencv属性,或者使用已搭建好的公共的opencv455属性(以opencv455为例,添加其它的也是这样的,例如opencv455_cuda等)
这里如果使用公共的opencv455属性,只需要在新建的c++空项目中使用以下步骤即可添加
1、 “属性管理器”——>“鼠标右键点击Release|x64”——>“添加现有属性表(E)”
在这里插入图片描述
2、 选在对应的已创建好的属性表,然后点击“打开”
在这里插入图片描述
3、添加后的结果
在这里插入图片描述
三、将code中的下列文件复制到新建的项目中的

repos/Project4/Project4

中,如下图所示
在这里插入图片描述
四、将code中的

cpp/yolo.cpp

添加到新建项目的

源文件

中,添加过程和结果如下图所示
在这里插入图片描述
结果
在这里插入图片描述
五、使用x64进行Release,结果如下图所示
1、opencv4.5.5推理结果
在这里插入图片描述
2、opencv4.7.0推理结果
在这里插入图片描述

六、yolo.cpp的代码在这(本人应该没做改动吧,忘记了)

#include<fstream>#include<opencv2/opencv.hpp>/*下文所有注释全是自我理解*//*加载classes.txt*/
std::vector<std::string>load_class_list(){
    std::vector<std::string> class_list;// 该行代码可以理解为申明一个可变容量的字符串数组class_list
    std::ifstream ifs("config_files/classes.txt");
    std::string line;while(getline(ifs, line)){
        class_list.push_back(line);}return class_list;}voidload_net(cv::dnn::Net& net,bool is_cuda){auto result = cv::dnn::readNet("config_files/yolov5s.onnx");if(is_cuda){
        std::cout <<"Attempty to use CUDA\n";
        result.setPreferableBackend(cv::dnn::DNN_BACKEND_CUDA);// result.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA_FP16);
        result.setPreferableTarget(cv::dnn::DNN_TARGET_CUDA);// 经过验证,这里必须去掉FP16,才能使用cuda加速,就是yolov5导出的是half onnx也不行,opencv只能读取16,但是还是按照32运行的}else{
        std::cout <<"Running on CPU\n";
        result.setPreferableBackend(cv::dnn::DNN_BACKEND_OPENCV);
        result.setPreferableTarget(cv::dnn::DNN_TARGET_CPU);}
    net = result;}const std::vector<cv::Scalar> colors ={ cv::Scalar(255,255,0), cv::Scalar(0,255,0), cv::Scalar(0,255,255), cv::Scalar(255,0,0)};constfloat INPUT_WIDTH =640.0;constfloat INPUT_HEIGHT =640.0;constfloat SCORE_THRESHOLD =0.2;// NMS中的score阈值(一般来说,这个应该是conf * class的阈值)constfloat NMS_THRESHOLD =0.4;// NMS中的IoU阈值constfloat CONFIDENCE_THRESHOLD =0.4;// conf阈值 (class, conf, x, y, w, h)structDetection{int class_id;float confidence;
    cv::Rect box;};/*这个作用是将需要预测的图片都变为正方形图片,以左上角对齐,将短的边都填充0*/
cv::Mat format_yolov5(const cv::Mat& source){int col = source.cols;int row = source.rows;int _max =MAX(col, row);
    cv::Mat result = cv::Mat::zeros(_max, _max, CV_8UC3);
    source.copyTo(result(cv::Rect(0,0, col, row)));return result;}voiddetect(cv::Mat& image, cv::dnn::Net& net, std::vector<Detection>& output,const std::vector<std::string>& className){
    cv::Mat blob;auto input_image =format_yolov5(image);

    cv::dnn::blobFromImage(input_image, blob,1./255., cv::Size(INPUT_WIDTH, INPUT_HEIGHT), cv::Scalar(),true,false);// 将预测图片resize到640,并将所有的像素都归一化
    net.setInput(blob);
    std::vector<cv::Mat> outputs;// 预测框作为一个矩阵保存在Mat,这个可变数组永远只有一个Mat,因为一个Mat即可保存所有的预测框,类似于图片[1, H, W],所以下文中outputs[0].data是所有预测框的地址
    net.forward(outputs, net.getUnconnectedOutLayersNames());float x_factor = input_image.cols / INPUT_WIDTH;// 缩放因子float y_factor = input_image.rows / INPUT_HEIGHT;float* data =(float*)outputs[0].data;constint dimensions =85;// 其实就是COCO的class + conf + xywhconstint rows =25200;// pre_box的数量小于25200

    std::vector<int> class_ids;
    std::vector<float> confidences;
    std::vector<cv::Rect> boxes;// 原始的NMS使用的非极大值抑制,并不是yolov5中的多分类非极大值抑制for(int i =0; i < rows;++i){float confidence = data[4];if(confidence >= CONFIDENCE_THRESHOLD){float* classes_scores = data +5;
            cv::Mat scores(1, className.size(), CV_32FC1, classes_scores);// 将classes_scores转化为一个Mat格式的数据
            cv::Point class_id;double max_class_score;minMaxLoc(scores,0,&max_class_score,0,&class_id);// 将scores中的最大的值以及其id分别赋给max_class_score, class_idif(max_class_score > SCORE_THRESHOLD){

                confidences.push_back(confidence);

                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 +=85;// 这个是cv::Mat中的每一个[x, y, w, h, conf, class]的首地址,一个预测框的首地址都加85[xywh+conf+class]即[5+80]后就是下一个预测框的首地址}

    std::vector<int> nms_result;
    cv::dnn::NMSBoxes(boxes, confidences, SCORE_THRESHOLD, NMS_THRESHOLD, nms_result);// 将NMS筛选之后的索引返回给nms_resultfor(int i =0; i < nms_result.size(); i++){int idx = nms_result[i];
        Detection result;
        result.class_id = class_ids[idx];
        result.confidence = confidences[idx];
        result.box = boxes[idx];
        output.push_back(result);}}intmain(int argc,char** argv){

    std::vector<std::string> class_list =load_class_list();

    cv::Mat frame;
    cv::VideoCapture capture("sample.mp4");if(!capture.isOpened()){
        std::cerr <<"Error opening video file\n";return-1;}//bool is_cuda = argc > 1 && strcmp(argv[1], "cuda") == 0;bool is_cuda =true;

    cv::dnn::Net net;load_net(net, is_cuda);auto start = std::chrono::high_resolution_clock::now();int frame_count =0;float fps =-1;int total_frames =0;while(true){
        capture.read(frame);if(frame.empty()){
            std::cout <<"End of stream\n";break;}

        std::vector<Detection> output;detect(frame, net, output, class_list);

        frame_count++;
        total_frames++;int detections = output.size();for(int i =0; i < detections;++i){auto detection = output[i];auto box = detection.box;auto classId = detection.class_id;constauto color = colors[classId % colors.size()];
            cv::rectangle(frame, box, color,3);

            cv::rectangle(frame, cv::Point(box.x, box.y -20), cv::Point(box.x + box.width, box.y), color, cv::FILLED);
            cv::putText(frame, class_list[classId].c_str(), cv::Point(box.x, box.y -5), cv::FONT_HERSHEY_SIMPLEX,0.5, cv::Scalar(0,0,0));}if(frame_count >=30){auto end = std::chrono::high_resolution_clock::now();
            fps = frame_count *1000.0/ std::chrono::duration_cast<std::chrono::milliseconds>(end - start).count();

            frame_count =0;
            start = std::chrono::high_resolution_clock::now();}if(fps >0){

            std::ostringstream fps_label;
            fps_label << std::fixed << std::setprecision(2);
            fps_label <<"FPS: "<< fps;
            std::string fps_label_str = fps_label.str();

            cv::putText(frame, fps_label_str.c_str(), cv::Point(10,25), cv::FONT_HERSHEY_SIMPLEX,1, cv::Scalar(0,0,255),2);}

        cv::imshow("output", frame);if(cv::waitKey(1)!=-1){
            capture.release();
            std::cout <<"finished by user\n";break;}}

    std::cout <<"Total frames: "<< total_frames <<"\n";return0;}

参考链接

  • 代码参考链接
  1. https://github.com/doleron/yolov5-opencv-cpp-python
  2. https://github.com/Hexmagic/ONNX-yolov5/tree/master
  3. https://github.com/yzy12-max/yolov5_deploy(这个是理论参考链接2中对应的仓库)
  • 理论参考链接
  1. https://github.com/ultralytics/yolov5/issues/251
  2. https://blog.csdn.net/weixin_41311686/article/details/128421801(这个的是另外的代码推理解析部分,值得一看)
标签: YOLO opencv dnn

本文转载自: https://blog.csdn.net/shilichangtin/article/details/135737487
版权归原作者 yuanjun0416 所有, 如有侵权,请联系我们删除。

“yolov5 opencv dnn部署 github代码”的评论:

还没有评论