yolo v2 之车牌检测

一、前言

        本文主要使用yolo v2 训练自己的车牌图片数据,并能够框出测试图片中存在的车牌区域,也即车牌检测。本文参考了博文http://m.blog.csdn.net/qq_34484472/article/details/73135354http://blog.csdn.net/zhuiqiuk/article/details/72722227

二、准备工作

        首先需要下载正确配置好darknet, 使用./darknet detect cfg/yolo.cfg yolo.weights data/dog.jpg 命令可得检测结果。本文主要是为了检测车牌区域,在darknet下新建一文件夹plate_imgae,其中存放train和val、pic三个文件夹,train文件夹下为1296张训练图片,val文件夹下为196张验证图片,pic为236张待检测的图片,图片格式均为jpg格式,训练模型主要用到train和val这两个文件夹。


三、制作标签文件

        yolo v2使用VOC格式的数据集,故这里首先需要对训练集及验证集的图片进行标注,每张图片均可得到相应的xml文件,然后再将xml文件转化为txt标签文件。参考这里http://blog.csdn.net/jesse_mx/article/details/53606897 安装标注工具LabelImg,安装完成后,./labelImg.py打开标注工具,先对train文件夹内的图片作标注,在plate_image文件夹下新建train_xml文件夹,用于存放生成的xml文件。所生成的xml文件如下所示:


同样的方法,也在在plate_image文件夹下新建val_xml文件夹,保存验证集的xml标注文件。这样就有VOC格式标记的XML文件,接下来需要将xml文件转换为txt文件,使用python转换,将train_xml中的xml文件,转换为txt保存于文件夹train_txt下;同理,将val_xml中的xml文件转换后保存于val_txt文件夹下

import xml.etree.ElementTree as ET  
import pickle  
import os  
from os import listdir, getcwd  
from os.path import join  

xml_label_Dir = 'train_xml'        #需转换的xml路径
txt_label_Dir = 'train_txt/'          #转换得的txt文件保存路径

def convert(size, box):        #归一化操作
    dw = 1./size[0]  
    dh = 1./size[1]  
    x = (box[0] + box[1])/2.0  
    y = (box[2] + box[3])/2.0  
    w = box[1] - box[0]  
    h = box[3] - box[2]  
    x = x*dw  
    w = w*dw  
    y = y*dh  
    h = h*dh  
    return (x,y,w,h)  
  
if not os.path.exists(txt_label_Dir):   
    os.makedirs(txt_label_Dir)  
for rootDir,dirs,files in os.walk(xml_label_Dir):  
    for file in files:  
        file_name = file.split('.')[0]  
        out_file = open(txt_label_Dir+'%s.txt'%(file_name),'w')  
        in_file = open("%s/%s"%(rootDir,file))  
        tree = ET.parse(in_file)  
        root = tree.getroot()  
        size = root.find('size')  
        w = int(size.find('width').text)  
        h = int(size.find('height').text)  
          
        for obj in root.iter('object'):  
            xmlbox = obj.find('bndbox')  
            b = (float(xmlbox.find('xmin').text), float(xmlbox.find('xmax').text), float(xmlbox.find('ymin').text), float(xmlbox.find('ymax').text))  
            bb = convert((w,h), b)  
            out_file.write("0" + " " + " ".join([str(a) for a in bb]) + '\n')      #only one class,index 0
        out_file.close()    
接着还需要获得训练集图片的绝对路径train_imgae_path.txt和验证集的绝对路径val_image_path.txt,同样使用以下python代码
import xml.etree.ElementTree as ET
import pickle
import os
from os import listdir, getcwd
from os.path import join

TrainDir = '/home/jyang/darknet/plate_image/train'

out_file = open('train_image_path.txt','w')
for root,dirs,files in os.walk(TrainDir):
    for file in files:
        out_file.write('%s/%s\n'%(root,file))
out_file.close()
YOLO是直接通过替换原图片绝对路径的后缀名来找到对应标记文件的。比如原图片的绝对路径为/home/ubuntu/data/train/1.jpg。则YOLO将会直接认为其对应的标记文件路径为/home/ubuntu/data/train/1.txt。所以,我们将之前生成的txt文件都放到相应的图片路径下,即将train_txt下txt文件放到train文件夹下,将val_txt下txt文件放到val文件夹下

看看plate_image下都有啥。


四、修改配置文件

(1)创建names文件

      在YOLO主目录的data文件夹下,创建一个.names文件,文件名任意,我的是myClass.names,在该文件中写入所有类别的名称,每一类占一行,我只检测车牌,故只在第一行写licence.

(2)修改data文件

     修改darknet主目录下的 cfg/voc.data文件,修改如下:

classes= 1                      #只有一个类别
train  = /home/jyang/darknet/plate_image/train_image_path.txt        #训练集的绝对路径
valid  = /home/jyang/darknet/plate_image/val_image_path.txt           #验证集的绝对路径
names = data/myClass.names
backup = /home/jyang/darknet/plate_image/backup                     #训练得的模型保存路径
(3)修改cfg文件

     修改darknet主目录下的cfg/yolo-voc.cfg。

