车牌检测识别功能实现

本文还有配套的精品资源,点击获取 menu-r.4af5f7ec.gif

本文档介绍如何利用已训练好的车牌检测与识别模型,结合tkinter构建界面,实现实时车牌检测、识别及时间费用统计。主要内容包括修改YOLOv5检测函数以增加分类识别,设计用户界面,并展示检测结果。

在本专题前面相关博客中已经讲述了 车牌检测与车牌识别算法的模型训练操作步骤以及数据集的制作过程。

本博文将结合前面训练好的模型来实现车牌的检测与识别。并用tkinter实现界面。最终通过检测车牌检测的前后时间来实现 时间与费用的统计计算展示。

1)修改检测函数

在yolov5检测函数的基础上进行修改,增加识别车牌的功能

def detect(opt,source,save_path,save_img=False):
    classify, out,  det_weights, rec_weights, view_img, save_txt, imgsz = \
        opt.classify, opt.output,  opt.det_weights, opt.rec_weights,  opt.view_img, opt.save_txt, opt.img_size
    webcam = source == '0' or source.startswith('rtsp') or source.startswith('http') or source.endswith('.txt')

    # Initialize
    device = torch_utils.select_device(opt.device)
    if os.path.exists(out):
        shutil.rmtree(out)  # delete rec_result folder
    os.makedirs(out)  # make new rec_result folder
    half = device.type != 'cpu'  # half precision only supported on CUDA

    # Load yolov5 model
    model = attempt_load(det_weights, map_location=device)  # load FP32 model
    print("load det pretrained model successful!")
    imgsz = check_img_size(imgsz, s=model.stride.max())  # check img_size
    if half:
        model.half()  # to FP16

    # Second-stage classifier  也就是rec 字符识别
    if classify:
        modelc = LPRNet(lpr_max_len=8, phase=False, class_num=len(CHARS), dropout_rate=0).to(device)
        modelc.load_state_dict(torch.load(rec_weights, map_location=torch.device('cpu')))
        print("load rec pretrained model successful!")
        modelc.to(device).eval()

    # Set Dataloader
    vid_path, vid_writer = None, None
    if webcam:
        view_img = True
        cudnn.benchmark = True  # set True to speed up constant image size demo
        dataset = LoadStreams(source, img_size=imgsz)
    else:
        save_img = True
        dataset = LoadImages(source, img_size=imgsz)

    # Get names and colors
    names = model.module.names if hasattr(model, 'module') else model.names
    colors = [[random.randint(0, 255) for _ in range(3)] for _ in range(len(names))]

    # Run demo
    t0 = time.time()
    img = torch.zeros((1, 3, imgsz, imgsz), device=device)  # init img
    _ = model(img.half() if half else img) if device.type != 'cpu' else None  # run once
    lb = ""
    for path, img, im0s, vid_cap in dataset:
        img = torch.from_numpy(img).to(device)
        img = img.half() if half else img.float()  # uint8 to fp16/32
        img /= 255.0  # 0 - 255 to 0.0 - 1.0
        if img.ndimension() == 3:
            img = img.unsqueeze(0)

        # Inference
        t1 = torch_utils.time_synchronized()
        pred = model(img, augment=opt.augment)[0]
        # Apply NMS
        pred = non_max_suppression(pred, opt.conf_thres, opt.iou_thres, classes=opt.classes, agnostic=opt.agnostic_nms)


        # Apply Classifier
        if classify:
            pred, plat_num = apply_classifier(pred, modelc, img, im0s)

        t2 = torch_utils.time_synchronized()

        # Process detections
        
        for i, det in enumerate(pred):  # detections per image
            if webcam:  # batch_size >= 1
                p, s, im0 = path[i], '%g: ' % i, im0s[i].copy()
            else:
                p, s, im0 = path, '', im0s

            #save_path = str(Path(out) / Path(p).name)
            txt_path = str(Path(out) / Path(p).stem) + ('_%g' % dataset.frame if dataset.mode == 'video' else '')
            s += '%gx%g ' % img.shape[2:]  # print string
            gn = torch.tensor(im0.shape)[[1, 0, 1, 0]]  # normalization gain whwh
            if det is not None and len(det):
                # Rescale boxes from img_size to im0 size
                det[:, :4] = scale_coords(img.shape[2:], det[:, :4], im0.shape).round()

                # Print results
                for c in det[:, 5].unique():
                    n = (det[:, 5] == c).sum()  # detections per class
                    s += '%g %ss, ' % (n, names[int(c)])  # add to string

                # Write results
                for de, lic_plat in zip(det, plat_num):
                    # xyxy,conf,cls,lic_plat=de[:4],de[4],de[5],de[6:]
                    *xyxy, conf, cls=de

                    if save_txt:  # Write to file
                        xywh = (xyxy2xywh(torch.tensor(xyxy).view(1, 4)) / gn).view(-1).tolist()  # normalized xywh
                        with open(txt_path + '.txt', 'a') as f:
                            f.write(('%g ' * 5 + '\n') % (cls, xywh))  # label format

                    if save_img or view_img:  # Add bbox to image
                        # label = '%s %.2f' % (names[int(cls)], conf)
                        
                        for a,i in enumerate(lic_plat):
                            # if a ==0:
                            #     continue
                            lb += CHARS[int(i)]
                        label = '%s %.2f' % (lb, conf)
                        im0 = plot_one_box(xyxy, im0, label=label, color=colors[int(cls)], line_thickness=3)

            # Print time (demo + NMS)
            print('%sDone. (%.3fs)' % (s, t2 - t1))

            # Stream results
            if view_img:
                cv2.imshow(p, im0)
                if cv2.waitKey(1) == ord('q'):  # q to quit
                    raise StopIteration

            # Save results (image with detections)
            if save_img:
                if dataset.mode == 'images':
                    cv2.imwrite(save_path, im0)
                else:
                    if vid_path != save_path:  # new video
                        vid_path = save_path
                        if isinstance(vid_writer, cv2.VideoWriter):
                            vid_writer.release()  # release previous video writer

                        fourcc = 'mp4v'  # rec_result video codec
                        fps = vid_cap.get(cv2.CAP_PROP_FPS)
                        w = int(vid_cap.get(cv2.CAP_PROP_FRAME_WIDTH))
                        h = int(vid_cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
                        vid_writer = cv2.VideoWriter(save_path, cv2.VideoWriter_fourcc(*fourcc), fps, (w, h))
                    vid_writer.write(im0)


    if save_txt or save_img:
        print('Results saved to %s' % os.getcwd() + os.sep + out)
        if platform == 'darwin':  # MacOS
            os.system('open ' + save_path)

    print('Done. (%.3fs)' % (time.time() - t0))


    return lb

主要改动 为在 yolov5检测函数的基础上增加分类识别功能

    # Second-stage classifier  也就是rec 字符识别
    if classify:
        modelc = LPRNet(lpr_max_len=8, phase=False, class_num=len(CHARS), dropout_rate=0).to(device)
        modelc.load_state_dict(torch.load(rec_weights, map_location=torch.device('cpu')))
        print("load rec pretrained model successful!")
        modelc.to(device).eval()

   
     # Apply Classifier
        if classify:
            pred, plat_num = apply_classifier(pred, modelc, img, im0s)

因为需要进行界面调用,所以最终将检测识别的车牌进行了返回

return lb

2) 设计实现如下界面

