Yolo v4系列学习(四)Yolo v4移植ROS

目录

  • 1、建立名为catkin_ws的工作空间
  • 2、下载darknet_ros包
  • 3、下载Yolo v4源码
  • 4、开始编译
  • 5、漫长的解决Bug的过程
  • 6、配置Yolo v4+ROS
  • 7、开始使用Yolo v4+ROS
  • 8、调参
  • 参考网址

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 v4移植ROS_第1张图片
原因分析: 这是由于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
Yolo v4系列学习(四)Yolo v4移植ROS_第2张图片
原因分析: 原因和问题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文件中添加头文件即可:

#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/路径下。
解决方案:修改如下:

#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这个函数的定义所在头文件没有添加。
解决方案:添加头文件:

#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’
Yolo v4系列学习(四)Yolo v4移植ROS_第3张图片
原因分析:这里是没有在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

(4)进入darknet_ros/config路径下,打开ros.yaml,将camera_reading下的topic修改为自己本地摄像头的图像发布话题,我这里是/usb_cam/image_raw,如下:

subscribers:

  camera_reading:
    topic: /usb_cam/image_raw
    queue_size: 1

(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
Yolo v4系列学习(四)Yolo v4移植ROS_第4张图片
解决方案:打开yolov4.cfg文件,将batch=64分别修改为batch=1即可。
解决上述问题后,不出意外,就可以看到Yolo v4在ROS下的检测结果了!以下是我在本机上记录的实验结果:
Yolo v4系列学习(四)Yolo v4移植ROS_第5张图片

8、调参

Yolo v4移植到ROS中后帧率比较低,只有20fps左右,这个帧率和yolov4.cfg中的width和height设置有关系,原始的是608,修改为416就达到40多fps,也可以改为320,能够达到60多fps,精度影响不大。
此外可以通过nvidia-smi查看GPU占用情况。

参考网址

Yolo v4源码
darknet_ros源码

你可能感兴趣的:(计算机视觉,ROS学习)