深度学习框架YOLOv3的C++调用
深度學習框架YOLOv3的C++調用
- 深度學習框架YOLOv3的C++調用
- (1)tensorflow版本的YOLOv3的C++調用(失敗)
- (2)darknet版本的YOLOv3的C++調用一(失敗)
- (3)darknet版本的YOLOv3的C++調用二(成功)
深度學習框架YOLOv3的C++調用
因為項目需要,我需要用C++調用YOLOv3來進行物體檢測,本文記錄了我嘗試的幾種調用方法,可能都有些旁門左道的感覺,大佬們不要見笑哈。
(1)tensorflow版本的YOLOv3的C++調用(失敗)
首先按照下面步驟把tensorflow版本的YOLOv3跑起來
(1)下載項目代碼
(2)下載完成后進到項目目錄里:
cd keras-yolo3(3)YOLO官網下載weights文件或者執行:
wget https://pjreddie.com/media/files/yolov3.weights(4)轉換YOLO的weights文件格式為Keras的格式:
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5(5) 缺什么裝什么,其中注意:ImportError: No module named PIL 錯誤 的解決方法:
pip install Pillow(6)進行測試
測試圖片:
測試視頻:
python yolo_video.py --input videos/traffic.mp4 --output videos/traffic_p.mp4下邊的命令不保存視頻:
python yolo_video.py --input videos/traffic.mp4啟動攝像頭
python yolo_video.py --input /dev/video0前面都是成功的,然后我的思路是先用python寫一個調用上述YOLOv3的接口,然后用通過C++調用Python函數的方式滴調用這個接口,具體代碼就不貼了,實現在 我的GIthub 里面,反正是不好使的,會遇到如下的問題:
‘’’ File “/home/leo/anaconda2/envs/yolo/lib/python3.5/threading.py” assert tlock.locked() ‘’’
感覺應該是c++調用anaconda里面的python3.5或者tensorflow的問題。因為除了YOLOv3這個框架,還有那么多框架是基于tensorflow實現的,之前實現過是通過ROS節點實現的,不過直接調用這條路是肯定也是走得通的。
(2)darknet版本的YOLOv3的C++調用一(失敗)
darknet是YOLO的作者基于C寫的一個深度學習框架(牛逼!),通過python調用C編譯生成的動態庫(.so文件),我的思路是還是通過C++調用python接口,代碼同樣在 我的GIthub 里面,然后慘痛經歷如下:
(1)首先我嘗試了用c++給python傳mat數據 失敗!因為darknet壓根就沒有提供mat的數據接口,好坑啊,為什么!
(2)然后我嘗試了用c++給python傳一個float的指針,因為image的data數據就是float 失敗!python的拓展接口里面沒有float*,沒法直接傳,因此得分裝成結構體再強轉,太麻煩,放棄吧
(2)最后我嘗試了修改darknet的接口,希望提供一個mat_to_image的接口,但是又遇到了c調用c++接口的namespace問題,剛剛好我的電腦裝的有事3.4.1版本的opencv,這一版opencv里面提供了c的接口,但是卻不能用c調用,3.4.0的好像就可以,哇,自己被自己坑到了
后來我幡然醒悟,.so文件不是可以直接通過C++調用嗎,為啥我要繞python這個彎呢?于是就有了最后一種成功的方法
(3)darknet版本的YOLOv3的C++調用二(成功)
這個方法我從頭開始講,我的電腦的GPU是750Ti的(比較渣),下面的配置我都是按照我的電腦配置的,首先你要裝好cuda以及opencv,我裝的是cuda8.0和opencv3.4.1,接下來就可以按照下面步驟進行編譯了:
(1)首先下載YOLOv3
(2)下載權重
wget https://pjreddie.com/media/files/yolov3.weights(3)打開yolo.clf文件,按照如下修改對應代碼,修改了batch、subdivisions、width、height(width,height越大精度會越高,但計算量也會越大,這個取決于你的GPU)
[net] # Testing batch=1 subdivisions=1 # Training #batch=64 #subdivisions=16 width=416 height=416(4)打開makefile文件找到對應代碼進行如下修改
GPU=1 CUDNN=1 OPENCV=1 OPENMP=0 DEBUG=0 ... ARCH= -gencode arch=compute_50,code=sm_50 \ ... ifeq ($(GPU), 1) COMMON+= -DGPU -I/usr/local/cuda-8.0/include/ CFLAGS+= -DGPU LDFLAGS+= -L/usr/local/cuda-8.0/lib64 -lcuda -lcudart -lcublas -lcurand endif ... NVCC=/usr/local/cuda-8.0/bin/nvcc這里由于兩點要注意
1)下面這個配置是根據你的GPU的算力確定的,算力越高對應數字越大,具體的GPU的算力可以再英偉達官網查到的
2)如果你沒有把opencv安裝在默認路徑可能會遇到找不到opencv各種文件的問題,例如我之前只裝了ROS Kinetic,我希望用ROS Kinetic自帶的opencv編譯文件,然后就倒騰了下makefile的寫法,進行如下修改鏈接到opencv即可
ifeq ($(OPENCV), 1) COMMON+= -DOPENCV -I/opt/ros/kinetic/include/opencv-3.3.1-dev CFLAGS+= -DOPENCV -I/opt/ros/kinetic/include/opencv-3.3.1-dev LDFLAGS+= -L/opt/ros/kinetic/lib/x86_64-linux-gnu -lopencv_core3 -lopencv_highgui3 -lopencv_videoio3 -lopencv_imgcodecs3 COMMON+= -I/opt/ros/kinetic/include/opencv-3.3.1-dev endif其實思路和cmakelist是差不多的
COMMON+= 后面加的是頭文件
LDFLAGS+= 后面加的lib庫, -L指的路徑, -l指的lib文件, 然后libopencv_core3.so鏈接進來應該改成-lopencv_core3,就這樣
(5)建立你的工程,把 libdarnet.so文件,darket.h,yolov3.cfg,coco.names,coco.data放到你的工程,然后寫個類把它調用起來就好了,下面一部分代碼是我從工程里摘抄出來的,能體現如何是調用接口的,但是并不能直接運行起來哈,需要進行一部分修改
Detecting.cpp
#include "Detecting.h" namespace YOLO {Detecting::Detecting(){string ConfigPath = "/home/leo/Desktop/sematic_slam_project/src/sematic_slam/YOLO_V3/config/yolov3.cfg";string WeightsPath = "/home/leo/Desktop/Data/yolov3.weights";string MetaDataPath = "/home/leo/Desktop/sematic_slam_project/src/sematic_slam/YOLO_V3/config/coco.data";mpNetwork = load_network((char *) ConfigPath.data(), (char *) WeightsPath.data(), 0);mData = get_metadata((char *) MetaDataPath.data());mpTransMethod = new TransMethod;}void Detecting::Detect(cv::Mat Frame, vector<DetectResult>& vDetectResults){vDetectResults.clear();image Image = mpTransMethod->MattoImage(Frame);//講Mat數據轉成Image類型//下面的檢測過程是仿照python接口寫的,還沒有太弄明白是怎么回事,具體可能需要花時間看paper了,先把框架搭起來吧int *pCount = new int(0);network_predict_image(mpNetwork, Image);detection *pDetection = get_network_boxes(mpNetwork, Image.w, Image.h, 0.5, 0.5, nullptr, 0,pCount);//第一步:get_network_boxesdo_nms_obj(pDetection, *pCount, mData.classes, 0.45);//第二步:do_nms_obj//獲取檢測結果for (size_t j = 0; j < *pCount; j++){for (size_t i = 0; i < mData.classes; i++){if (pDetection[j].prob[i] > 0){DetectResult Result;Result.mName = mData.names[i];Result.mConfidence = pDetection[j].prob[i];Result.mTop = (pDetection[j].bbox.y - pDetection[j].bbox.h / 2);Result.mBottom = (pDetection[j].bbox.y + pDetection[j].bbox.h / 2);Result.mLeft = (pDetection[j].bbox.x - pDetection[j].bbox.w / 2);Result.mRight = (pDetection[j].bbox.x + pDetection[j].bbox.w / 2);vDetectResults.push_back(Result);}}}}void Detecting::DrawResult( cv::Mat &Image, vector<DetectResult> Result){for (vector<DetectResult>::iterator it = Result.begin(); it != Result.end(); it++){cv::Point2f PointA(it->mLeft, it->mTop);cv::Point2f PointB(it->mRight, it->mBottom);cv::rectangle(Image, PointA, PointB, cv::Scalar(5, 100, 255), 5);}} }Detecting.h
// // Created by leo on 18-11-13. //#ifndef PROJECT_DETECTING_H #define PROJECT_DETECTING_H#include <string> #include <YOLO_V3/include/darknet.h> #include <opencv2/opencv.hpp> #include <opencv2/core.hpp> #include <opencv2/highgui.hpp> #include <condition_variable> #include "DetectResult.h" #include "ORB_SLAM2/include/Tracking.h"using namespace std; namespace YOLO {class TransMethod;class Tracking;class Detecting{public:Detecting();void Detect(cv::Mat Frame, vector<DetectResult>& vDetectResults);void DrawResult( cv::Mat &Image, vector<DetectResult> Result);private:network *mpNetwork;metadata mData;TransMethod *mpTransMethod;};class TransMethod{public:image MattoImage(cv::Mat m){IplImage ipl = m;image im = IpltoImage(&ipl);rgbgr_image(im);return im;}private:image IpltoImage(IplImage *src){int h = src->height;int w = src->width;int c = src->nChannels;image im = make_image(w, h, c);unsigned char *data = (unsigned char *) src->imageData;int step = src->widthStep;int i, j, k;for (i = 0; i < h; ++i){for (k = 0; k < c; ++k){for (j = 0; j < w; ++j){im.data[k * w * h + i * w + j] = data[i * step + j * c + k] / 255.;}}}return im;}}; } #endif //PROJECT_DETECTING_HDetectResult.h
// // Created by leo on 18-11-20. //#ifndef PROJECT_DETECTRESULT_H #define PROJECT_DETECTRESULT_H#include <string>using namespace std;//把這個類單獨放一個h文件是因為Frame類的編譯鏈接問題 class DetectResult { public:string mName;float mConfidence;float mTop;float mBottom;float mLeft;float mRight;bool mbGoodFlag = false;//不是好的檢測結果 };#endif //PROJECT_DETECTRESULT_H這部分代碼其實是我做語義SLAM中間調用YOLOv3的一部分,參考代碼在 我的Github中,通過上面的接口就能調用起來YOLOv3了,這種方法主要是因為YOLOv3是基于c實現的,其他的深度學習框架的C++調用應該還是通過第一種方法實現。
總結
以上是生活随笔為你收集整理的深度学习框架YOLOv3的C++调用的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超像素SLIC算法源码阅读
- 下一篇: 从零开始使用Realsense D435