1. 程式人生 > 實用技巧 >VS+Yolov3+QT+opencv(GPU版)

VS+Yolov3+QT+opencv(GPU版)

環境: 系統:win10 (顯示卡:NVIDIA GTX 950M) Yolo版本:V3 cuda:9.0 cudnn:9.0 opencv:3.4.9 VS:2015

1、環境準備:

1.1、下載Yolov3(darknet)

下載連結:https://github.com/AlexeyAB/darknet

1.2、下載權重檔案(yolov3.weights)

下載連結:https://link.csdn.net/?target=https%3A%2F%2Fpjreddie.com%2Fmedia%2Ffiles%2Fyolov3.weights 下載完成後,將yolov3.weights檔案複製到E:\yolo\darknet-master\darknet-master\build\darknet\x64目錄下。

1.3、下載CUDA 9.0

下載連結:連結:https://pan.baidu.com/s/1LLMmFVOCSLvaY4GzTuVYcg 提取碼:kkvb 安裝過程網上搜教程就行了,挺簡單的(PS:CUDA版本需根據自己電腦配置選擇,我電腦顯示卡是:NVIDIA GTX 950M的,一開始我裝CUDA10.0和11.0都不行,後來改為9.0可以了,也是一波三折)

1.4、下載CUDNN 9.0

下載連結:連結:https://pan.baidu.com/s/1d-yigqIoy9q6Ha5-fdJkSA 提取碼:74kw 將裡面3個資料夾裡的每個檔案複製到C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v9.0目錄下對應的資料夾中即可。

1.4、opencv3.4.9和VS2015

網上搜索安裝即可並將opencv配置到VS2015中

2、編譯Yolo

2.1、編譯darknet.exe

2.1.1、找到darknet.vcxproj用EditPlus開啟CTRL+F搜尋CUDA 11.1全部改為9.0然後儲存。共2處

2.1.2、開啟darknet.sln

修改為Release X64模式,然後生成即可。

3、執行yolov3

雙擊darknet_yolo_v3.cmd識別圖片例項;而darknet_web_cam_voc.cmd是開啟筆記本攝像頭動態檢測識別。

4、編譯Yolov3動態連結庫

開啟yolo_cpp_dll.sln在Release X64模式下生成(也要修改yolo_cpp_dll.vcxproj中的cuda版本) 會生成yolo_cpp_dll.dll和yolo_cpp_dll.lib的庫檔案

5、使用yolo的動態連結庫進行開發

使用yolo編譯好的yolo_cpp_dll.dll和yolo_cpp_dll.lib的庫檔案和API:yolo_v2_class.hpp標頭檔案 mainwindow.h
#pragma
once //這段程式碼一定要加,這是在yolo_v2_class.hpp檔案中使用opencv函式 #ifdef _WIN32 #define OPENCV #define GPU #endif #include <QtWidgets/QMainWindow> #include "ui_mianwindow.h" #include "yolo_v2_class.hpp" #include "opencv\highgui.h" #include "opencv2\opencv.hpp" #include "opencv2\core\core.hpp" #include "opencv2\highgui\highgui.hpp" #include <iostream> #include <stdio.h> #pragma comment(lib, "yolo_cpp_dll.lib")//引入yolo連結庫 #pragma execution_character_set("utf-8") using namespace cv; class mianwindow : public QMainWindow { Q_OBJECT public: mianwindow(QWidget *parent = Q_NULLPTR); void draw_boxes(Mat mat_img, std::vector<bbox_t> result_vec, std::vector<std::string> obj_names); std::vector<std::string> objects_names_from_file(std::string const filename); QImage cvMat2QImage(const Mat& mat); Mat QImage2cvMat(QImage image); private: Ui::mianwindowClass ui; };

mainwindow.cpp

#include "mianwindow.h"
#include "yolo_v2_class.hpp"
#include <QDebug>
mianwindow::mianwindow(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    QImage q_image(QString("E:/TX_workCode/DataInfo/images/dog.jpg"));

    ui.label_img->setPixmap(QPixmap::fromImage(q_image));
    
    std::string names_file = "coco.names";
    std::string cfg_file = "yolov3.cfg";
    std::string weights_file = "yolov3.weights";
    Detector detector(cfg_file, weights_file); //初始化Detector

    std::vector<std::string> obj_names;
    obj_names = objects_names_from_file(names_file);
    //測試是否成功讀入分類物件檔案
    for (int i = 0; i < obj_names.size(); i++)
    {
        qDebug() << "第i個:" << QString(QString::fromLocal8Bit(obj_names[i].c_str()));
    }
    
    Mat frame = QImage2cvMat(q_image);
    std::vector<bbox_t> result_vec = detector.detect(frame);
    draw_boxes(frame, result_vec, obj_names);

    QImage det_image = cvMat2QImage(frame);
    ui.label_detectorImg->setPixmap(QPixmap::fromImage(det_image));

}
//以下draw_boxes和objects_names_from_file兩段程式碼來自yolo_console_dll.sln
//給Mat型別的影象畫出檢測出物件框
void mianwindow::draw_boxes(cv::Mat mat_img, std::vector<bbox_t> result_vec, std::vector<std::string> obj_names)
{
    int const colors[6][3] = { { 1,0,1 },{ 0,0,1 },{ 0,1,1 },{ 0,1,0 },{ 1,1,0 },{ 1,0,0 } };
    for (auto &i : result_vec) {
        cv::Scalar color = obj_id_to_color(i.obj_id);
        cv::rectangle(mat_img, cv::Rect(i.x, i.y, i.w, i.h), color, 2);
        if (obj_names.size() > i.obj_id) {
            std::string obj_name = obj_names[i.obj_id];
            if (i.track_id > 0) obj_name += " - " + std::to_string(i.track_id);
            cv::Size const text_size = getTextSize(obj_name, cv::FONT_HERSHEY_COMPLEX_SMALL, 1.2, 2, 0);
            int const max_width = (text_size.width > i.w + 2) ? text_size.width : (i.w + 2);
            cv::rectangle(mat_img, cv::Point2f(std::max((int)i.x - 1, 0), std::max((int)i.y - 30, 0)),
                cv::Point2f(std::min((int)i.x + max_width, mat_img.cols - 1), std::min((int)i.y, mat_img.rows - 1)),
                color, CV_FILLED, 8, 0);
            putText(mat_img, obj_name, cv::Point2f(i.x, i.y - 10), cv::FONT_HERSHEY_COMPLEX_SMALL, 1.2, cv::Scalar(0, 0, 0), 2);
        }
    }

}
//讀names檔案中物件類別名稱儲存在vector<std::string>容器中
std::vector<std::string> mianwindow::objects_names_from_file(std::string const filename) {
    std::ifstream file(filename);
    std::vector<std::string> file_lines;
    if (!file.is_open()) return file_lines;
    for (std::string line; getline(file, line);) file_lines.push_back(line);
    std::cout << "object names loaded \n";
    return file_lines;
}

