yolov3 测试自己的数据

train完数据之后下面把测试的过程记录下吧,train结束后会在backup文件夹中有对应最终的yolov3_final.weights(如果你没改源码的情况下)。

darknet提供了用于评估模型的三个命令,即

./darknet detector  test cfg/coco.data cfg/yolov3.cfg backup/yolov3_final.weights data/dogs.jpg

/*不现实评价指标,输入图片路径,只显示框好后的图片和类别、置信率*/

./darknet detector  valid cfg/coco.data cfg/yolov3.cfg backup/yolov3_final.weights 

在./results/comp4_det_test_[类名].txt里保存测试结果*/
./darknet detector  recall cfg/coco.data cfg/yolov3.cfg backup/yolov3_final.weights 

/*依次ID:图片序号从0开始,correct:累计检测正确的总框数,total:累计的总ground truth数,RPs/Img: 累计的总proposals/已检测图片数,IOU,Recall: correct / total,proposals:累计的总框数,Precision: correct / proposals*/

其中recall需要修改源码。下面会说。
 

上图中第一个test最常用啦。这默认是单张图片的detect结果  在这里说一个刚train结束后的bug,就是coco数据的background类,yolov3默认是81分类啦,我在刚开始project.names只按照annotations中的class name写了,漏掉了背景类,于是出现了标签错乱的问题,detect的结果都是跟正确的label错1位,于是修改了project.name,把第一行默认为background,做成了81行的class name的签,就能对应上结果了。

一  批量执行测试并生成对应的检测结果图片

测试单张图片,需要编译时有OpenCV支持:./darknet detector test
文件中batch和subdivisions两项必须为1。
测试时还可以用-thresh和-hier选项指定对应参数。

测试多张图片,就需要更改darknet源码啦。
找到exmaple/detetoc.c

1.用下面代码替换detector.c文件(example文件夹下)的void test_detector函数(注意有3处要改成自己的路径)

void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, char *outfile, int fullscreen)
{
    list *options = read_data_cfg(datacfg);
    char *name_list = option_find_str(options, "names", "data/names.list");
    char **names = get_labels(name_list);
 
    image **alphabet = load_alphabet();
    network *net = load_network(cfgfile, weightfile, 0);
    set_batch_network(net, 1);
    srand(2222222);
    double time;
    char buff[256];
    char *input = buff;
    float nms=.45;
    int i=0;
    while(1){
        if(filename){
            strncpy(input, filename, 256);
            image im = load_image_color(input,0,0);
            image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
            layer l = net->layers[net->n-1];
 
 
            float *X = sized.data;
            time=what_time_is_it_now();
            network_predict(net, X);
            printf("%s: Predicted in %f seconds.\n", input, what_time_is_it_now()-time);
            int nboxes = 0;
            detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
            //printf("%d\n", nboxes);
            //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
            if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
                draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
                free_detections(dets, nboxes);
            if(outfile)
             {
                save_image(im, outfile);
             }
            else{
                save_image(im, "predictions");
#ifdef OPENCV
                cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
                if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
                }
                show_image(im, "predictions");
                cvWaitKey(0);
                cvDestroyAllWindows();
#endif
            }
            free_image(im);
            free_image(sized);
            if (filename) break;
         } 
        else {
            printf("Enter Image Path: ");
            fflush(stdout);
            input = fgets(input, 256, stdin);
            if(!input) return;
            strtok(input, "\n");
   
            list *plist = get_paths(input);
            char **paths = (char **)list_to_array(plist);
             printf("Start Testing!\n");
            int m = plist->size;
            if(access("/media/pengjk/30213d25-fae8-4100-9d8b-9aed2bb5a8df/darknet/data/out",0)==-1)//"/home/FENGsl/darknet/data"修改成自己的路径
            {
              if (mkdir("/media/pengjk/30213d25-fae8-4100-9d8b-9aed2bb5a8df/darknet/data/out",0777))//"/home/FENGsl/darknet/data"修改成自己的路径
               {
                 printf("creat file bag failed!!!");
               }
            }
            for(i = 0; i < m; ++i){
             char *path = paths[i];
             image im = load_image_color(path,0,0);
             image sized = letterbox_image(im, net->w, net->h);
        //image sized = resize_image(im, net->w, net->h);
        //image sized2 = resize_max(im, net->w);
        //image sized = crop_image(sized2, -((net->w - sized2.w)/2), -((net->h - sized2.h)/2), net->w, net->h);
        //resize_network(net, sized.w, sized.h);
        layer l = net->layers[net->n-1];
 
 
        float *X = sized.data;
        time=what_time_is_it_now();
        network_predict(net, X);
        printf("Try Very Hard:");
        printf("%s: Predicted in %f seconds.\n", path, what_time_is_it_now()-time);
        int nboxes = 0;
        detection *dets = get_network_boxes(net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes);
        //printf("%d\n", nboxes);
        //if (nms) do_nms_obj(boxes, probs, l.w*l.h*l.n, l.classes, nms);
        if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
        draw_detections(im, dets, nboxes, thresh, names, alphabet, l.classes);
        free_detections(dets, nboxes);
        if(outfile){
            save_image(im, outfile);
        }
        else{
             
             char b[2048];
            sprintf(b,"/media/pengjk/30213d25-fae8-4100-9d8b-9aed2bb5a8df/darknet/data/out/%s",GetFilename(path));//"/home/FENGsl/darknet/data"修改成自己的路径
            
            save_image(im, b);
            printf("save %s successfully!\n",GetFilename(path));
#ifdef OPENCV
            cvNamedWindow("predictions", CV_WINDOW_NORMAL); 
            if(fullscreen){
                cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);
            }
            show_image(im, "predictions");
            cvWaitKey(0);
            cvDestroyAllWindows();
#endif
        }
 
        free_image(im);
        free_image(sized);
        if (filename) break;
        }
      }
    }
}