界面代码实现如下

""" 窗口初始化 """
window = tk.Tk()  # 实例化object,建立窗口window
window.title('人员数量统计')  # 窗口名
window.geometry('740x740')  # 设定窗口的大小(长x宽)
window.resizable(0, 0)  # 设置窗口大小不可变
myfront = ['Consolas', 11]  # 字体参数
infofront = ['Consolas', 10]

var1 = StringVar()
var2 = StringVar()


def print_scale(v):
    var2.set(v)
   


""" 框架组件 用于布局"""
# 父组件 边框像素(1凹陷感,2框线感)->简写bd 边线风格 垂直边距 高 宽
f1 = tk.Frame(window, borderwidth=2, relief="groove", height=100, width=700)
f2 = tk.Frame(window, borderwidth=2, relief="groove", height=160, width=700)
f3 = tk.Frame(window, borderwidth=2, relief="groove", height=400, width=700)
# grid布局 所在行 所在列 (跨越行数) 水平边距 垂直边距
f1.grid(row=0, column=0, padx=20, pady=20)  # 700+20+20=740 边框长+边距*2=窗口长 因此边框居中
f2.grid(row=1, column=0, padx=20, pady=0)
f3.grid(row=2, column=0, padx=20, pady=20)
# 固定组件大小,防止子组件大小影响
f1.grid_propagate(0)  # 子组件为grid布局
f2.grid_propagate(0)
f3.grid_propagate(0)


