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)就好了,不造咋回事,沒細究。)

 

 

 

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