2,在前面添加*GetFilename(char *p)函数(注意后面的注释)

#include "darknet.h"
#include 
#include
#include
#include
static int coco_ids[] = {1,2,3,4,5,6,7,8,9,10,11,13,14,15,16,17,18,19,20,21,22,23,24,25,27,28,31,32,33,34,35,36,37,38,39,40,41,42,43,44,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,67,70,72,73,74,75,76,77,78,79,80,81,82,84,85,86,87,88,89,90};
 
char *GetFilename(char *p)
{ 
    static char name[20]={""};
    char *q = strrchr(p,'/') + 1;
    strncpy(name,q,6);//注意后面的6,如果你的测试集的图片的名字字符(不包括后缀)是其他长度,请改为你需要的长度(官方的默认的长度是6)
    return name;
}

3.重新make  记得先make clean。

在这里有个bug啊我遇到的,make失败总说找不到opencv中的window_normal_windows 但是明明已经先编译了opencv! github上有人也遇到了but没有相关的解释啊贼难受, 最后就死马当活马医直接不用opencv,把makefile文件中的opencv重新改为0,编译通过。

4. 执行下面的命令。

./darknet detector test cfg/coco.data cfg/yolov3.cfg backup/yolov3_final.weights 

然后会要你输入image的路径了,然后就复制过来即可,在coco.data文件(你自己定义的文件中的valid)的路径,复制过来即可。

5.坐等data/out文件夹下的结果吧 贴上我的result

 

yolov3 测试自己的数据_第1张图片

二 计算mAP

先通过valid命令生成对应的结果啦,


./darknet detector  valid cfg/coco.data cfg/yolov3.cfg backup/yolov3_final.weights 

在./results/comp4_det_test_[类名].txt里保存测试结果*/

以上代码是使用的yolo网络自带的valid函数接口来测试大量的图片,把检测结果保存在txt文件里, -out 后面的“”会自动生成 “类名.txt” 在darknet / result 目录下。

因为最终我只需要测试无人机这一类,就以这一类为例了。

result下查看结果,打开对应的txt,其中的每一行代表

图片名字,这一类的框框的置信度,坐标信息,这是voc格式的。

使用py-faster-rcnn下的voc_eval.py计算mAP

将py-faster-rcnn/lib/datasets/voc_eval.py拷贝到darknet根目录。

voc_eval.py下载:https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/datasets/voc_eval.py

新建自己的comput_mAP.py文件,如下,针对my无人机类测试

yolov3 测试自己的数据_第2张图片

其中第一个参数为自己的results的位置,第二个参数为test图片的annotation的xml所在位置,第三个参数是保存所有test路径的txt文件(注意,这里的txt文件必须不带最后的.jpg后缀,不是.data文件中的那个valid了!重新生成一个把后缀split掉。)第四个参数即你要检测的类别,这里喔也有问题,生成的result带有com4_test的前缀,但这里必须要跟coco.name中的照应上,如果你直接输入带有com4_test的会gg,所以稳妥点把生成的txt rename成对应的 class name。

然后执行py文件,就能生成对应的mAP了。

大规模coco+自己的数据训练了5万次的结果 0.78mAP。后面在优化下应该能达到80+。

重复执行,检测其他类别需要删除 ./darknet/annots.pkl ,或者改变compute_mAP.py中pkl文件保存的路径

三 计算recall

需要修改detector.c源码:

替换list *plist = get_paths("data/coco_val_5k.list");为list *plist=get_paths("voc/train.txt");自己的测试集文本

结果:最后一列为recall值。  

我把recall的结果重定向到txt文件中了,结果如下:

yolov3 测试自己的数据_第3张图片

这对应的是单张图片的recall,如果想算测试集上总的recall,自己写个脚本累加一下就行了。

 

附:同时输出所有类的mAP代码,我没有用,仅供参考:

from voc_eval import voc_eval
 
import os
 
current_path = os.getcwd()
results_path = current_path+"/results"
sub_files = os.listdir(results_path)
 
mAP = []
for i in range(len(sub_files)):
    class_name = sub_files[i].split(".txt")[0]    rec, prec, ap = voc_eval('/home/peidashun/projects/darknet/results/{}.txt', '/home/peidashun/projects/darknet/voc/VOCdevkit/VOC2018/Annotations/{}.xml', '/home/peidashun/projects/darknet/voc/2018_test.txt', class_name, '/home/peidashun/projects/darknet/voc/VOCdevkit/VOC2018/mAP')
    print("{} :\t {} ".format(class_name, ap))
    mAP.append(ap)
 
mAP = tuple(mAP)
 
print("***************************")
print("mAP :\t {}".format( float( sum(mAP)/len(mAP)) ))

 

你可能感兴趣的:(目标检测)