""" 标签 输入输出"""
title_output = tk.Label(f1, text='输出路径:', font=myfront, width=0, height=0)
title_input = tk.Label(f1, text='输入路径:', font=myfront, width=0, height=0)
# font为字体 width为长 height为高 这里的是字符的长和高(字符间距)
""" 输入路径 """
text_input = tk.Entry(f1, width=65, bd=2, show=None, state='normal', exportselection=False)  # 无密文 可写
# 此处双击文本 与list选择模型(line:70)事件冲突 双击后list失去选择报错 指定ex=f后解决(选中文本不可复制到剪贴板)
# 可双击选中 ctrl+C复制
text_input.insert(0, "未选择...")  # 写入文本
text_input.config(state='readonly')  # 写入后设为只读
""" 输出路径 """
text_output = tk.Entry(f1, width=65, bd=2, show=None, state='normal', exportselection=False)
text_output.insert(0, "未选择...")
text_output.config(state='readonly')
""" 按钮 选择文件 """
button_chooseFile = tk.Button(f1, text='选择文件', font=myfront, width=10, height=1, bd=4,
                              command=lambda: func_chooseFile(entryInput=text_input, entryOutput=text_output))
# command是按钮回调函数 lambda:传递参数
""" 按钮 开始 """
button_start = tk.Button(f1, text='开始', font=myfront, width=10, height=1, bd=4,
                         command=lambda: func_start())
""" 布局 """
title_input.grid(row=0, column=0, padx=10, pady=15)
title_output.grid(row=1, column=0, padx=10, pady=0)
text_input.grid(row=0, column=1, padx=0, pady=0)
text_output.grid(row=1, column=1, padx=0, pady=0)
button_chooseFile.grid(row=0, column=2, padx=15, pady=0)
button_start.grid(row=1, column=2, padx=15, pady=0)


""" 标签 参数选择"""
title_chvi = tk.Label(f2, text='视频/图像:', font=myfront, width=0, height=0)
title_chways = tk.Label(f2, text='选择阈值:', font=myfront, width=0, height=0)


s1=Scale(f2,from_=0,to=600,orient=HORIZONTAL,
    length=265,showvalue=1,variable=var1,tickinterval=200,
    resolution=1,command=print_scale)

e = Entry(f2,textvariable=var2,width=4,font=("仿宋", 17, "normal"))
""" 单选 算法选择 """

""" 单选 视频/图像 """
r_vi = StringVar()
r_vi.set('image')
radio_vi = tk.Radiobutton(f2, text='视频', variable=r_vi, value='video',
                          command=lambda: func_VideoImage(
                              ch='video'))
radio_vi2 = tk.Radiobutton(f2, text='图像', variable=r_vi, value='image',
                           command=lambda: func_VideoImage(
                               ch='image'))
""" 布局 """
title_chvi.grid(row=0, column=0, padx=40, pady=10)
radio_vi.grid(row=2, column=0, padx=0, pady=0)
radio_vi2.grid(row=1, column=0, padx=0, pady=0)
title_chways.grid(row=0, column=1, padx=0, pady=0)

s1.grid(row=1, column=1, padx=0, pady=0)
e.grid(row=2, column=1, padx=0, pady=0)



""" 标签 """

lmain = Label(master=f3, bg="blue" ,borderwidth=2, relief="groove", width=image_width, height=image_height)
lmain2 = Label(master=f3,  borderwidth=2, relief="groove", width=image_width, height=image_height)


lmain.pack(side = LEFT)
lmain2.pack(side = RIGHT)
lmain.grid(row=0, column=0, padx=0, pady=0)
lmain2.grid(row=0, column=1, padx=0, pady=0)
lmain.pack_propagate(0)
lmain2.pack_propagate(0)



""" 主窗口循环显示 """


window.mainloop()


 3)结果检测

备注:这篇博文中涉及到的模型都是前面博文中训练来的。

完整的代码见

https://download.csdn.net/download/reset2021/87946658?spm=1001.2101.3001.9499

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

reset2021

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值