在前面一篇博客(Yolo v4移植ROS)中介绍了将Yolo v4移植到ROS中。由于Yolo v4的源码在Yolo v3源码的基础上有改动,移植成功后会出现一个小bug,如下图所示:
我们可以从图中看到: 打开rviz后,显示Yolo v4检测结果的话题/darknet_ros/detection_image,却显示的是一堆乱码。
原因分析:具体可以参看YoloObjectDetector.cpp的代码,打开YoloObjectDetector.cpp文件,搜索关键词viewImage_,定位到第4处,代码如下:
if (viewImage_) {
displayInThread(0);
} else {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
}
这里的viewImage_参数就对应于ros.yaml文件中的image_view:enable_opencv参数,即是否对检测结果进行显示。这时候我们进入检测结果显示线程displayInThread(0)中继续查看源码,可以发现显示图像用到了关键函数show_image_cv()。
但是yolov3_ros版本和yolov4_ros版本所用的show_image_cv()函数略有区别,前者(yolov3)所用的show_image_cv()函数定义如下:
void show_image_cv(image p, const char *name, IplImage *disp)
后者(yolov4)所用的show_image_cv()函数定义如下:
void show_image_cv(image p, const char *name);
可以看到二者的定义相差一个参数,而我们可以看到Yolo算法移植到ROS后最终转化为话题/darknet_ros/detection_image的就是这里用到的第3个参数(实参为ipl_,ipl_是发布/darknet_ros/detection_image话题的关键中间变量)。知道了原因,就有了如下解决方案了。
解决方案一:将ros.yaml文件中的enable_opencv: true参数改为false,这样就进入了else语句中,将检测结果buff_传给了ipl_。这算是最简单粗暴的方案。这样虽然检测结果不会实时显示(因为没有进入displayInThread(0)线程),但是在rviz中查看/darknet_ros/detection_image话题时能够正常显示结果。
解决方案二:在不修改ros.yaml文件的前提下,将前面提到的if...else语句修改如下:
if (viewImage_) {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
displayInThread(0);
} else {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
}
即在if判断条件内添加一条generate_image语句,这样就能将检测结果buff_传给了ipl_,然后ipl_以/darknet_ros/detection_image话题的形式发布出去,就能在rviz中正常显示了。
再回过头来看,可以发现实际上在yolov3_ros版本中的show_image_cv函数中包含了generate_image的代码,在yolov4_ros版本中去掉了generate_image相关的代码,所以才会出现标题所描述的问题。
问题解决~~~~