本文转载自: 原文连接(木顶思上)
1、建立名为catkin_ws的工作空间
$ mkdir -p catkin_ws/src
$ cd catkin_ws/src/
$ catkin_init_workspace
$ cd ..
$ catkin_make
2、下载darknet_ros包
$ cd src/
$ git clone https://github.com/leggedrobotics/darknet_ros
3、下载Yolo v4源码
下载好了之后,可以看到darknet_ros中有3个文件夹:darknet、darknet_ros和darknet_ros_msgs,现在将darknetAB的代码放到第一个文件夹darknet中:
$ rm -r darknet/
$ git clone https://github.com/AlexeyAB/darknet
4、开始编译
$ cd ../..
$ catkin_make
执行上述操作后,会开始下载权重(yolov2-tiny.weights、yolov3.weights和yolov2.weights)
也可以打开darknet_ros文件夹下的CMakeLists.txt文件,搜索找到execute_process,这是weights权重文件下载的指令,可以屏蔽掉(句首添加#号即可),提前将下载好的权重放到对应的位置(即darknet_ros/yolo_network_config/weights/路径下)
5、漫长的解决Bug的过程
在上一步进行编译时,会遇到很多问题,现逐一进行解决。(以下问题是每次解决一个就重新执行catkin_make进行编译)
问题1:Cannot find source file:src/cuda.c
原因分析: 这是由于Yolo v4的代码中将Yolo v1-v3的代码cuda.c文件改为了dark_cuda.c文件,因此需要将CMakeLists.txt文件对应位置进行修改。
解决方案:打开darknet_ros文件夹下的CMakeLists.txt文件,将{DARKNET_PATH}/src/cuda.c改为{DARKNET_PATH}/src/dark_cuda.c
问题2:Cannot find source file:src/logistic_layer.c
原因分析: 原因和问题1类似,Yolo v4的代码去掉了logistic_layer.c文件。
解决方案:打开CMakeLists.txt文件,屏蔽{DARKNET_PATH}/src/logistic_layer.c,在$前面加个#号;
还有一个类似的问题:Cannot find source file:src/l2norm_layer.c,也是屏蔽掉:{DARKNET_PATH}/src/l2norm_layer.c;
问题3:Cannot find source file:examples/art.c
原因分析: Yolo v4的代码中将Yolo v1-v3的源代码中examples文件夹下的代码均放到src文件夹下了。
解决方案:打开CMakeLists.txt文件,将{DARKNET_PATH}/examples/art.c修改为${DARKNET_PATH}/src/art.c;
有17个文件都这样修改,从examples改到src;
问题4:Cannot find source file:src/lsd.c
原因分析: 原因和问题2是一样的。
解决方案:打开CMakeLists.txt文件,屏蔽{DARKNET_PATH}/src/lsd.c,在$前面加个#号;
还有attention.c、regressor.c和segmenter.c,都采用屏蔽的方式;
问题5:image_interface.h:16:30: error: unknown type name ‘IplImage’
原因分析:IplImage的定义找不到对应的头文件,IplImage是在"opencv2/core/types_c.h"中进行定义的。
解决方案:在image_interface.h文件中添加头文件即可:
1 | #include "opencv2/core/types_c.h"
问题6:image.c:16:23: fatal error: stb_image.h: No such file or directory
原因分析:找不到头文件stb_image.h的位置,该头文件在/3rdparty/stb/include/路径下。
解决方案:修改如下:
1 | #include "../3rdparty/stb/include/stb_image.h"
出现fatal error: stb_image_write.h,解决方式一样,也是将头文件路径修改一下即可。
注意:如果没有出现这2个错误就可以跳过,不用修改。
问题7:YoloObjectDetector.hpp:62:72: error: conflicting declaration of C function ‘void show_image_cv(image, const char*, IplImage*)’
原因分析:show_image_cv这个函数定义冲突,由于ROS中没有使用到,可以去掉这一行。
解决方案:屏蔽这一行即可;
问题8: YoloObjectDetector.cpp:278:34: error: ‘fill_cpu’ was not declared in this scope
原因分析:fill_cpu这个函数的定义所在头文件没有添加。
解决方案:添加头文件:
1 | #include "../../darknet/src/blas.h"
还有error: ‘axpy_cpu’ was not declared in this scope也是这个问题,axpy_cpu函数的声明也在blas.h中;
问题9:YoloObjectDetector.cpp:290:104: error: too few arguments to function ‘detection* get_network_boxes(network*, int, int, float, float, int*, int, int*, int)’
原因分析:查看network.c文件中get_network_boxes()函数定义可知,末尾缺少一个参数。
解决方案:在对应调用到get_network_boxes()函数的末尾添加一个1,如下所示:
detection *dets = get_network_boxes(net, buff_[0].w, buff_[0].h, demoThresh_, demoHier_, 0, 1, nboxes,1);
问题10: YoloObjectDetector.cpp:301:39: error: could not convert ‘((darknet_ros::YoloObjectDetector*)this)->darknet_ros::YoloObjectDetector::net_’ from ‘network*’ to ‘network’
原因分析:查看network.c文件中network_predict()函数定义可知,输入参数类型与定义不一致。
解决方案:将net_前面添加一个*号即可:
float* prediction = network_predict(*net_, X);
问题11:YoloObjectDetector.cpp:318:94: error: invalid conversion from ‘detection*’ to ‘int’ [-fpermissive]
原因分析:Yolo v4版中的画框函数draw_detections在Yolo v1-v3版本基础上有变化,这里采用与原始定义一致的draw_detections_v3即可。
解决方案:将这一行代码修改如下:
draw_detections_v3(display, dets, nboxes, demoThresh_, demoNames_, demoAlphabet_, demoClasses_, 1);
问题12:YoloObjectDetector.cpp:387:61: error: too many arguments to function ‘void show_image_cv(image, const char*)’
原因分析:这里查看image_opencv.cpp文件中show_image_cv的定义可知,show_image_cv的定义有所变化,少了一个参数定义。
解决方案:将这一行代码修改如下:
show_image_cv(buff_[(buffIndex_ + 1)%3], "YOLO V4");
注意:这里有个小细节,可以将窗口名称YOLO V3修改为YOLO V4,那YoloObjectDetector.cpp文件出现的7处都需要修改过来。
问题13:undefined reference to `draw_detections_cv_v3’
原因分析:这里是没有在CMakeLists.txt添加对应的文件。例如draw_detections_cv_v3()函数是在image_opencv.cpp文件中定义的,就需要在CMakeLists.txt中添加如下语句: ${DARKNET_PATH}/src/image_opencv.cpp
解决方案:将所有出现undefined reference to问题的部分都将对应定义的的cpp文件添加到CMakeLists.txt中即可。
问题14:在YoloObjectDetector.cpp中使用到的ipl_into_image()函数和ipl_to_image()函数并没有在Yolo v4代码中进行定义,因此需要在Yolo v4源代码中的src/image.c文件的末尾添加这两个函数的定义,即:
(1)ipl_into_image()函数的定义:
void ipl_into_image(IplImage* src, image im)
{
unsigned char *data = (unsigned char *)src->imageData;
int h = src->height;
int w = src->width;
int c = src->nChannels;
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.;
}
}
}
}
(2)ipl_to_image()函数的定义:
image ipl_to_image(IplImage* src)
{
int h = src->height;
int w = src->width;
int c = src->nChannels;
image out = make_image(w, h, c);
ipl_into_image(src, out);
return out;
}
同时记得在src/image.c中添加头文件#include “opencv2/core/types_c.h”,否则会报与问题5一样的错误。
解决了上述十几个问题后,编译应该能够通过。当然如果还有其他问题,继续解决即可。我在实验的时候遇到的问题都记录在这里了。
6、配置Yolo v4+ROS
(1)在darknetAB官网上有下载yolov4权重,下载地址如下:yolov4权重,然后将下载好的权重yolo_network_config/weights文件夹下,yolov4.weights权重大小是257.7MB;
(2)进入darknet_ros/darknet/cfg/文件夹下,将配置文件yolov4.cfg复制yolo_network_config/cfg文件夹下;
(3)进入darknet_ros/config路径下,复制yolov2.yaml文件修改为yolov4.yaml,打开yolov4.yaml,修改如下:
yolo_model:
config_file:
name: yolov4.cfg
weight_file:
name: yolov4.weights
(5)进入darknet_ros/launch路径下,复制yolo_v3.launch,名字修改为yolo_v4.launch,打开yolo_v4.launch,修改如下:
<arg name="network_param_file" default="$(find darknet_ros)/config/yolov4.yaml"/>
即,将调用yolov3.yaml修改为调用yolov4.yaml即可
7、开始使用Yolo v4+ROS
(1)打开一个终端,开启主节点:
$ roscore
(2)打开第2个终端,运行摄像头节点:
$ rosrun usb_cam usb_cam_node
如果没有安装usb_cam摄像头的ROS包,那么输入如下指令进行安装即可:
$ sudo apt-get install ros-kinetic-usb-cam
(3)打开第3个终端,运行yolov4_ros节点:
$ source devel/setup.bash
$ roslaunch darknet_ros yolo_v4.launch
注意:在运行第3条指令可能会出现如下错误:
CUDA Error: out of memory
CUDA Error: out of memory: File exists
解决方案:打开yolov4.cfg文件,将batch=64分别修改为batch=1即可。
解决上述问题后,不出意外,就可以看到Yolo v4在ROS下的检测结果了!以下是我在本机上记录的实验结果:
8、调参
Yolo v4移植到ROS中后帧率比较低,只有20fps左右,这个帧率和yolov4.cfg中的width和height设置有关系,原始的是608,修改为416就达到40多fps,也可以改为320,能够达到60多fps,精度影响不大。
此外可以通过nvidia-smi查看GPU占用情况。
参考网址
Yolo v4源码:https://github.com/AlexeyAB/darknet
darknet_ros源码:https://github.com/leggedrobotics/darknet_ros