//---------QImage與Mat型別相互轉換----------------------------------------------------------
QImage mianwindow::cvMat2QImage(const cv::Mat& mat)
{
    // 8-bits unsigned, NO. OF CHANNELS = 1  
    if (mat.type() == CV_8UC1)
    {
        QImage image(mat.cols, mat.rows, QImage::Format_Indexed8);
        // Set the color table (used to translate colour indexes to qRgb values)  
        image.setColorCount(256);
        for (int i = 0; i < 256; i++)
        {
            image.setColor(i, qRgb(i, i, i));
        }
        // Copy input Mat  
        uchar *pSrc = mat.data;
        for (int row = 0; row < mat.rows; row++)
        {
            uchar *pDest = image.scanLine(row);
            memcpy(pDest, pSrc, mat.cols);
            pSrc += mat.step;
        }
        return image;
    }
    // 8-bits unsigned, NO. OF CHANNELS = 3  
    else if (mat.type() == CV_8UC3)
    {
        // Copy input Mat  
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat  
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_RGB888);
        return image.rgbSwapped();
    }
    else if (mat.type() == CV_8UC4)
    {
        qDebug() << "CV_8UC4";
        // Copy input Mat  
        const uchar *pSrc = (const uchar*)mat.data;
        // Create QImage with same dimensions as input Mat  
        QImage image(pSrc, mat.cols, mat.rows, mat.step, QImage::Format_ARGB32);
        return image.copy();
    }
    else
    {
        qDebug() << "ERROR: Mat could not be converted to QImage.";
        return QImage();
    }
}
cv::Mat mianwindow::QImage2cvMat(QImage image)
{
    cv::Mat mat;
    qDebug() << image.format();
    switch (image.format())
    {
    case QImage::Format_ARGB32:
    case QImage::Format_RGB32:
    case QImage::Format_ARGB32_Premultiplied:
        mat = cv::Mat(image.height(), image.width(), CV_8UC4, (void*)image.constBits(), image.bytesPerLine());
        break;
    case QImage::Format_RGB888:
        mat = cv::Mat(image.height(), image.width(), CV_8UC3, (void*)image.constBits(), image.bytesPerLine());
        cv::cvtColor(mat, mat, CV_BGR2RGB);
        break;
    case QImage::Format_Indexed8:
        mat = cv::Mat(image.height(), image.width(), CV_8UC1, (void*)image.constBits(), image.bytesPerLine());
        break;
    }
    return mat;
}

報錯:error MSB3721

解決辦法: 問題產生的原因: sm_XX,compute_XX:表示自己電腦顯示卡的計算能力,顯示卡越好值越高,自己顯示卡對應的值可以檢視英偉達官網 由於自己電腦顯示卡有好有壞,對應的sm_XX,compute_XX值也不一樣,出現上述錯誤的原因主要是當前執行的程式裡的sm_XX,compute_XX值選取不當。如下圖是我自己程式中設定sm_XX,compute_XX的值。(我將sm_30改為了sm_35可以) 參考連結: 1、https://blog.csdn.net/lixudem/article/details/106993430?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-6.control 2、https://blog.csdn.net/sinat_41852207/article/details/90906309?utm_medium=distribute.pc_relevant.none-task-blog-OPENSEARCH-5.control&depth_1-utm_source=distribute.pc_relevant.none-task-blog-OPENSEARCH-5.control 3、https://blog.csdn.net/alansss/article/details/104448347?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161095690516780271532753%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=161095690516780271532753&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-3-104448347.first_rank_v2_pc_rank_v29&utm_term=win10%E7%BC%96%E8%AF%91yolov3%E6%97%B6%E6%8A%A5%E9%94%99error%20MSB3721&spm=1018.2226.3001.4187 4、https://blog.csdn.net/jin739738709/article/details/90342696 5、https://blog.csdn.net/stjuliet/article/details/87884976?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522161102361916780269894467%2522%252C%2522scm%2522%253A%252220140713.130102334.pc%255Fall.%2522%257D&request_id=161102361916780269894467&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2~all~first_rank_v2~rank_v29-3-87884976.first_rank_v2_pc_rank_v29&utm_term=%E4%BD%BF%E7%94%A8yolo%E7%9A%84%E5%8A%A8%E6%80%81%E9%93%BE%E6%8E%A5%E5%BA%93&spm=1018.2226.3001.4187