環境:
系統:win10 (顯卡:NVIDIA GTX 950M)
Yolo版本:V3
cuda:9.0
cudnn:9.0
opencv:3.4.9
VS:2015
1、環境准備:
1.1、下載Yolov3(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; }
6、運行結果
報錯:error MSB3721
解決辦法:
問題產生的原因:
sm_XX,compute_XX:表示自己電腦顯卡的計算能力,顯卡越好值越高,自己顯卡對應的值可以查看英偉達官網
由於自己電腦顯卡有好有壞,對應的sm_XX,compute_XX值也不一樣,出現上述錯誤的原因主要是當前運行的程序里的sm_XX,compute_XX值選取不當。如下圖是我自己程序中設置sm_XX,compute_XX的值。(我將sm_30改為了sm_35可以)
參考鏈接:
