YOLOv3 小功能

目录

1. 仅输出指定类别的检测结果

2. 裁剪出目标

3. 添加目标置信度

4. 批量测试图片并保存至指定文件夹

5. 保存视频检测结果

6. 修改模型保存频率

7. 保存训练日志,参数可视化


1. 仅输出指定类别的检测结果

coco模型,只输出人、车或其他指定类别的检测结果

这个比较简单,只需要在打印框、输出框信息的时候加个判断即可。

修改src/image.c中的draw_detection函数

            int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;
            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;

            bool is_person=false;
            bool is_car=false;
            is_person=!strcmp(labelstr,"person");//判断标签是否为person
            is_car=!strcmp(labelstr,"car");
            if(is_person||is_car){//只输出人和车的检测结果
                draw_box_width(im, left, top, right, bot, width, red, green, blue);
                if (alphabet) {
                    image label = get_label(alphabet, labelstr, (im.h*.03));
                    draw_label(im, top + width, left, label, rgb);
                    free_image(label);
                }
                if (dets[i].mask){
                    image mask = float_to_image(14, 14, 1, dets[i].mask);
                    image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
                    image tmask = threshold_image(resized_mask, .5);
                    embed_image(tmask, im, left, top);
                    free_image(mask);
                    free_image(resized_mask);
                    free_image(tmask);
                }
            }

https://blog.csdn.net/u012244950/article/details/25143019,C++裁剪图片

https://blog.csdn.net/weixin_40003920/article/details/79693221。裁剪yolo

https://blog.csdn.net/LOVE1055259415/article/details/81017075,裁剪yolo

2. 裁剪出目标

只打印指定类别的检测结果+裁剪出目标,修改src/image.c中的draw_detection函数。

void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
    int i,j;

    for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        for(j = 0; j < classes; ++j){
            if (dets[i].prob[j] > thresh){
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    class = j;
                } else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                }
                //printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            } 
			else if (dets[i].prob[j] > 0)
            {
            	printf("Error %s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            }
			
        }
        if(class >= 0){
            int width = im.h * .006;

            /*
               if(0){
               width = pow(prob, 1./2.)*10+1;
               alphabet = 0;
               }
             */

            //printf("%d %s: %.0f%%\n", i, names[class], prob*100);
            int offset = class*123457 % classes;
            float red = get_color(2,offset,classes);
            float green = get_color(1,offset,classes);
            float blue = get_color(0,offset,classes);
            float rgb[3];

            //width = prob*20+2;

            rgb[0] = red;
            rgb[1] = green;
            rgb[2] = blue;
            box b = dets[i].bbox;
            //printf("%f %f %f %f\n", b.x, b.y, b.w, b.h);

            int left  = (b.x-b.w/2.)*im.w;
            int right = (b.x+b.w/2.)*im.w;
            int top   = (b.y-b.h/2.)*im.h;
            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;

            bool Is_person = false;
            bool Is_car = false;
            
            Is_person = !strcmp(labelstr, "person");
            Is_car = !strcmp(labelstr, "car");
       
            if(Is_person || Is_car){

                IplImage* src;
                src=image_to_iplImage(im,src);
               // cvShowImage("src",src);
                int x = left*1.0;
                int y = top*1.0;
                int w = (right - left)*1.0;
                int h = (bot - top)*1.0;
                cvSetImageROI(src,cvRect(x,y,w,h)); //这里如果宽或者高越界会导致错误,闪退/ 	     
	        IplImage* crop = cvCreateImage(cvSize(w,h),IPL_DEPTH_8U,src->nChannels);
 	        cvCopy(src,crop,0);
	        cvResetImageROI(src);

                draw_box_width(im, left, top, right, bot, width, red, green, blue);

	        save_image(im,"test"); //这里的图像已经是有框的
	      
	        src = image_to_iplImage(im,src);
	        cvShowImage("src_bbox",src);
	        cvShowImage("crop",crop);
	        cvSaveImage("crop.jpg",crop,0);

                if (alphabet) {
                    image label = get_label(alphabet, labelstr, (im.h*.03));
                    draw_label(im, top + width, left, label, rgb);
                    free_image(label);
                }
                if (dets[i].mask){
                    image mask = float_to_image(14, 14, 1, dets[i].mask);
                    image resized_mask = resize_image(mask, b.w*im.w, b.h*im.h);
                    image tmask = threshold_image(resized_mask, .5);
                    embed_image(tmask, im, left, top);
                    free_image(mask);
                    free_image(resized_mask);
                    free_image(tmask);
                }
            }
        }
    }
}

3. 添加目标置信度

在src/image.c中修改函数draw_detections函数。

strcat函数:用来连接字符串,其原型为:char *strcat(char *dest, const char *src);dest 为目的字符串指针,src 为源字符串指针。将参数 src 字符串复制到参数 dest 所指的字符串尾部;dest 最后的结束字符 NULL 会被覆盖掉,并在连接后的字符串的尾部再增加一个 NULL。返回dest 字符串起始地址。

修改image.c文件

大概239行,draw_detector函数,源代码如下:

void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
    int i,j;

    for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        for(j = 0; j < classes; ++j){
            if (dets[i].prob[j] > thresh){
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    class = j;
                } else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                }
                //printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            } 
			else if (dets[i].prob[j] > 0)
            {
            	printf("Error %s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            }
			
        }
    ......
       
}

修改后,代码如下:

void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{
    int i,j;

    for(i = 0; i < num; ++i){
        char labelstr[4096] = {0};
        int class = -1;
        char lprob[10];//修改的部分
        for(j = 0; j < classes; ++j){
            sprintf(lprob, "%.2f",dets[i].prob[j]*100);//修改的部分
            if (dets[i].prob[j] > thresh){
                if (class < 0) {
                    strcat(labelstr, names[j]);
                    strcat(labelstr, ": ");//修改的部分
                    strcat(labelstr, lprob);//修改的部分
                    strcat(labelstr, "%");//修改的部分
                    class = j;
                } else {
                    strcat(labelstr, ", ");
                    strcat(labelstr, names[j]);
                    strcat(labelstr, ": ");//修改的部分
                    strcat(labelstr, lprob);//修改的部分
                    strcat(labelstr, "%");//修改的部分
                }
                printf("%s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            } 
			else if (dets[i].prob[j] > 0)
            {
            	printf("Error %s: %.0f%%\n", names[j], dets[i].prob[j]*100);
            }
       }
  ......
 }

这样make之后,测试图片便显示了置信度。

4. 批量测试图片并保存至指定文件夹

打开darknet文件下examples/detector.c文件,替换test_detector函数如下:

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 { //如果命令行无图片路径,则提示输入txt路径,txt文件包含图片的路径

            printf("Enter Image Path: ");

            fflush(stdout);

            input = fgets(input, 256, stdin);

            if(!input) return;

            strtok(input, "\n");

   

            list *plist = get_paths(input);//这里同train_detector时读取图片的操作一样

            char **paths = (char **)list_to_array(plist);

             printf("Start Testing!\n");

            int m = plist->size;
//access()函数,确定文件的访问权限 access(filename,mode)
//mode=0,判断文件是否存在;mode=1,检测文件是否可运行;mode=2,检测文件是否可写访问;mode=4,检查是//否可读访问;mode=6,检查是否可读/写访问 
//返回0表示存在,返回-1表示不存在

            if(access("/xxx/darknet/data/out",0)==-1)//"/xxx/darknet/data"修改成自己的路径,想把测试结果存哪就写哪

            {
//如果没有上述文件,则用mkdir创建,若创建失败,返回-1.
              if (mkdir("/xxx/darknet/data/out",0777))//"/xxx/darknet/data"修改成自己的路径

               {

                 printf("create file bag failed!!!");

               }

            }

            for(i = 0; i < m; ++i){//m张图片

             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,"/xxx/darknet/data/out/%s",GetFilename(path));//"/xxx/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;

        }

      }

    }

}

在前面添加函数:

#include "darknet.h"

#include <sys/stat.h>

#include<stdio.h>

#include<time.h>

#include<sys/types.h>

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);

    return name;

}

在darknet下重新编译,make.

终端输入测试指令:

./darknet detector test cfg/xx.data cfg/xx.cfg backup/xx.weights

加载完模型后出现Enter Image Path:

这个时候,输入test.txt的路径。test.txt即放测试图片路径的文档。之后测试结果就保存在test_detector函数中写的路径下的out文件夹内。

5. 保存视频检测结果

./darknet detector demo cfg/coco.data cfg/yolov3.cfg yolov3.weights <video file>,测试视频指令

https://blog.csdn.net/sinat_33718563/article/details/79964758,保存视频测试结果。

 

6. 修改模型保存频率

在examples文件夹中的detector.c文件中,if(i%10000==0 || (i < 1000 && i%100 == 0)) 表示迭代次数1000以下,每一百次保存一次模型,1000次以上,每1W次保存一次模型,可以根据需要自行修改。

    

   if(i%100==0){//这里改的是每多少次保存一个back模型,这个会覆盖掉之前的back模型
#ifdef GPU
            if(ngpus != 1) sync_nets(nets, ngpus, 0);
#endif
            char buff[256];
            sprintf(buff, "%s/%s.backup", backup_directory, base);
            save_weights(net, buff);
        }
        if(i%1000==0 || (i < 1000 && i%100 == 0)){//这里改的是每多少次保存一个模型,不会覆盖
#ifdef GPU
            if(ngpus != 1) sync_nets(nets, ngpus, 0);
#endif
            char buff[256];
            sprintf(buff, "%s/%s_%d.weights", backup_directory, base, i);
            save_weights(net, buff);
        }

修改文件后,要重新编译make,才能生效。如果不行,就先make clean,再make。

7. 保存训练日志,参数可视化

训练指令后面加2>1 | tee train_log.txt(后面这个txt名自定义,放在darknet文件下,记录训练日志),tee保存网络加载信息和checkout点保存信息。

./darknet detector train cfg/xx.data cfg/xx.cfg backup/xx.weights 2>1 | tee train_log.txt

日志参数可视化:

https://blog.csdn.net/yudiemiaomiao/article/details/72469135,亲测可用。三个文件在电脑上,先用convert_log.txt文件,分割log.txt成两个txt文档。之后分别运行log.py和iou.py文件(记得修改文件里面的txt路径及名称),可得到loss,avg loss变化图。(按照原来的x%10==9,loss只出现图,没有线。改成和iou一样,if(x%10==0 or x%10==9)就好了,不造咋回事,没细究。)

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章