深度学习框架YOLOv3的C++调用
深度學(xué)習(xí)框架YOLOv3的C++調(diào)用
- 深度學(xué)習(xí)框架YOLOv3的C++調(diào)用
- (1)tensorflow版本的YOLOv3的C++調(diào)用(失敗)
- (2)darknet版本的YOLOv3的C++調(diào)用一(失敗)
- (3)darknet版本的YOLOv3的C++調(diào)用二(成功)
深度學(xué)習(xí)框架YOLOv3的C++調(diào)用
因?yàn)轫?xiàng)目需要,我需要用C++調(diào)用YOLOv3來進(jìn)行物體檢測(cè),本文記錄了我嘗試的幾種調(diào)用方法,可能都有些旁門左道的感覺,大佬們不要見笑哈。
(1)tensorflow版本的YOLOv3的C++調(diào)用(失敗)
首先按照下面步驟把tensorflow版本的YOLOv3跑起來
(1)下載項(xiàng)目代碼
(2)下載完成后進(jìn)到項(xiàng)目目錄里:
cd keras-yolo3(3)YOLO官網(wǎng)下載weights文件或者執(zhí)行:
wget https://pjreddie.com/media/files/yolov3.weights(4)轉(zhuǎn)換YOLO的weights文件格式為Keras的格式:
python convert.py yolov3.cfg yolov3.weights model_data/yolo.h5(5) 缺什么裝什么,其中注意:ImportError: No module named PIL 錯(cuò)誤 的解決方法:
pip install Pillow(6)進(jìn)行測(cè)試
測(cè)試圖片:
測(cè)試視頻:
python yolo_video.py --input videos/traffic.mp4 --output videos/traffic_p.mp4下邊的命令不保存視頻:
python yolo_video.py --input videos/traffic.mp4啟動(dòng)攝像頭
python yolo_video.py --input /dev/video0前面都是成功的,然后我的思路是先用python寫一個(gè)調(diào)用上述YOLOv3的接口,然后用通過C++調(diào)用Python函數(shù)的方式滴調(diào)用這個(gè)接口,具體代碼就不貼了,實(shí)現(xiàn)在 我的GIthub 里面,反正是不好使的,會(huì)遇到如下的問題:
‘’’ File “/home/leo/anaconda2/envs/yolo/lib/python3.5/threading.py” assert tlock.locked() ‘’’
感覺應(yīng)該是c++調(diào)用anaconda里面的python3.5或者tensorflow的問題。因?yàn)槌薡OLOv3這個(gè)框架,還有那么多框架是基于tensorflow實(shí)現(xiàn)的,之前實(shí)現(xiàn)過是通過ROS節(jié)點(diǎn)實(shí)現(xiàn)的,不過直接調(diào)用這條路是肯定也是走得通的。
(2)darknet版本的YOLOv3的C++調(diào)用一(失敗)
darknet是YOLO的作者基于C寫的一個(gè)深度學(xué)習(xí)框架(牛逼!),通過python調(diào)用C編譯生成的動(dòng)態(tài)庫(kù)(.so文件),我的思路是還是通過C++調(diào)用python接口,代碼同樣在 我的GIthub 里面,然后慘痛經(jīng)歷如下:
(1)首先我嘗試了用c++給python傳mat數(shù)據(jù) 失敗!因?yàn)閐arknet壓根就沒有提供mat的數(shù)據(jù)接口,好坑啊,為什么!
(2)然后我嘗試了用c++給python傳一個(gè)float的指針,因?yàn)閕mage的data數(shù)據(jù)就是float 失敗!python的拓展接口里面沒有float*,沒法直接傳,因此得分裝成結(jié)構(gòu)體再?gòu)?qiáng)轉(zhuǎn),太麻煩,放棄吧
(2)最后我嘗試了修改darknet的接口,希望提供一個(gè)mat_to_image的接口,但是又遇到了c調(diào)用c++接口的namespace問題,剛剛好我的電腦裝的有事3.4.1版本的opencv,這一版opencv里面提供了c的接口,但是卻不能用c調(diào)用,3.4.0的好像就可以,哇,自己被自己坑到了
后來我幡然醒悟,.so文件不是可以直接通過C++調(diào)用嗎,為啥我要繞python這個(gè)彎呢?于是就有了最后一種成功的方法
(3)darknet版本的YOLOv3的C++調(diào)用二(成功)
這個(gè)方法我從頭開始講,我的電腦的GPU是750Ti的(比較渣),下面的配置我都是按照我的電腦配置的,首先你要裝好cuda以及opencv,我裝的是cuda8.0和opencv3.4.1,接下來就可以按照下面步驟進(jìn)行編譯了:
(1)首先下載YOLOv3
(2)下載權(quán)重
wget https://pjreddie.com/media/files/yolov3.weights(3)打開yolo.clf文件,按照如下修改對(duì)應(yīng)代碼,修改了batch、subdivisions、width、height(width,height越大精度會(huì)越高,但計(jì)算量也會(huì)越大,這個(gè)取決于你的GPU)
[net] # Testing batch=1 subdivisions=1 # Training #batch=64 #subdivisions=16 width=416 height=416(4)打開makefile文件找到對(duì)應(yīng)代碼進(jìn)行如下修改
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這里由于兩點(diǎn)要注意
1)下面這個(gè)配置是根據(jù)你的GPU的算力確定的,算力越高對(duì)應(yīng)數(shù)字越大,具體的GPU的算力可以再英偉達(dá)官網(wǎng)查到的
2)如果你沒有把opencv安裝在默認(rèn)路徑可能會(huì)遇到找不到opencv各種文件的問題,例如我之前只裝了ROS Kinetic,我希望用ROS Kinetic自帶的opencv編譯文件,然后就倒騰了下makefile的寫法,進(jìn)行如下修改鏈接到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其實(shí)思路和cmakelist是差不多的
COMMON+= 后面加的是頭文件
LDFLAGS+= 后面加的lib庫(kù), -L指的路徑, -l指的lib文件, 然后libopencv_core3.so鏈接進(jìn)來應(yīng)該改成-lopencv_core3,就這樣
(5)建立你的工程,把 libdarnet.so文件,darket.h,yolov3.cfg,coco.names,coco.data放到你的工程,然后寫個(gè)類把它調(diào)用起來就好了,下面一部分代碼是我從工程里摘抄出來的,能體現(xiàn)如何是調(diào)用接口的,但是并不能直接運(yùn)行起來哈,需要進(jìn)行一部分修改
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數(shù)據(jù)轉(zhuǎn)成Image類型//下面的檢測(cè)過程是仿照python接口寫的,還沒有太弄明白是怎么回事,具體可能需要花時(shí)間看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//獲取檢測(cè)結(jié)果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;//把這個(gè)類單獨(dú)放一個(gè)h文件是因?yàn)镕rame類的編譯鏈接問題 class DetectResult { public:string mName;float mConfidence;float mTop;float mBottom;float mLeft;float mRight;bool mbGoodFlag = false;//不是好的檢測(cè)結(jié)果 };#endif //PROJECT_DETECTRESULT_H這部分代碼其實(shí)是我做語義SLAM中間調(diào)用YOLOv3的一部分,參考代碼在 我的Github中,通過上面的接口就能調(diào)用起來YOLOv3了,這種方法主要是因?yàn)閅OLOv3是基于c實(shí)現(xiàn)的,其他的深度學(xué)習(xí)框架的C++調(diào)用應(yīng)該還是通過第一種方法實(shí)現(xiàn)。
總結(jié)
以上是生活随笔為你收集整理的深度学习框架YOLOv3的C++调用的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 超像素SLIC算法源码阅读
- 下一篇: 从零开始使用Realsense D435