本文讲述如何在ubuntu20.04(其他版本系统也适用)下编译官方darknet框架下YOLOV3并使用提供的coco数据集的预训练权重检测识别图片。
Opencv4 这里会和官方教程有一些出入,2021-2022年的时候ubuntu里安装的多是opecv4,编译darknet YOLO的时候可能因为opencv和opencv4会报错 No package ‘opencv’ found。
CUDA
https://pjreddie.com/darknet/yolo/
新建一个空文件夹,在当前路径下打开命令行,输入下面命令git clone下载,cd进下载的文件夹,编译。
git clone https://github.com/pjreddie/darknet
cd darknet
make
在darknet/makefile 里可以看到默认的make是不用gpu和opencv cudnn的。
GPU=0
CUDNN=0
OPENCV=0
OPENMP=0
DEBUG=0
下载权重文件,这里我是在/darknet/cfg文件夹路径下下载的,也可以放在不同的路径下,之后指明对应路径就行。权重248MB大小。
wget https://pjreddie.com/media/files/yolov3.weights
运行检测,检测对象是自带的darknet/dog.jpg. cfg/yolv3.cfg 是自带的,weights是刚刚下载的248MB。
./darknet detect cfg/yolov3.cfg cfg/yolov3.weights data/dog.jpg
如果weights下载在darknet路径下,可以
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
命令行会输出:
同时darknet文件夹内生成一张图片名叫predictions.jpg
至此,CPU运行YOLOV3成功跑通,识别效果也不错。
但是命令行结果里可以看出,在10700fcpu上花了17s多,比较长,下面开始gpu实现。
需要cuda和驱动已经安装好。Cudnn可以不需要。
nvidia-smi
如果之前make过,先在darknet路径下打开命令行,make clean, 很快,几秒完成。
make clean
然后打开 dakenet/makefile,可以用im或者记事本打开,将最前面的几行改为
GPU=1
CUDNN=0
OPENCV=1
OPENMP=0
DEBUG=0
保存后直接make会报错 No package ‘opencv’ found。需要改为opencv4.
No package 'opencv' found
./src/image_opencv.cpp:12:1: error: ‘IplImage’ does not name a type
12 | IplImage *image_to_ipl(image im)
| ^~~~~~~~
compilation terminated due to -Wfatal-errors.
make: *** [Makefile:86: obj/image_opencv.o] Error 1
whereis opencv,找不到但是可以找到 whereis opencv4.
(base) xxxx:~/xxxxt/darknet$ whereis opencv
opencv:
(base) xxxx:~/xxxx/darknet$ whereis opencv4
opencv4: /usr/include/opencv4 /usr/share/opencv4
将makefile里的45 46行原本的opencv改为opencv4
ifeq ($(OPENCV), 1)
COMMON+= -DOPENCV
CFLAGS+= -DOPENCV
LDFLAGS+= `pkg-config --libs opencv4` -lstdc++
COMMON+= `pkg-config --cflags opencv4`
endif
然饿仍然会有报错:
‵./src/image_opencv.cpp:12:1: error: ‘IplImage’ does not name a type
12 | IplImage *image_to_ipl(image im)
| ^~~~~~~~
compilation terminated due to -Wfatal-errors.
make: *** [Makefile:86: obj/image_opencv.o] Error 1
这时候新建一个文本文档叫做patch.diff,将以下内容复制进新建的文档并且git apply diff
ref:https://stackoverflow.com/questions/64885148/error-iplimage-does-not-name-a-type-when-trying-to-build-darknet-with-opencv
diff --git a/src/image_opencv.cpp b/src/image_opencv.cpp
index 7511280..c11805a 100644
--- a/src/image_opencv.cpp
+++ b/src/image_opencv.cpp
@@ -9,30 +9,34 @@ using namespace cv;
extern "C" {
-IplImage *image_to_ipl(image im)
+Mat image_to_mat(image im)
{
+ assert(im.c == 3 || im.c == 1);
int x,y,c;
- IplImage *disp = cvCreateImage(cvSize(im.w,im.h), IPL_DEPTH_8U, im.c);
- int step = disp->widthStep;
+ image copy = copy_image(im);
+ constrain_image(copy);
+ if(im.c == 3) rgbgr_image(copy);
+ Mat m(im.h, im.w, CV_MAKETYPE(CV_8U, im.c));
for(y = 0; y < im.h; ++y){
for(x = 0; x < im.w; ++x){
for(c= 0; c < im.c; ++c){
- float val = im.data[c*im.h*im.w + y*im.w + x];
- disp->imageData[y*step + x*im.c + c] = (unsigned char)(val*255);
+ float val = copy.data[c*im.h*im.w + y*im.w + x];
+ m.data[y*im.w*im.c + x*im.c + c] = (unsigned char)(val*255);
}
}
}
- return disp;
+ free_image(copy);
+ return m;
}
-image ipl_to_image(IplImage* src)
+image mat_to_image(Mat m)
{
- int h = src->height;
- int w = src->width;
- int c = src->nChannels;
+ int h = m.rows;
+ int w = m.cols;
+ int c = m.channels();
image im = make_image(w, h, c);
- unsigned char *data = (unsigned char *)src->imageData;
- int step = src->widthStep;
+ unsigned char *data = (unsigned char*)m.data;
+ int step = m.step;
int i, j, k;
for(i = 0; i < h; ++i){
@@ -42,26 +46,6 @@ image ipl_to_image(IplImage* src)
}
}
}
- return im;
-}
-
-Mat image_to_mat(image im)
-{
- image copy = copy_image(im);
- constrain_image(copy);
- if(im.c == 3) rgbgr_image(copy);
-
- IplImage *ipl = image_to_ipl(copy);
- Mat m = cvarrToMat(ipl, true);
- cvReleaseImage(&ipl);
- free_image(copy);
- return m;
-}
-
-image mat_to_image(Mat m)
-{
- IplImage ipl = m;
- image im = ipl_to_image(&ipl);
rgbgr_image(im);
return im;
}
@@ -72,9 +56,9 @@ void *open_video_stream(const char *f, int c, int w, int h, int fps)
if(f) cap = new VideoCapture(f);
else cap = new VideoCapture(c);
if(!cap->isOpened()) return 0;
- if(w) cap->set(CV_CAP_PROP_FRAME_WIDTH, w);
- if(h) cap->set(CV_CAP_PROP_FRAME_HEIGHT, w);
- if(fps) cap->set(CV_CAP_PROP_FPS, w);
+ if(w) cap->set(CAP_PROP_FRAME_WIDTH, w);
+ if(h) cap->set(CAP_PROP_FRAME_HEIGHT, w);
+ if(fps) cap->set(CAP_PROP_FPS, w);
return (void *) cap;
}
@@ -123,7 +107,7 @@ void make_window(char *name, int w, int h, int fullscreen)
{
namedWindow(name, WINDOW_NORMAL);
if (fullscreen) {
- setWindowProperty(name, CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
+ setWindowProperty(name, WND_PROP_FULLSCREEN, WINDOW_FULLSCREEN);
} else {
resizeWindow(name, w, h);
if(strcmp(name, "Demo") == 0) moveWindow(name, 0, 0);
运行
git apply patch.diff
make
编译通过。
下载权重 v3或者v3-tiny
wget https://pjreddie.com/media/files/yolov3.weights
wget https://pjreddie.com/media/files/yolov3-tiny.weights
运行yolov3.
./darknet detect cfg/yolov3.cfg cfg/yolov3.weights data/dog.jpg
两g显存的我运行yolov3会提示cuda out of memory.
可以换用别的显卡.
或者运行tiny:
./darknet detect cfg/yolov3-tiny.cfg yolov3-tiny.weights data/dog.jpg
一张dog.jpg耗时,CPU的yolov3是17s,CPU的yolov3-tiny是0.6s,GPU+OPENCV的yolov3-tiny是0.148s.