然后有了几千条数据之后就可以初步训练一个分类器出来了,用分类器的推断结果再标注剩下的图的一部分,岂不美哉?
可比百度那个接口标注准度提升的多了~
一、修改yolov3源代码为批量推断
注意啦!代码修改全是基于darknet-yolov3的!
//examples/detector.c里面前面部分要改成这样子且增加一个函数#include "darknet.h"
#include <opencv2/highgui/highgui_c.h>
#include <sys/stat.h> //add
#include <stdio.h> //add
#include <unistd.h> //add
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/timeb.h>
#include <sys/types.h>
#include <time.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[200]={""};char *q = strrchr(p,'/') + 1;strncpy(name,q,60); //6是你的测试图像名称的长度return name;
}//改完了以后把这个函数换成这个样子~
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);// time_t t;// t=time(0);// printf("%ld\n",t);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 OPENCVcvNamedWindow("predictions", CV_WINDOW_NORMAL); if(fullscreen){cvSetWindowProperty("predictions", CV_WND_PROP_FULLSCREEN, CV_WINDOW_FULLSCREEN);}show_image(im, "predictions",0);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");struct timeb timebuffer1,timebuffer2;time_t time1,time2;unsigned short millitm1,millitm2;ftime( &timebuffer1 );time1 = timebuffer1.time;millitm1 = timebuffer1.millitm;//当前时间的秒值baiprintf( "Seconds since midnight, January 1, 1970 (UTC): %Id\n",time1);//当前时间的毫秒值printf( "Milliseconds: %d\n", millitm1);list *plist = get_paths(input);char **paths = (char **)list_to_array(plist);printf("Start Testing!\n");int m = plist->size;if(access("/home/nvidia/yolov3/darknet/output",0)==-1)//修改成自己的路径{if (mkdir("/home/nvidia/yolov3/darknet/output",0777))//修改成自己的路径{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("\n%s:", path);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/nvidia/yolov3/darknet/output/%s",GetFilename(path));//修改成自己的路径// 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",0);// cvWaitKey(0);// cvDestroyAllWindows();
#endif// }free_image(im);free_image(sized);// if (filename) break;// struct timeb timebuffer1,timebuffer2;// time_t time1,time2;// unsigned short millitm1,millitm2;// ftime( &timebuffer1 );// time1 = timebuffer1.time;// millitm1 = timebuffer1.millitm;//当前时间的秒值bai// printf( "%Id\n",time1);//当前时间的毫秒值// printf( "Milliseconds: %d\n", millitm1);}}}}
这是第一个文件的修改,主要是屏蔽没用的输出,单张推断改为从文件按照行读取图片目录,然后是第二个
//src/image.c这个里面也是改一个函数
void draw_detections(image im, detection *dets, int num, float thresh, char **names, image **alphabet, int classes)
{int i,j;int x;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);x = j;}}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;int b_x_center = (left + right) / 2;int b_y_center = (top + bot) / 2;int b_width = right - left;int b_height = bot - top;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);}printf("%d,%d,%d,%d,%s;",b_x_center-(b_width/2), b_y_center-(b_height/2), b_width, b_height,names[x]);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);}}}
}
从画框函数获取坐标值,然后配合标签打印出来,C++实在是太繁琐了,我不会写到txt,就只能跑完了手动保存了
修改好了就make clean & make重新编译一次
二、批量推断
运行那个detector test的推断命令,注意权重后面要空着
等到读完了权重打印出模型结构以后输入那个文件名的txt地址:
#这是个Python文件,深度学习工程师当然用Python了
import os
paths = "/home/nvidia/test" # 测试图片的路径
f = open('1.txt', 'w') # 最后得到的图片路径txt文件
filenames = os.listdir(paths)
filenames.sort()
for filename in filenames:out_path = "/home/nvidia/test/" + filename # 引号内为测试图片文件夹的绝对路径print(out_path)f.write(out_path + '\n')
f.close()
使用这个文件得出图片路径的txt文件,大概这个样:
/home/name/xxxxx/1.jpg
/home/name/xxxxx/2.jpg
/home/name/xxxxx/3.jpg
/home/name/xxxxx/4.jpg
/home/name/xxxxx/5.jpg
/home/name/xxxxx/6.jpg
然后说回到运行那个推断命令,观察终端的输出,把这些东西保存下来:
/home/nvidia/test/1cdb-1250-41e6-9582-c9871e20b49e.jpg:191,252,212,201,class1;
/home/nvidia/test/292a3f-254c-48d0-8e14-596fb103667a.jpg:277,262,212,217,class2;
/home/nvidia/test/29ab95-f3f8-458b-b082-2bf5a1056e38.jpg:185,262,194,201,class1;
/home/nvidia/test/adc2-0255-40e9-8dd9-e831544db847.jpg:305,170,201,220,class2;
/home/nvidia/test/10d-9a08-496f-88c2-95aab3859312.jpg:173,314,266,165,class1;
/home/nvidia/test/7346-5881-4b26-a5e6-425cf3dce4ae.jpg:236,226,219,242,class5;
/home/nvidia/test/7a77-98ef-4c52-9667-7e6e43ee9de3.jpg:211,217,239,262,class1;
/home/nvidia/test/5e-472d-4a6e-bdd3-4d3034e65eb7.jpg:234,373,230,99,class5;
/home/nvidia/test/867-4058-bd61-b90f57ac34e1.jpg:320,218,255,261,class1;
/home/nvidia/test/d3-ba8e-4665-a8f1-49f4842e2d2b.jpg:254,270,235,203,class1;
三、自动标注
#这是个Python文件import cv2
import sys
import os
# res text file name
file_v3 = open("图片路径那个txt")
flag_face = 0
res_str = ""
part1 = "<annotation><folder>jiaobaba</folder><filename>"
part2 = "</filename><path>"
part3 = "</path><source><database>Unknown</database></source><size><width>"
part4 = "</width><height>"
part5 = "</height><depth>"
part6 = "</depth></size><segmented>0</segmented>"
t1 = "<object><name>"
t2 = "</name><pose>Unspecified</pose><truncated>1</truncated><difficult>0</difficult><bndbox><xmin>"
t3 = "</xmin><ymin>"
t4 = "</ymin><xmax>"
t5 = "</xmax><ymax>"
t6 = "</ymax></bndbox></object>"
write_xml_file_path = "xml标注文件保存到哪里?"
while 1:lines_v3 = file_v3.readlines()for index in range(len(lines_v3)):file_path_and_val = lines_v3[index].split(":")tmp = ""if(file_path_and_val[1]!=""):file_path = file_path_and_val[0]file_name = file_path.split("/")[-1]file_name_no_type = file_name.split(".")[0]h = 0w = 0d = 0print("hit -> ",file_path)img = cv2.imread(file_path)h,w,d = img.shapedata = file_path_and_val[1]class_and_coordinate = data.split(";")# print(class_and_coordinate)for i in range(len(class_and_coordinate)-1):part_data = class_and_coordinate[i].split(",")xmin = int(part_data[0])ymin = int(part_data[1])xmax = int(part_data[0])+int(part_data[2])ymax = int(part_data[1])+int(part_data[3])tmp = tmp + t1+part_data[4]+t2+str(xmin)+t3+str(ymin)+t4+str(xmax)+t5+str(ymax)+t6res_str = part1+file_name+part2+file_path+part3+str(w)+part4+str(h)+part5+str(d)+part6+tmpres_str = res_str + "</annotation>"every_line_xml_path = write_xml_file_path+file_name_no_type+".xml"file_xml = open(every_line_xml_path,'w')file_xml.write(res_str)file_xml.close()res_str = ""part_data = []h = 0w = 0d = 0tmp = ""
file_v3.close()
运行这个文件,得到xml标注信息以后到labelimg检查一遍就OK了
所以说,懒惰是科技发展的原动力~