yolo-v2修改只识别person
问题1:为什么classes改为1就是检测person了还不是其它的目标,可能是因为 cfg/coco.data 中,names = data/coco.names,而coco.names中person排第一个
查看run_detector和draw_detections函数的源码,修改的两个参数都是代表类别数
验证:将上面的1全部都改为2,查看coco.names里前两个分别为 person 和 bicycle 经测试,此时只检测这两类
问题2: 当输入为 ./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg 时,调用的函数为test_detector
而当输入为 ./darknet detector test cfg/coco.data cfg/yolov3.cfg yolov3.weights data/dog.jpg 时,调用的函数为 run_detector,在run_detector中再次调用了test_detector
所以如果用第一行的命令,是不是只需修改test_detector即可?
验证:可行
~/darknet/examples/darknet.c
main函数
line 408 ~/darknet/ 下的darknet文件是怎么得来的,为什么只有输入./darknet 时才会显示 usage: ./darknet <function>
line 412 给gpu-index赋值时为什么是find_int_arg函数的参数是 " -i "
line 425 这里开始的 if 语句就是 ./darknet<function> 中的各种 function 了
目标:使输入一张图片,只检测人体
这里测试时用的是
./darknet detect cfg/yolov3.cfg yolov3.weights data/dog.jpg
找到 “detect" 所对应的函数
line 435 test_detector("cfg/coco.data", argv[2], argv[3], filename, thresh, .5, outfile, fullscreen) 函数,找到其定义在下面的文件中
~/darknet/examples/detector.c
test_detector函数
line 565 第一个输入参数为datacfg,根据前文,默认输入为 cfg/coco.data 查看此文件,coco.data 中的 train,valid,backup的路径都没有找到在哪
options是read_data_cfg函数读取datacfg后返回的一个list类
line 566 这里的data/name.list 是什么意思
line 570 load_network函数是如何构建net的,见后文network.c
line 576 nms的用途没看明白,见line 604
line 587 image im = load_image_color(input,0,0)这个函数涉及OpenCV操作,与图片显示有关,后面再细看
image结构体里有w,h,c,data四个变量,w,h,应该是表示宽度和高度,单位应该是像素,c表示通道数,data还不知道表示什么
line 593 这几行还得仔细看看 net,network结构体中有一个变量layers,其类型为layer,layer也是一个结构体,因此,net中保存的应该是整个网络共有参数,而layer中
保存的应该是每一层的参数
line 598 调用函数network_predict(net,X),后一行就开始输出结果了,因些这一行比较关键,下面查看network_predict()函数定义。见下方network.c line 497-line 787
line 600 根据image.c中draw_detections()函数猜测nboxes应该指的时bounding boxes的数量?但和显示的不一样应该是有一些没显示出来
line 602 输出的是识别出的目标类别的编号
下一行的输出目标名称和概率在代码中没找到在哪里。见image.c
line 604 do_nms_sort(),按概率大小排序?
line 605 显示图片部分重点查看,draw_detections()这个函数是关键,可以修改names使其把概率包含进去。见image.c
line 613 OpenCV是只是用来显示图片,重点在上一部分
~/darknet/src/network.c
line 53 network *load_network(char *cfg, char *weights, int clear)
调用parse_network_cfg函数为结构体net赋值,net包含了网络的各种参数。见后文 parse.c
line 59 net->seen是哪个参数还没太看明白,详见network的定义 ~darknet/include/darknet.h line 495
line 177 network *make_network(int n) calloc(n)是一个C函数
在内存的动态存储区中分配n个长度为size的连续空间,函数返回一个指向分配起始地址的指针;如果分配不成功,返回NULL。
line 497 关键处调用了一个forward_network(net)函数,查看此函数。定义位于line 188
line 188 若使用gpu查看forward_network_gpu(net),line 762
line 762~769 是关于cuda的操作,具体意义暂未深究,下面一个for循环没太明白,fill_gpu()定义为啥没找到。。
line 786 调用函数pull_network_output(netp),line 1123
line 1123 调用函数get_network_output_layer(network *net),line 699,返回值是第net->layers[i].type!=COST的那一层,这个返回值也上一个函数的输入值
line 787 调用函数calc_network_cost(netp),计算损失函数。
~/darknet/src/parse.c
line 730 parse_network_cfg(char *filename)
line 739 section这一块儿没太明白,section应该是表示cfg文件中的每一小节,那为什么这个不是在循环里的,在line 836行
line 757 这个循环是输出了运行网络时输出的每一层网络的参数,细节看得有些模棱两可,里面那一串if语句中的各种parse函数是根据layer的不同类型分别调用不同的函数进行处
理,这里的各种parse函数的细节还没看
line 836 将处理完的layer,赋值给net->layers[count]
~/darknet/src/image.c
line 239 draw_detections()函数
line 255 打印类别及概率
line 295 定义了一个label,查看get_label()函数,line 132
line 132 image get_label(image **characters, char *string, int size),这里传入的size为im.h*0.03,可是size不是必须是整型吗?传入的characters就是前面的alphabet,查看函数
load_alphabet(),传入的string是什么呢,回头看调用此函数的地方,传入的是laberstr,是在函数draw_detections中定义的,结合后面的几点确定,最后修改line 243里那个循
环,把概率加进去就可以了。添加的内容,将dets[i].prob[j]由浮点转化为字符串,然后连接到labelstr后面,这引出一个问题,后面在draw时laberstr是如何分段的,如何修改才能
不对此有影响,先试一下吧。。试了一下发现成功了。
效果如图
line 223 image **load_alphabet(),这个里面的buff由sprintf函数以sprintf(buff, "data/labels/%d_%d.png", i, j)的格式写入buff中,查看data/labels中的文件,全是各种size的小的图片,
找到可以用来表示概率的图片,与ASCII码是对应的,37为百分号,46为小数点,48~57为数字0~9,看完此函数,继续看get_label(),line 138,
line 296 draw_label(),查看其定义
line 149 通过像素的操作把label画出来,关键还是在前面的get_label()