YOLO用于检测目标和目标识别,即精确找到物体的位置并标注物体类别。YOLO神经网络主要有以下两个工程上面的优势:
(一)采用单个卷积神经网络利用全图信息来预测目标区域和所属类别,速度非常快,在GPU上可以达到实时。
(二)代码不依赖其他的库,都是纯C写的,方便移植和二次开发。
本文采用Windows 7平台,在VS2015环境下配置和调试,使用CPU(GPU可以下载CUDA自行测试):
- 下载YOLO V3代码:Github链接:https://github.com/AlexeyAB/darknet 百度云链接:百度网盘 请输入提取码 密码:q27g;
- 解压文件夹,在如下路径用VS2015打开darknet_no_gpu.sln;
- 更改模式为release,x64;
- 点击打开工程属性
- 更改为你的opencv包含路径和库路径
- 点击生成解决方案
- 下载权值文件yolov3.weights或者yolov3-tiny.weights(yolov3-tiny.weights文件小,速度快,效果差一点,本文选择yolov3-tiny.weights进行讲解),将权值文件放在..\darknet-master\darknet-master\build\darknet\x64(..为你的工程所在目录)。下载链接:百度网盘 请输入提取码 密码:azfa;
- 复制darknet_yolo_v3.cmd,并更改副本名称为darknet_yolo_v3-tiny.cmd;
- 点击右键-》编辑,更改darknet_yolo_v3-tiny.cmd内容:
darknet.exe改为darknet_no_gpu.exe,yolov3.cfg改为cfg/yolov3-tiny.cfg,yolov3.weights改为yolov3-tiny.weights
- 保存后退出,运行darknet_yolo_v3-tiny.cmd得到测试图
- 如果需要单步调试,请继续往后看;
- 进入darknet_no_gpu.sln工程,打开darknet.c,找到main函数所在位置
- 更改main函数为:
int main()
{
gpu_index = -1;
int argc = 10;
char **argv;
argv = (char **)malloc(sizeof(char)*argc);
for (int i = 0; i < argc; i++)
{
*(argv + i) = (char *)malloc(sizeof(char) * 30);
}
argv[0] = "darknet.exe";//多一个就行
argv[1] = "detector";
argv[2] = "test";
argv[3] = "x64/data/coco.data";
argv[4] = "x64/cfg/yolov3-tiny.cfg";
argv[5] = "x64/yolov3-tiny.weights";
argv[6] = "x64/dog.jpg";
argv[7] = "-thresh";
argv[8] = "0.25";
argv[9] = "pause";
run_detector(argc, argv);
return 0;
}
- 更改detector.c中函数void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh, float hier_thresh, int dont_show, int ext_output, int save_labels)为:(注:与原函数改动不大,可以自己核对)
void test_detector(char *datacfg, char *cfgfile, char *weightfile, char *filename, float thresh,
float hier_thresh, int dont_show, int ext_output, int save_labels)
{
list *options = read_data_cfg(datacfg);
char *name_list = "x64/data/coco.names";
int names_size = 0;
char **names = (char **)calloc(80, sizeof(char *));
FILE* fp;
char buffer[255];
fp = fopen(name_list, "r");
while (fgets(buffer, 255, (FILE*)fp)) {
//strlen(buffer);
names[names_size] = (char *)calloc(strlen(buffer), sizeof(char));
strcpy(names[names_size], buffer);
names[names_size][strlen(buffer) - 1] = 0;
++names_size;
}
fclose(fp);
image **alphabet = load_alphabet();
network net = parse_network_cfg_custom(cfgfile, 1); // set batch=1
if(weightfile){
load_weights(&net, weightfile);
}
//set_batch_network(&net, 1);
fuse_conv_batchnorm(net);
if (net.layers[net.n - 1].classes != names_size) {
printf(" Error: in the file %s number of names %d that isn't equal to classes=%d in the file %s \n",
name_list, names_size, net.layers[net.n - 1].classes, datacfg);
if(net.layers[net.n - 1].classes > names_size) getchar();
}
srand(2222222);
double time;
char buff[256];
char *input = buff;
int j;
float nms=.45; // 0.4F
while(1){
if(filename){
strncpy(input, filename, 256);
if(strlen(input) > 0)
if (input[strlen(input) - 1] == 0x0d) input[strlen(input) - 1] = 0;
} else {
printf("Enter Image Path: ");
fflush(stdout);
input = fgets(input, 256, stdin);
if(!input) return;
strtok(input, "\n");
}
image im = load_image(input,0,0,net.c);
int letterbox = 0;
image sized = resize_image(im, net.w, net.h);
//image sized = letterbox_image(im, net.w, net.h); letterbox = 1;
layer l = net.layers[net.n-1];
//box *boxes = calloc(l.w*l.h*l.n, sizeof(box));
//float **probs = calloc(l.w*l.h*l.n, sizeof(float *));
//for(j = 0; j < l.w*l.h*l.n; ++j) probs[j] = calloc(l.classes, sizeof(float *));
float *X = sized.data;
time= what_time_is_it_now();
network_predict(net, X);
//network_predict_image(&net, im); letterbox = 1;
printf("%s: Predicted in %f seconds.\n", input, (what_time_is_it_now()-time));
//get_region_boxes(l, 1, 1, thresh, probs, boxes, 0, 0);
// if (nms) do_nms_sort_v2(boxes, probs, l.w*l.h*l.n, l.classes, nms);
//draw_detections(im, l.w*l.h*l.n, thresh, boxes, probs, names, alphabet, l.classes);
int nboxes = 0;
detection *dets = get_network_boxes(&net, im.w, im.h, thresh, hier_thresh, 0, 1, &nboxes, letterbox);
if (nms) do_nms_sort(dets, nboxes, l.classes, nms);
draw_detections_v3(im, dets, nboxes, thresh, names, alphabet, l.classes, ext_output);
save_image(im, "predictions");
if (!dont_show) {
show_image(im, "predictions");
}
// pseudo labeling concept - fast.ai
if(save_labels)
{
char labelpath[4096];
replace_image_to_label(input, labelpath);
FILE* fw = fopen(labelpath, "wb");
int i;
for (i = 0; i < nboxes; ++i) {
char buff[1024];
int class_id = -1;
float prob = 0;
for (j = 0; j < l.classes; ++j) {
if (dets[i].prob[j] > thresh && dets[i].prob[j] > prob) {
prob = dets[i].prob[j];
class_id = j;
}
}
if (class_id >= 0) {
sprintf(buff, "%d %2.4f %2.4f %2.4f %2.4f\n", class_id, dets[i].bbox.x, dets[i].bbox.y, dets[i].bbox.w, dets[i].bbox.h);
fwrite(buff, sizeof(char), strlen(buff), fw);
}
}
fclose(fw);
}
free_detections(dets, nboxes);
free_image(im);
free_image(sized);
//free(boxes);
//free_ptrs((void **)probs, l.w*l.h*l.n);
#ifdef OPENCV
if (!dont_show) {
cvWaitKey(0);
cvDestroyAllWindows();
}
#endif
if (filename) break;
}
// free memory
free_ptrs(names, net.layers[net.n - 1].classes);
free_list_contents_kvp(options);
free_list(options);
int i;
const int nsize = 8;
for (j = 0; j < nsize; ++j) {
for (i = 32; i < 127; ++i) {
free_image(alphabet[j][i]);
}
free(alphabet[j]);
}
free(alphabet);
free_network(net);
}
- 更改image.c中函数image **load_alphabet()为:
image **load_alphabet()
{
int i, j;
const int nsize = 8;
image **alphabets = calloc(nsize, sizeof(image));
for(j = 0; j < nsize; ++j){
alphabets[j] = calloc(128, sizeof(image));
for(i = 32; i < 127; ++i){
char buff[256];
sprintf(buff, "x64/data/labels/%d_%d.png", i, j);
alphabets[j][i] = load_image_color(buff, 0, 0);
}
}
return alphabets;
}
- 运行得到结果
- 至此,你就可以进行happy的调试之旅。
- 这是经过以上操作配置好的调试版本,直接使用可以省点事o.o 链接:百度网盘 请输入提取码 密码:u66a