1.[region]层中classes改为1

2.[region]层上方的[convolution]层中,filters的数量改成(classes+coords+1)*NUM。我这里改成了(1+4+1)*5=30.

五、 修改src/yolo.c文件

1.第13行改成 char *voc_names[] = {"licence"}; //如果你是一类的话,就改成这样,如果你有多类,自己根据需求改。

2.第322行draw_detections函数中,最后一个参数由20改成你的类别数,我这里是1

3.第354行demo函数中,倒数第三个参数由20改成你的类别数,我这里是1

4.第17行改成 char *train_images = "<你的路径>/train_imgae_path";

5.第18行改成 char *backup_directory = "你的路径/backup/";

6.第121行改成 char *base = "results/comp4_det_test_"

7.第123行改成 list *plist = get_paths("<你的路径>/val_image_path.txt"); 

8.第209行改成 char *base = "results/comp4_det_test_"

9.第210行改成 list *plist = get_paths("<你的路径>/val_image_path.txt");

10.将src/yolo_kernels.cu文件中,第62行draw_detections函数最后一个参数由20改成你的类别数,我这里是1.

11.scripts/voc_label.py 文件中 ,位置第9行改成:classes=[“licence”],因为我只有一类

12.将src/detector.c文件中,第372行改成 list *plist = get_paths("<你的路径>/val_image_path.txt");,第542行option_find_int函数的最后一个参数由20改成1.

六、重新编译darknet yolo

       进入darknet主目录,make clean后 make -j8

七、下载预训练文件cfg/darknet19_448.conv.23

        为了加快训练速度,下载官方提供的预训练模型,保存至cfg下。下载地址为

http://pjreddie.com/media/files/darknet19_448.conv.23

八、训练

        在darknet文件夹路径下运行命令:

        ./darknet detector train cfg/voc.data cfg/yolo-voc.cfg cfg/darknet19_448.conv.23
        系统默认会迭代45000次batch,如果需要修改训练次数,进入cfg/yolo_voc.cfg修改max_batches的值。

九、训练过程输出log

       参考自这篇文章http://blog.csdn.net/renhanchi/article/details/71077830?locationNum=13&fps=1,以下摘自这篇文章

       Region Avg IOU: 这个是预测出的bbox和实际标注的bbox的交集 除以 他们的并集。显然,这个数值越大,说明预测的结果越好

       Avg Recall: 这个表示平均召回率, 意思是 检测出物体的个数 除以 标注的所有物体个数。

       count: 标注的所有物体的个数。 如果 count = 6, recall = 0.66667, 就是表示一共有6个物体(可能包含不同类别,这个不管类别),然后我预测出来了4个,所以Recall 就是 4 除以 6 = 0.66667

       有一行跟上面不一样的,最开始的是iteration次数,然后是train loss,然后是avg train loss, 然后是学习率, 然后是一batch的处理时间, 然后是已经一共处理了多少张图片。 重点关注 train loss 和avg train loss,这两个值应该是随着iteration增加而逐渐降低的。如果loss增大到几百那就是训练发散了,如果loss在一段时间不变,就需要降低learning rate或者改变batch来加强学习效果。当然也可能是训练已经充分。这个需要自己判断

十、评估训练得的模型

       训练了3天,得到了迭代30000次的权值,在plate_image/backup/下生成了yolo-voc_30000.weights,当然还有其他迭代次数的权值,使用以下语句可以测试单张图片

./darknet detector test cfg/voc.data cfg/yolo-voc.cfg plate_image/backup/yolo-voc_30000.weights plate_image/pic/099999.jpg

       显示的检测结果为

       

      训练的时候只是用到了训练集,评估检测性能才会使用到验证集。使用以下指令评估

      root@computer:/home/jyang/darknet# ./darknet detector recall cfg/voc.data cfg/yolo-voc.cfg plate_image/backup/yolo-voc_30000.weights

      根据参考的第2篇博文,使用该指令的时候,会调用src/detector.c里的validate_detector_recall函数,将其中的阈值从0.001修改为0.25,防止过多框被识别出,将432行代码修改为如下:

fprintf(stderr, "Id:%5d Correct:%5d Total%5d\tRPs/Img: %.2f\tIOU: %.2f\tRecall:%.2f%%\tPrecision:%.2f%%\n", i, 
         correct, total, (float)proposals/(i+1), avg_iou*100/total, 100.*correct/total ,100.*correct/proposals);
重新make之后,运行结果为:

可见196张图片,准确率有97%以上。

结语

        本文只是使用了yolo v2 检测了车牌,后续对框下来的车牌图片作识别,请看《yolo v2之车牌检测后续识别字符(一)》


  • 3
    点赞
  • 61
    收藏
    觉得还不错? 一键收藏
  • 31
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 31
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值