一、ROS yoloV4
1、建立工作空间
mkdir -p catkin_ws/src
cd catkin_ws/src/
catkin_init_workspace
cd ..
catkin_make
2、下载所需的包
(1)下载darknet_ros包
链接:https://github.com/leggedrobotics/darknet_ros
git clone https://github.com/leggedrobotics/darknet_ros
下载后有3个文件夹:darknet、darknet_ros、darknet_ros_msgs
(2)yolov4 源码下载
链接:https://github.com/AlexeyAB/darknet
将yolov4源码放在darknet文件夹下
rm -r darknet/
git clone https://github.com/AlexeyAB/darknet
3、编译
cd catkin_ws
catkin_make
此时自动下载权重yolov2-tiny.weights、yolov3.weights和yolov2.weights,再自行下载yolov4.weights,将权重文件放在(darknet_ros/yolo_network_config/weights/)路径下
4、编译过程中的问题解决
(1) 问题1:Cannot find source file:src/cuda.c
解决:修改darknet_ros文件夹下CMakeLists.txt文件,将{DARKNET_PATH}/src/cuda.c改为{DARKNET_PATH}/src/dark_cuda.c
原因:yolov1-3是cuda.c,yolov4应为dark_cuda.c
(2)问题2:Cannot find source file:src/logistic_layer.c
解决:打开刚才的CMakeLists.txt文件,屏蔽{DARKNET_PATH}/src/logistic_layer.c
原因:yolov4代码去掉了logistic_layer.c
(3)问题3:Cannot find source file:src/l2norm_layer.c
解决:打开刚才的CMakeLists.txt文件,屏蔽{DARKNET_PATH}/src/l2norm_layer.c
原因:同上问题3
(4)问题4:Cannot find source file:examples/art.c
解决:将CMakeLists.txt文件中{DARKNET_PATH}/examples/art.c修改为${DARKNET_PATH}/src/art.c,即将所有的examples改为src
原因: Yolo v4的代码中将Yolo v1-v3的源代码中examples文件夹下的代码均放到src文件夹下了
(5)问题5:Cannot find source file:src/lsd.c
解决:打开CMakeLists.txt文件,屏蔽{DARKNET_PATH}/src/lsd.c
原因:同问题2
(6)同上述相同的问题:Cannot find source file:src/attention.c、src/regressor.c和src/segmenter.c
解决:打开CMakeLists.txt文件,屏蔽上述文件
(7)问题7:image_interface.h:16:30: error: unknown type name ‘IplImage’
解决:在image_interface.h文件中添加头文件:
#include "opencv2/core/types_c.h"
原因:IplImage的定义找不到对应的头文件,IplImage在"opencv2/core/types_c.h"中进行定义
(8)问题8:image.c:16:23: fatal error: stb_image.h: No such file or directory
解决:修改image.c文件,修改头文件
#include "../3rdparty/stb/include/stb_image.h"
原因:找不到头文件stb_image.h,该头文件在/3rdparty/stb/include/路径下
(9)问题9:fatal error: stb_image_write.h: No such file or directory
解决:同上修改路径
原因:同问题8
(10)问题10:YoloObjectDetector.hpp: error: conflicting declaration of C function ‘void show_image_cv(image, const char*, IplImage*)’
解决:屏蔽这一行
(11)问题11:YoloObjectDetector.cpp:278:3: error: ‘fill_cpu’ was not declared in this scope
解决:添加头文件
#include "../../darknet/src/blas.h"
原因:fill_cpu函数的定义所在头文件没有添加
同样问题: ‘axpy_cpu’ was not declared in this scope,axpy_cpu函数的声明也在blas.h中;
(12)问题12:YoloObjectDetector.cpp:290:104: error: too few arguments to function ‘detection* get_network_boxes(network*, int, int, float, float, int*, int, int*, int)’
解决:在对应调用到get_network_boxes()函数的末尾添加一个1
detection *dets = get_network_boxes(net, buff_[0].w, buff_[0].h, demoThresh_, demoHier_, 0, 1, nboxes,1);
原因:查看network.c文件中get_network_boxes()函数定义可知,末尾缺少一个参数
(13)问题13:YoloObjectDetector.cpp:300:39: error: could not convert ‘((darknet_ros::YoloObjectDetector*)this)->darknet_ros::YoloObjectDetector::net_’ from ‘network*’ to ‘network’
解决:在net_前面加一个*号
float* prediction = network_predict(*net_, X);
原因:通过network.c文件中network_predict()函数定义可知,输入参数类型与定义不一致。
(14)问题14:YoloObjectDetector.cpp:316:94: error: invalid conversion from ‘detection*’ to ‘int’ [-fpermissive]
解决:修改代码:
draw_detections_v3(display, dets, nboxes, demoThresh_, demoNames_, demoAlphabet_, demoClasses_, 1)
原因:yolov4画框函数draw_detections在yolov1-v3有变化
(15)问题15:YoloObjectDetector.cpp:384:61: error: too many arguments to function ‘void show_image_cv(image, const char*)’
解决:修改代码:
show_image_cv(buff_[(buffIndex_ + 1)%3], "YOLO V4");
原因:show_image_cv少了一个参数定义。该函数在image_opencv.cpp文件中
(16)问题16:将YoloObjectDetector.cpp中的7个“YOLO V3”改为 “YOLO V4”
(17)问题17:yolo_v2_class.cpp:16:10: fatal error: stb_image.h: No such file or directory
解决:修改yolo_v2_class.cpp头文件
#include "../3rdparty/stb/include/stb_image.h"
(18)问题18:undefined reference to `draw_detections_cv_v3’,undefined reference to 'this_thread_sleep_for’等
解决:找到所有出现undefined reference to问题的部分,将对应的定义cpp文件添加到CMakeLists.txt中;
例如:draw_detections_cv_v3()函数是在image_opencv.cpp文件中定义的,就需要在CMakeLists.txt中添加如下语句:
${DARKNET_PATH}/src/image_opencv.cpp
其他文件:如下
(19)问题19:在YoloObjectDetector.cpp中使用到的ipl_into_image()函数和ipl_to_image()函数并没有在Yolo v4代码中进行定义,因此需要在Yolo v4源代码中的src/image.c文件的末尾添加这两个函数的定义,即:
a: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.;
}
}
}
}
b: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;
}
(20)问题20:image.c:16:30: error: unknown type name ‘IplImage’
解决:在src/image.c中添加头文件
#include "opencv2/core/types_c.h"
5、ros_yolov4相应的文件配置
(1)权重文件的下载:yolov4.weights,将文件放在yolo_network_config/weights文件夹下
(2)将darknet_ros/darknet/cfg/文件夹下的配置文件yolov4.cfg复制yolo_network_config/cfg文件夹下;
(3)在darknet_ros/config文件夹下,建立yolov4.yaml,将yolov2.yaml内容复制yolov4.yaml中,并修改内容为:
yolo_model:
config_file:
name: yolov4.cfg
weight_file:
name: yolov4.weights
(4)在darknet_ros/config文件夹下,将ros.yaml中camera_reading 下的topic改为摄像头的图像发布话题,D435i相机如下:
subscribers:
camera_reading:
topic: /camera/color/image_raw
queue_size: 1
(5)在darknet_ros/launch文件夹下,建立yolo_v4.launch,将yolo_v3.launch中内容复制到里面, 并修改内容:
<arg name="network_param_file" default="$(find darknet_ros)/config/yolov4.yaml"/>
二、利用D435i相机进行yolov4、ros
1、打开ROS主节点:
roscore
2、打开相机节点:
roslaunch realsense2_camera rs_camera.launch
3、运行yolov4_ros节点
roslaunch darknet_ros yolo_v4.launch
此时可能出现错误,根据电脑配置进行batch的更改
4、打开rviz进行显示
rviz
选择添加图片,话题修改为/darknet_ros/detection_image
此时出现显示问题,需进行一下修改
(1)打开YoloObjectDetector.cpp文件,搜索关键词viewImage_,定位到第4处,代码如下:
if (viewImage_) {
displayInThread(0);
} else {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
}
这里的viewImage_参数就对应于ros.yaml文件中的image_view:enable_opencv参数,即是否对检测结果进行显示。显示图像用到了show_image_cv()。
yolov3_ros函数:
void show_image_cv(image p, const char *name, IplImage *disp)
yolov4_ros所用的show_image_cv()函数定义:
void show_image_cv(image p, const char *name);
解决1:将ros.yaml文件中的enable_opencv: true参数改为false,在rviz中查看/darknet_ros/detection_image话题时能够正常显示结果,但是检测结果不会实时显示
解决2:修改YoloObjectDetector.cpp,如下:
if (viewImage_) {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
displayInThread(0);
} else {
generate_image(buff_[(buffIndex_ + 1)%3], ipl_);
}
5、利用摄像头实时显示
roscore
roslaunch realsense2_camera rs_rgbd.launch
roslaunch darknet_ros darknet_ros.launch
步骤同上1-4.若出现多检测框,检测错误
解决:进入darknet_ros/config,打开darknet_ros.launch,修改如下
arg name="network_param_file" default="$(find darknet_ros)/config/yolov2-tiny.yaml"/
改为
arg name="network_param_file" default="$(find darknet_ros)/config/yolov3.yaml"/
三、本地视频测试
1、在src下建立包
catkin_create_pkg local_vedio_detect std_msgs rospy roscpp
2、话题模型创建
(1)创建videopub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<stdio.h>
using namespace cv;
using namespace std;
int main(int argc, char** argv)
{
// ROS节点初始化
ros::init(argc, argv, "image_publisher");
ros::NodeHandle n;
ros::Time time = ros::Time::now();
ros::Rate loop_rate(5);
// 定义节点句柄
image_transport::ImageTransport it(n);
image_transport::Publisher pub = it.advertise("/camera/image_raw", 1);
sensor_msgs::ImagePtr msg;
// opencv准备读取视频
cv::VideoCapture video;
video.open("/home/data/11.mp4");
if( !video.isOpened() )
{
ROS_INFO("Read Video failed!\n");
return 0;
}
Mat frame;
int count = 0;
while(1)
{
video >> frame;
if( frame.empty() )
break;
count++;
msg = cv_bridge::CvImage(std_msgs::Header(), "bgr8", frame).toImageMsg();
pub.publish(msg);
ROS_INFO( "read the %dth frame successfully!", count );
loop_rate.sleep();
ros::spinOnce();
}
video.release();
return 0;
}
注意: /camera/image_raw与ros.yaml中camera_reading中的topic一致
// 定义节点句柄
image_transport::ImageTransport it(n);
image_transport::Publisher pub = it.advertise("/camera/image_raw", 1);
sensor_msgs::ImagePtr msg;
(2)创建videosub.cpp
#include<ros/ros.h>
#include<cv_bridge/cv_bridge.h>
#include<sensor_msgs/image_encodings.h>
#include<image_transport/image_transport.h>
#include<opencv2/opencv.hpp>
#include<opencv2/highgui/highgui.hpp>
#include<opencv2/imgproc/imgproc.hpp>
#include<stdio.h>
#include<math.h>
#include<vector>
void imageCalllback(const sensor_msgs::ImageConstPtr& msg)
{
ROS_INFO("Received \n");
try{
cv::imshow( "video", cv_bridge::toCvShare(msg, "bgr8")->image );
cv::waitKey(30);
}
catch( cv_bridge::Exception& e )
{
ROS_ERROR( "Could not convert from '%s' to 'bgr8'.", msg->encoding.c_str() );
}
}
int main(int argc, char** argv)
{
ros::init(argc, argv, "image_listener");
ros::NodeHandle n;
cv::namedWindow("video");
cv::startWindowThread();
image_transport::ImageTransport it(n);
image_transport::Subscriber sub = it.subscribe( "video_image", 1, imageCalllback );
ros::spin();
cv::destroyWindow("video");
return 0;
}
(3)CMakeList.txt修改
a: find_package(catkin …)修改为一下内容
find_package(catkin REQUIRED COMPONENTS
cv_bridge
image_transport
roscpp
rospy
sensor_msgs
std_msgs
)
find_package(OpenCV REQUIRED)
b: 将include_directories(…)修改为以下内容
include_directories(include ${catkin_INCLUDE_DIRS})
include_directories(include ${OpenCV_INCLUDE_DIRS})
add_executable(videopub src/videopub.cpp)
target_link_libraries(videopub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
#add_dependencies(mytest opencvexam_gencpp)
add_executable(videosub src/videosub.cpp)
target_link_libraries(videosub ${catkin_LIBRARIES} ${OpenCV_LIBRARIES})
3、编译
catkin_make
4、运行
roscore
roslaunch darknet_ros darknet_ros.launch
rosrun local_vedio_detect vediopub
注意:显示框中满屏横线,解决同上
解决:进入darknet_ros/config,打开darknet_ros.launch,修改如下
arg name="network_param_file" default="$(find darknet_ros)/config/yolov2-tiny.yaml"/
改为
arg name="network_param_file" default="$(find darknet_ros)/config/yolov3.yaml"/
参考链接:https://blog.csdn.net/JIEJINQUANIL/article/details/106461895