大家在使用深度学习进行识别检测的时候,有时候不仅要将其找到判别种类,有时候我们还要对坐标进行分析。下面给大家讲述如何通过YOLOV2进行训练的时候是如何输出物体的位置坐标。
1.查看保存检测图片的源码
大家阅读过源码肯定知道,在训练与检测的时候我们通常使用了YOLO里面的detector函数,而在不进行改变源码时,我们会将检测的图片存为darknet.exe同路径的“prediction.png”。由此我们可以查看保存检测图片的源码。
1.1首先在darknet/src/下找到image.c文件,找到(239行)的draw_detections函数,在规定位置将Boundingbox的坐标输出。
1.2保存Boundingbox坐标到一个.txt来做分析,这样我们可以实时的知道物体的类别以及位置。
注意:在C语言中,打开文件并在里面写东西,使用'w+',即先清空该文件,在填写,使用'a+'的时候,即不清空文件,填写文件。
2.YOLO批次测试图片,并将检测好的图片放到特定文件夹
2.1选择图片
选择测试图片,并将其放入文件夹下,使用如下图所示的python代码将测试图片的地址以及name存入.txt文档中,程序如下所示。并将该.txt的地址写入obj.data对应的valid里面。
from os import listdir,getcwd
import os
dir=getcwd()#得到该py文件的绝对路径
path=dir+'/Test'#写自己的地址即可(Test为自己文件夹的名称)
img_list=os.listdir(path)
img_file=open('test.txt','w')
for img in img_list:
img_name,index=os.path.splitext(img)##将文件的名称以及后缀名分离
img_file.write(path+'/'+img+"\n")
img_file.close()
2.2建立对应的.cfg
为了方便大家可以建立不同的.cfg,如train.cfg以及test.cfg,这样我们在调试运行darknet的时候我们可以方便而且不会出错。(detector.c文件在darknet/examples,obj.data以及.cfg在darknet/cfg中)
2.3批次测试图片,并保存自定义文件夹
实现了将文件放入某个特定的文件夹中(文件夹的名字及路径由自己设定),首先读取文件夹中图片的名称,并将图片的绝对路径保存在某一个txt文件中,在测试中,我们读取每个路径,对每个路径进行训练,并将测试好的图片放入特定文件夹中。
2.3.1更改后的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;
bool flag_test=true;
DIR *dir;
char basePath[1000];
memset(basePath,'\0',sizeof(basePath));
strcpy(basePath,"/home/xinhan/darknet/scripts/Test_img");
//basePath="/home/hx/darknet/test_img";
readFileList(basePath);
while(flag_test){
if(filename)
{
flag_test=false;
strncpy(input, filename, 256);
}
else
{
flag_test=false;
//printf("Enter Image Path: ");
fflush(stdout);
input="/home/xinhan/darknet/scripts/test_image.txt";
//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("/home/xinhan/darknet/scripts/out_image",0)==-1)//"/home/FENGsl/darknet/data"修改成自己的路径
{
if (mkdir("/home/xinhan/darknet/scripts/out_image",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,"/home/xinhan/darknet/scripts/out_image/%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;
}
}
}
printf("Test successfully!\n");
}
2.3.2 GetFilename(char *p)函数
#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);//6表示图片名称的长短,可根据自己图片名字来更改其数值
return name;
}
2.3.3 readFileList函数
int readFileList(char *basePath)
{
DIR *dir;
struct dirent *ptr;
char base[1000];
FILE* ra =fopen("/home/xinhan/darknet/scripts/test_image.txt","w");
if ((dir=opendir(basePath)) == NULL)
{
perror("Open dir error...");
exit(1);
}
while ((ptr=readdir(dir)) != NULL)
{
if(strcmp(ptr->d_name,".")==0 || strcmp(ptr->d_name,"..")==0) ///current dir OR parrent dir
continue;
else if(ptr->d_type == 8) ///file
{printf("d_name:%s/%s\n",basePath,ptr->d_name);
fprintf(ra,"%s/%s\n",basePath,ptr->d_name);}
else if(ptr->d_type == 10) ///link file
printf("d_name:%s/%s\n",basePath,ptr->d_name);
else if(ptr->d_type == 4) ///dir
{
memset(base,'\0',sizeof(base));
strcpy(base,basePath);
strcat(base,"/");
strcat(base,ptr->d_name);
readFileList(base);
}
}
fclose(ra);
closedir(dir);
return 1;
}
2.3.4将函数添加进去后,重新make
2.3.5执行批次测试图片
./darknet detector test cfg/obj.data cfg/test.cfg [weights]
默认输入的是我们既定好的路径。
2.4 YOLO指令
2.4.1测试并返回图片名称、类别以及置信度:./darknet detector train cfg/obj.data cfg/train.cfg [weights]
然后在输入对应单张图片的绝对路径,即可判断出图片中存在物体的类别以及置信度。(原本的darknet带的未更改的test_detector函数)
2.4.2测试模型的好坏,得到其recall以及IOU:./darknet detector valid cfg/obj.data cfg/valid.cfg [weights]
2.4.2.1更改detector.c中的validate_detector_recall()函数,本次实验默认是obj.data中的valid
validate_detector_recall函数定义和调用改为:
void validate_detector_recall(char *datacfg, char *cfgfile, char *weightfile)
validate_detector_recall(datacfg, cfg, weights);
validate_detector_recall中的plist和paths如下所示(原本的)
list *plist = get_paths("data/voc.2007.test");
char **paths = (char **)list_to_array(plist);
更改为:
list *options = read_data_cfg(datacfg);
char *valid_images = option_find_str(options, "valid", "data/train.list");
list *plist = get_paths(valid_images);
char **paths = (char **)list_to_array(plist);
2.4.2.2更改完代码后从新编译,在输入命令即可得到下图所示的评判标准。
/*依次ID:图片序号从0开始,correct:累计检测正确的总框数,total:累计的总ground truth数,RPs/Img: 累计的总proposals/已检测图片数,IOU,Recall: correct / total,proposals:累计的总框数,Precision: correct / proposals*/
2.5 GPU/CPU训练模型
单GPU:./darknet -i <gpu_id>detector train cfg/obj.data cfg/train.cfg [weights]
多GPU:./darknet detector train cfg/obj.data cfg/train.cfg [weights] -gpus 0,1,2,3
CPU:./darknet -nogpu detector train cfg/obj.data cfg/train.cfg [weights]
参考博客:https://blog.csdn.net/NNNNNNNNNNNNY/article/details/54561928
https://blog.csdn.net/mieleizhi0522/article/details/79989754