关于yolo在ros上的移植(一)

接到师兄的任务,把yolov2移植到ros上。

环境为ubuntu16.04+ros+cuda9.0+NVDIA GTX1050

刚开始想的解决方法是,先把yolov2的检测图片的代码一点点的黏贴到ros的程序包中然后进行编译,可是黏贴一点,编译一点,当编译到

struct network;

typed struct network network;

struct layer;

typed struct layer layer;

typed struct layer{

……(struct network);

}

typed struct network{

 ……(struct layer);

}

这里编译的时候报错,因为ros是基于c++的编译方式,而yolov2则是用c写的,虽然c++和c大部分是兼容的,但是ros用的是c++ 11的版本,貌似从c++ 9之后,c与c++的编译差异就越来越大了,所以,在这里出现了c的前置声明问题,所以不太懂怎么弄,也找不到人问。

于是没办法,只能在github上找有没有关于yolo 移植到 ros上的已经写好的代码。

结果一找还真有,但是编译起来,真的,好多坑啊!!!!!!!!!!!!!!!!!!!!!!!

好在有男票大神带着,才能一天之中搞出来,不然我自己可能一个星期都搞不定吧。

首先,遇到的第一个坑。

main函数是yolo_object_detector_node.cpp,里面定义并初始化了两个线程。两个线程在YoloObjectDetector.cpp里面。

然后先catkin_make一下,然后 rosrun darknet_ros darknet_ros,编译通过了,也可以运行,但是一直打印“waiting for image”然后我就去程序里找,哪里打印的。找到是在

void YoloObjectDetector::yolo()
{
  const auto wait_duration = std::chrono::milliseconds(2000);
  while (!getImageStatus()) {
    printf("Waiting for image.\n");
    if (!isNodeRunning()) {
      return;
    }
    std::this_thread::sleep_for(wait_duration);
  }

在这个函数里,如果没有得到getimagestatus,我就又往上翻找,看是不是遗漏了什么,但是往上面翻找发现,里面有很多主题。里面写着cam/image_view/,我就猜想这里的图像应该是订阅其他主题的图像来的,于是就下载了一个ros的usb包,然后编译成功。把程序里面的cam/image_view/主题改成usb_cam发布的usb_cam/image_view/这个主题(本来是把usb_cam发布的usb_cam/image_view/修改成cam/image_view/,但是这么一改,usb_cam的launch文件就无法运行了,可能是因为发布的主题和节点的名称不一致的问题,所以还是修改yolo的订阅主题)。

这次usb_cam也能发布图像,yolo也能接收到程序,但是yolo接收到图像之后竟然没有一点反应!!!!!!!!!!

当时真是把我气了个半死,我就猜想是不是我的很多参数没有传进去,因为运行darknet的时候,是要传很多参数进去的(例如:./darknet detector cfg/yolo.cfg  yolo.weights  data/dog.jpg)但是我运行这个darknet_ros的时候却只运行了 rosrun darknet_ros darknet_ros 并没有传其他的参数进去,我就继续在程序里看。

原来在void YoloObjectDetector::init()里面,已经把参数传好了,穿的thresh=0.3,yolo.weights, yolo.cfg, 后来我又看它是否把路径设置的正确,自己配置了自己的路径,尽量把路径写完全(/home/miranda/catkin_ws_darknet/src/darknet_ros/darknet_ros/yolo_network_config/cfg)我的路径就是这样写的。

把路径配置正确以后,还是没有反应,就又在想是不是检测到了却没有把框框画出来。因为前几天看darknet的源码的时候看到过draw_detection这个函数,是画框框的,我就在darknet_ros这个里面找draw_detection,结果在void *YoloObjectDetector::detectInThread()里面,就在进draw_detection里面去看,这个函数我是之前看darknet源码的时候用的sourceinsight看的,知道在image.c里面,sourceinsight真是神器啊,看代码的神器!!!!为sourceinsight疯狂打call!!!!!!!!!!!我都不知道这么好用,还是男票大神告诉我的,哭唧唧,怎么不早点告诉我。 

看darknet_ros里面的image.c,再对照darknet源码里的image.c,会发现有很多不同,首先 我发现它俩传进来的参数不同,源码里有mask这个参数,但是darknet_ros里面没有mask这个参数,我以为这是个很重大的发现,但是后来发现,原来是mask是可有可无的。 再继续对照代码,发现他的prob的计算方法不太一样,然后我就在这里打印

for(i = 0; i < num; ++i){
int class = max_index(probs[i], classes);
float prob = probs[i][class];

printf("aaaaaaaaaaaa");

在这里打印一些字符,看是否程序跑到这里了,结果发现,程序跑到int class = max_index(probs[i], classes);就崩溃了。我就觉得很奇怪,打印prob发现,这个概率一直是0,然后就觉得很奇怪。又很奇怪这个class是什么,打印出来一看,尼玛,这个class竟然是-1,怪不得程序要崩溃,男票大神告诉我让我对照darknet源码修改。我就按照源码修改,但是这里面的classes发现原来也有问题,他传参传进来的classes为0,而源码里面传进来的参数为l.classes,所以我在程序里加了democlass=l.classes。

因为这个cfg/coco.data是在darknet.c文件里面就指定的,所以我就把这个放在了yoloobectdetector.c里面添加了

list *options = read_data_cfg("/home/miranda/catkin_ws_darknet/src/darknet_ros/darknet/cfg/coco.data");
    char *name_list = option_find_str(options, "names", "data/names.list");// name_list = "data/coco.names"
    char coco_names_path[128]="/home/miranda/catkin_ws_darknet/src/darknet_ros/darknet/";
    strcat(coco_names_path,name_list);

   label_names = get_labels(coco_names_path);

目前只能想起来这么多了,后面想起来再继续更新,现在已经能够用ros跑起来yolo了,哈哈哈。


猜你喜欢

转载自blog.csdn.net/weixin_40003920/article/details/79547000