0. 主要工作:

  • 代码:https://github.com/wuxiaolang/darknet
  • darknet.c 中添加了 detect_tum_batch 命令处理 tum 和自制数据集,添加 detect_kitti_batch 命令处理 kitti 数据集
  • detector.c 中添加了读取数据集图像的函数 test_detector_tum_batch()test_detector_kitti_batch()
  • image.c 中添加了绘制与保存结果(txt 文件和绘制检测框的图像)的函数 draw_save_detections()

1. 指令

1.1 TUM 数据集

  • 指令:
1
./darknet detect_tum_batch [path_of_cfg] [path_of_weight] [path_of_dataset] [output_folder] [-thresh thresh]
  • 例如:
1
./darknet detect_tum_batch cfg/yolov3.cfg yolov3.weights /home/wu/data/dataset/rgbd_dataset_freiburg1_desk/ /home/wu/data/ -thresh 0.4
  • 注意:请在 [output_folder] 下创建 yolo_imgsyolo_txts 文件夹来存放绘制了检测框的图片和检测框 txt 信息。

1.2 KITTI 数据集

  • 指令:
1
./darknet detect_kitti_batch [path_of_cfg] [path_of_weight] [path_of_dataset] [output_folder] [-thresh thresh]

  例如:

1
./darknet detect_kitti_batch cfg/yolov3.cfg yolov3.weights /home/wu/data/dataset/kitti/color/07/ /home/wu/data/ -thresh 0.4
  • 注意
    • ① 请在 [output_folder] 下创建 yolo_imgsyolo_txts 文件夹来存放绘制了检测框的图片和检测框 txt 信息;
    • ② 在 test_detector_kitti_batch() 函数中默认采用的是 image_2 kitti 彩色数据集,如果使用 gray 数据集,可以将 image_2 改成 image_0image_1
  • 其他数据集:可仿照改动的函数写。

2. TUM 数据集

2.1 在 darknet.c 中添加指令参数

  • 具体代码:darknet.c
  • 在 main 函数中添加输入的第二个参数 detect_tum_batch
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    else if (0 == strcmp(argv[1], "detect_tum_batch"))
    {
         // 读取阈值,默认为 0.5.
         float thresh = find_float_arg(argc, argv, "-thresh", .5);
         // @PARAM    input_folder   输入数据集路径.
         char *input_folder = (argc > 4) ? argv[4]: 0;
         // @PARAM    output_folder  输出结果存放路径.
         char *output_folder = (argc > 5) ? argv[5]: 0;
         // 开始处理.
         test_detector_tum_batch(   "cfg/coco.data", 
                                    argv[2],            /* 网络模型 */
                                    argv[3],            /* 权重文件 */
                                    input_folder,       /* 输入数据集路径 */
                                    output_folder,      /* 输出的结果路径 */
                                    thresh, 
                                    .5);
    }
    

2.2 在 detector.c 中添加读取图片函数

  • 具体代码:detector.c
  • 在 detector.c 中添加上一步中用到的函数
    1
    2
    3
    4
    5
    6
    7
    8
    
    void test_detector_tum_batch(   char *datacfg,      /* cfg/coco.data */
                                    char *cfgfile,      /* 网络模型 */
                                    char *weightfile,   /* 权重文件 */
                                    char *input_folder, /* 输入数据集路径 */
                                    char *output_folder,/* 输出结果保存路径 */
                                    float thresh,       /* 置信度阈值 */
                                    float hier_thresh)
    {……}
    
  • 下面是处理的主要步骤。

2.2.1 读取数据集路径下的 rgb.txt 文件

  • 由于给出的路径是 ~/dataset/rgbd_dataset_freiburg1_desk/ ,数据集图片存放在 ~/dataset/rgbd_dataset_freiburg1_desk/rgb,图片名存放在 ~/dataset/rgbd_dataset_freiburg1_desk/rgb.txt 中,首先读取 rgb.txt 文件:
    1
    2
    3
    4
    5
    
    // NOTE 读取图像文件列表 rgb.txt. rgb_txt_path = ~/dataset/rgbd_dataset_freiburg1_desk/rgb.txt
    char buff[256];
    char *rgb_txt_path = buff;
    strncpy(rgb_txt_path, input_folder, 256); // input_folder 还是 ~/dataset/rgbd_dataset_freiburg3_long_office_household/
    FILE *fp_rgb_txt = fopen(strcat(rgb_txt_path,"rgb.txt"), "r");
    

2.2.2 读取图片文件名

  • rgb.txt 存储的内容形式如下,不考虑前三行,后面每行分别为时间戳和文件名:
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    
    # color images
    # file: 'rgbd_dataset_freiburg1_desk.bag'
    # timestamp filename
    1305031452.791720 rgb/1305031452.791720.png
    1305031452.823674 rgb/1305031452.823674.png
    1305031452.859642 rgb/1305031452.859642.png
    1305031452.891726 rgb/1305031452.891726.png
    1305031452.923715 rgb/1305031452.923715.png
    1305031452.959701 rgb/1305031452.959701.png
    1305031452.991647 rgb/1305031452.991647.png
    1305031453.023650 rgb/1305031453.023650.png
    1305031453.059754 rgb/1305031453.059754.png
    1305031453.091704 rgb/1305031453.091704.png
    
  • 读取 19-43 列的图片文件名 img_name,再添加路径得到 input_img_name
    • 另外需注意 txt 文件的前三行无效,需要跳过
     1
     2
     3
     4
     5
     6
     7
     8
     9
    10
    11
    12
    13
    14
    15
    16
    17
    
    int img_counter = -4;   // rgb.txt 文件前三行无效.
    while(!feof(fp_rgb_txt))
    {
        img_counter++;
    
        memset(szTest, 0, sizeof(szTest));
        fgets(szTest, sizeof(szTest) - 1, fp_rgb_txt); // 包含了换行符
    
        // 前三行无效不存储,但得遍历读取,所以这个判断在上两行后面.
        if( img_counter < 0)
            continue;
    
        strncpy(img_name, szTest+22, 17);               // 每行前面 18位为时间戳,后面是文件名.
        sprintf(input_img_name, "%srgb/%s.png", input_folder, img_name);
        printf("文件名: %s\n", input_img_name);
    }
    fclose(fp_rgb_txt);
    
  • 输出检测的图片结果,输出在 output_folder/yolo_imgs
1
2
3
4
5
6
// NOTE 输出图片.
strncpy(output_file, output_folder, 256);
char frame_index_c3[256];
//sprintf(frame_index_c3,"/yolo_imgs/%04d_yolo_%.2f",img_counter,thresh);  // 0001_yolo2_0.50.jpg
sprintf(frame_index_c3,"yolo_imgs/%s",img_name);  // 1905140001.223000.jpg
char * result_img = strcat(output_file,frame_index_c3);

3. KITTI 数据集

3.1 在 darknet.c 中添加指令参数

  • 与 TUM 数据集类似,修改指令名和调用的函数名即可:detect_kitti_batch,test_detector_kitti_batch()。

3.2 在 detector.c 中添加读取并检测图像的函数

  • 与 TUM 数据集类似,创建 test_detector_kitti_batch() 函数;
  • 读取图像按照 6 位数序号来读取:
    1
    2
    3
    4
    
    // STEP 1. 得到输入文件
    // 读取输入的图像文件:~/color/21/image_2/000001.png
    sprintf(input_img_name, "%simage_2/%06d.png", input_folder, num);   // color image_2,gray image_0
    printf("输入文件名: %s\n", input_img_name);
    
  • 输出结果的文件名有两种存储方式:
    • 第一种是按序号命名(默认情况),结果保存为:000001.jpg000001.txt
    • 第二种是按照时间戳命名,结果保存为:0.10387.jpg0.10387.txt
    • 可在 test_detector_kitti_batch() 函数中选择
       1
       2
       3
       4
       5
       6
       7
       8
       9
      10
      11
      12
      
      // 【方法 ①】: 以序号命名
      printf("文件序号: %06d\n", num);
      sprintf(output_file_name, "%06d", num);
      // // 【方法 ②】: 以时间戳命名
      // // 逐行读取 txt 文件的时间戳:1.036224e-01.
      // memset(szTest, 0, sizeof(szTest));
      // fgets(szTest, sizeof(szTest) - 1, fp_rgb_txt); // 包含了换行符
      // strncpy(output_file_name, szTest, 12);
      // // 将时间戳转换成十进制
      // double tmp_name = strtod(output_file_name, NULL);   // note strtod() 转换成 lf 十进制类型.
      // // 保留 5 位小数.
      // sprintf(output_file_name, "%.5lf", tmp_name);
      

4. 在 image.c 中添加保存结果函数

  • 具体代码:image.c
  • 此函数仿写的 draw_detections(),具体详见:
1
2
3
4
5
6
7
8
9
void draw_save_detections(  image im, 
                            detection *dets, 
                            int num, 
                            float thresh, 
                            char **names, 
                            image **alphabet, 
                            int classes,
                            FILE *save_txt)
{……}
  • 分别保存 类别、左上角坐标 + 宽 + 长、置信度,也可以修改为类别在 coco.name 中的编号,左上角和右下角坐标
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// NOTE 左上角坐标和右下脚坐标
int left  = (b.x-b.w/2.)*im.w;
int top   = (b.y-b.h/2.)*im.h;
int right = (b.x+b.w/2.)*im.w;
int bot   = (b.y+b.h/2.)*im.h;

if(left < 0) left = 0;
if(right > im.w-1) right = im.w-1;
if(top < 0) top = 0;
if(bot > im.h-1) bot = im.h-1;
            
// NOTE 分别写入类别和坐标
// fprintf(save_txt,"%s\t%d\t%d\t%d\t%d\t%.2f\n", names[class], left, top, right-left, bot-top, dets[i].prob[class]);
fprintf(save_txt,"%d %d %d %d %d\n", class, left, top, right-left, bot-top);
  • 输出 txt 结果,保存格式:类别 ID   左上角.x   左上角.y   长   宽   [置信度]
    1
    2
    3
    
    66   70    294   260   185    0.794691
    64   255   258   63     38    0.813716
    62   224   0     243   234    0.610995
    
  • 可指定只保存某种类型的结果
    1
    2
    3
    4
    5
    6
    
    // NOTE 只筛选出 "cup" 和 "bottle" 类别.
    // if ((strcmp(names[class], "cup") != 0)&&(strcmp(names[class], "bottle") != 0))
    //     {continue;}
    // 只选出 car.
    if (strcmp(names[class], "car") != 0)
    
        continue;
    


2019.03.11
wuyanminmax@gmail.com