当前位置:   article > 正文

【香橙派 Orange pi AIpro】| 搭建部署基于Yolov5的车牌识别系统_aipro部署yolov5

aipro部署yolov5

最近刚好想研究一下嵌入式方面的知识就看到了香橙派新出的板子 Orange pi AIpro,果断搞来研究一下

在这里插入图片描述

一、香橙派 Orange pi AIpro 开发板介绍及实物开箱

1.1 开发板介绍

昇腾AI技术路线:高性能,低功耗 4核64位处理器 + AI处理器,速度更快,功耗更低,可为各类AI应用场景带来卓越的性能表现。

多通道输出,支持多屏异显:支持双HDMI视频输出,支持双4K高清输出,支持一个MIPI DSI屏输出,支持两个MIPI接口摄像头输入。

丰富接口,易于扩展:汇聚了MIPI DSI、MIPI CSI、USB 3.0、Type-C 3.0、HDMI 2.0、千兆以太网、支持SATA/NVMe SSD 2280的M.2插槽等各类流行的接口,可应用于外部设备控制和扩展。

应用场景广泛 覆盖 AIoT各行各业:可广泛适用于AI教学实训、AI算法验证、智能小车、机械臂、边缘计算、无人机、人工智能、云计算、AR/VR、智能安防、智能家居、智能交通等领域。

可运行openEuler系统:高效、稳定、安全。可运行openEuler系统,支持多种硬件架构和虚拟化技术,可广泛应用于企业级云计算、边缘计算场景等。

在这里插入图片描述

1.2 产品详情图

正面
在这里插入图片描述
背面
在这里插入图片描述

1.3 开箱实物

物品清单
在这里插入图片描述
正面图
在这里插入图片描述

背面图
在这里插入图片描述

在提交申请后,也是很快就收到了快递包裹,开箱后,有一个快充头和数据线,板子同标准的盒子装着,同时用两块薄海绵包裹着,可以预防静电对板子造成损害
实物颜值非常高,且已经自带了一块32G的TF卡,里面也已经烧录了openeuler镜像系统

二、开发部署预先准备

2.1 镜像介绍与烧录

开发板默认支持 ubuntu系统和 openeuler系统,由于 TF卡中已经预先烧录好了 openeuler系统,所以下面我就直接使用该系统进行搭建和部署了,熟悉和习惯 ubuntu系统的用户也可以格式化,重新烧录一个 ubuntu系统。

在这里插入图片描述

官方也提供了烧录工具
在这里插入图片描述

2.2 启动开发板

连接电源后,开发板会自动启动
在这里插入图片描述

2.3 连接开发板

由于手边没有 HDMI 线,我就直接用远程连接的方式连接吧

  1. 拿到开发板的 ip
    在这里插入图片描述

  2. 使用 MobaXterm 远程连接
    在这里插入图片描述

三、基于Yolov5的车牌识别系统

3.1 项目介绍

该项目是一个基于深度学习与yolov5 的车牌检测 、车牌识别、中文车牌识别与检测、支持12种中文车牌、支持双层车牌的目标识别系统。
项目开源地址:Chinese_license_plate_detection_recognition

3.2 拉取项目

  1. 先创建一个文件夹用来存放我们的项目
mkdir yolov5
  • 1

在这里插入图片描述

  1. 开发板系统中已经预先安装好了 git,我们直接使用 git 将项目拉取下来就可以了
git clone https://github.com/we0091234/Chinese_license_plate_detection_recognition.git
  • 1

在这里插入图片描述

  1. 进入到刚刚拉取的项目中
cd Chinese_license_plate_detection_recognition
  • 1

在这里插入图片描述

  1. 刚刚拉取的项目,需要众多的依赖,这里需要下载一下,使用下面的命令下载就可以了
pip install -r ./requirements.txt -i https://mirrors.aliyun.com/pypi/simple
  • 1

需要下载的依赖比较多,这里可能需要多等待一下

在这里插入图片描述
出现绿色的 Successfully 就代表依赖下载成功了

  1. 到此为止,项目就算拉取成功了,我们看一下,项目的目录文件结构

在这里插入图片描述
可以看到文件还是很多的

3.3 部分核心代码

# -*- coding: UTF-8 -*-
import argparse
import time
from pathlib import Path
import os
import cv2
import torch
import torch.backends.cudnn as cudnn
from numpy import random
import copy
import numpy as np
from models.experimental import attempt_load
from utils.datasets import letterbox
from utils.general import check_img_size, non_max_suppression_face, apply_classifier, scale_coords, xyxy2xywh, \
    strip_optimizer, set_logging, increment_path
from utils.plots import plot_one_box
from utils.torch_utils import select_device, load_classifier, time_synchronized
from utils.cv_puttext import cv2ImgAddText
from plate_recognition.plate_rec import get_plate_result,allFilePath,init_model,cv_imread
# from plate_recognition.plate_cls import cv_imread
from plate_recognition.double_plate_split_merge import get_split_merge

clors = [(255,0,0),(0,255,0),(0,0,255),(255,255,0),(0,255,255)]
danger=['危','险']
def order_points(pts):                   #四个点按照左上 右上 右下 左下排列
    rect = np.zeros((4, 2), dtype = "float32")
    s = pts.sum(axis = 1)
    rect[0] = pts[np.argmin(s)]
    rect[2] = pts[np.argmax(s)]
    diff = np.diff(pts, axis = 1)
    rect[1] = pts[np.argmin(diff)]
    rect[3] = pts[np.argmax(diff)]
    return rect


def four_point_transform(image, pts):                       #透视变换得到车牌小图
    # rect = order_points(pts)
    rect = pts.astype('float32')
    (tl, tr, br, bl) = rect
    widthA = np.sqrt(((br[0] - bl[0]) ** 2) + ((br[1] - bl[1]) ** 2))
    widthB = np.sqrt(((tr[0] - tl[0]) ** 2) + ((tr[1] - tl[1]) ** 2))
    maxWidth = max(int(widthA), int(widthB))
    heightA = np.sqrt(((tr[0] - br[0]) ** 2) + ((tr[1] - br[1]) ** 2))
    heightB = np.sqrt(((tl[0] - bl[0]) ** 2) + ((tl[1] - bl[1]) ** 2))
    maxHeight = max(int(heightA), int(heightB))
    dst = np.array([
        [0, 0],
        [maxWidth - 1, 0],
        [maxWidth - 1, maxHeight - 1],
        [0, maxHeight - 1]], dtype = "float32")
    M = cv2.getPerspectiveTransform(rect, dst)
    warped = cv2.warpPerspective(image, M, (maxWidth, maxHeight))
    return warped

def load_model(weights, device):   #加载检测模型
    model = attempt_load(weights, map_location=device)  # load FP32 model
    return model

def scale_coords_landmarks(img1_shape, coords, img0_shape, ratio_pad=None):  #返回到原图坐标
    # Rescale coords (xyxy) from img1_shape to img0_shape
    if ratio_pad is None:  # calculate from img0_shape
        gain = min(img1_shape[0] / img0_shape[0], img1_shape[1] / img0_shape[1])  # gain  = old / new
        pad = (img1_shape[1] - img0_shape[1] * gain) / 2, (img1_shape[0] - img0_shape[0] * gain) / 2  # wh padding
    else:
        gain = ratio_pad[0][0]
        pad = ratio_pad[1]

    coords[:, [0, 2, 4, 6]] -= pad[0]  # x padding
    coords[:, [1, 3, 5, 7]] -= pad[1]  # y padding
    coords[:, :8] /= gain
    #clip_coords(coords, img0_shape)
    coords[:, 0].clamp_(0, img0_shape[1])  # x1
    coords[:, 1].clamp_(0, img0_shape[0])  # y1
    coords[:, 2].clamp_(0, img0_shape[1])  # x2
    coords[:, 3].clamp_(0, img0_shape[0])  # y2
    coords[:, 4].clamp_(0, img0_shape[1])  # x3
    coords[:, 5].clamp_(0, img0_shape[0])  # y3
    coords[:, 6].clamp_(0, img0_shape[1])  # x4
    coords[:, 7].clamp_(0, img0_shape[0])  # y4
    # coords[:, 8].clamp_(0, img0_shape[1])  # x5
    # coords[:, 9].clamp_(0, img0_shape[0])  # y5
    return coords


def get_plate_rec_landmark(img, xyxy, conf, landmarks, class_num,device,plate_rec_model,is_color=False):  #获取车牌坐标以及四个角点坐标并获取车牌号
    h,w,c = img.shape
    result_dict={}
    tl = 1 or round(0.002 * (h + w) / 2) + 1  # line/font thickness

    x1 = int(xyxy[0])
    y1 = int(xyxy[1])
    x2 = int(xyxy[2])
    y2 = int(xyxy[3])
    height=y2-y1
    landmarks_np=np.zeros((4,2))
    rect=[x1,y1,x2,y2]
    for i in range(4):
        point_x = int(landmarks[2 * i])
        point_y = int(landmarks[2 * i + 1])
        landmarks_np[i]=np.array([point_x,point_y])

    class_label= int(class_num)  #车牌的的类型0代表单牌,1代表双层车牌
    roi_img = four_point_transform(img,landmarks_np)   #透视变换得到车牌小图
    if class_label:        #判断是否是双层车牌,是双牌的话进行分割后然后拼接
        roi_img=get_split_merge(roi_img)
    if not is_color:
        plate_number,rec_prob = get_plate_result(roi_img,device,plate_rec_model,is_color=is_color)                 #对车牌小图进行识别
    else:
        plate_number,rec_prob,plate_color,color_conf=get_plate_result(roi_img,device,plate_rec_model,is_color=is_color) 
    # cv2.imwrite("roi.jpg",roi_img)
    result_dict['rect']=rect                      #车牌roi区域
    result_dict['detect_conf']=conf              #检测区域得分
    result_dict['landmarks']=landmarks_np.tolist() #车牌角点坐标
    result_dict['plate_no']=plate_number   #车牌号
    result_dict['rec_conf']=rec_prob   #每个字符的概率
    result_dict['roi_height']=roi_img.shape[0]  #车牌高度
    result_dict['plate_color']=""
    if is_color:
        result_dict['plate_color']=plate_color   #车牌颜色
        result_dict['color_conf']=color_conf    #颜色得分
    result_dict['plate_type']=class_label   #单双层 0单层 1双层
    
    return result_dict



def detect_Recognition_plate(model, orgimg, device,plate_rec_model,img_size,is_color=False):#获取车牌信息
    # Load model
    # img_size = opt_img_size
    conf_thres = 0.3      #得分阈值
    iou_thres = 0.5       #nms的iou值   
    dict_list=[]
    # orgimg = cv2.imread(image_path)  # BGR
    img0 = copy.deepcopy(orgimg)
    assert orgimg is not None, 'Image Not Found ' 
    h0, w0 = orgimg.shape[:2]  # orig hw
    r = img_size / max(h0, w0)  # resize image to img_size
    if r != 1:  # always resize down, only resize up if training with augmentation
        interp = cv2.INTER_AREA if r < 1  else cv2.INTER_LINEAR
        img0 = cv2.resize(img0, (int(w0 * r), int(h0 * r)), interpolation=interp)

    imgsz = check_img_size(img_size, s=model.stride.max())  # check img_size  

    img = letterbox(img0, new_shape=imgsz)[0]           #检测前处理,图片长宽变为32倍数,比如变为640X640
    # img =process_data(img0)
    # Convert
    img = img[:, :, ::-1].transpose(2, 0, 1).copy()  # BGR to RGB, to 3x416x416  图片的BGR排列转为RGB,然后将图片的H,W,C排列变为C,H,W排列

    # Run inference
    t0 = time.time()

    img = torch.from_numpy(img).to(device)
    img = 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 = time_synchronized()/
    pred = model(img)[0]
    # t2=time_synchronized()
    # print(f"infer time is {(t2-t1)*1000} ms")

    # Apply NMS
    pred = non_max_suppression_face(pred, conf_thres, iou_thres)

    # print('img.shape: ', img.shape)
    # print('orgimg.shape: ', orgimg.shape)

    # Process detections
    for i, det in enumerate(pred):  # detections per image
        if len(det):
            # Rescale boxes from img_size to im0 size
            det[:, :4] = scale_coords(img.shape[2:], det[:, :4], orgimg.shape).round()

            # Print results
            for c in det[:, -1].unique():
                n = (det[:, -1] == c).sum()  # detections per class

            det[:, 5:13] = scale_coords_landmarks(img.shape[2:], det[:, 5:13], orgimg.shape).round()

            for j in range(det.size()[0]):
                xyxy = det[j, :4].view(-1).tolist()
                conf = det[j, 4].cpu().numpy()
                landmarks = det[j, 5:13].view(-1).tolist()
                class_num = det[j, 13].cpu().numpy()
                result_dict = get_plate_rec_landmark(orgimg, xyxy, conf, landmarks, class_num,device,plate_rec_model,is_color=is_color)
                dict_list.append(result_dict)
    return dict_list
    # cv2.imwrite('result.jpg', orgimg)

def draw_result(orgimg,dict_list,is_color=False):   # 车牌结果画出来
    result_str =""
    for result in dict_list:
        rect_area = result['rect']
        
        x,y,w,h = rect_area[0],rect_area[1],rect_area[2]-rect_area[0],rect_area[3]-rect_area[1]
        padding_w = 0.05*w
        padding_h = 0.11*h
        rect_area[0]=max(0,int(x-padding_w))
        rect_area[1]=max(0,int(y-padding_h))
        rect_area[2]=min(orgimg.shape[1],int(rect_area[2]+padding_w))
        rect_area[3]=min(orgimg.shape[0],int(rect_area[3]+padding_h))

        height_area = result['roi_height']
        landmarks=result['landmarks']
        result_p = result['plate_no']
        if result['plate_type']==0:#单层
            result_p+=" "+result['plate_color']
        else:                             #双层
            result_p+=" "+result['plate_color']+"双层"
        result_str+=result_p+" "
        for i in range(4):  #关键点
            cv2.circle(orgimg, (int(landmarks[i][0]), int(landmarks[i][1])), 5, clors[i], -1)
        cv2.rectangle(orgimg,(rect_area[0],rect_area[1]),(rect_area[2],rect_area[3]),(0,0,255),2) #画框
        
        labelSize = cv2.getTextSize(result_p,cv2.FONT_HERSHEY_SIMPLEX,0.5,1) #获得字体的大小
        if rect_area[0]+labelSize[0][0]>orgimg.shape[1]:                 #防止显示的文字越界
            rect_area[0]=int(orgimg.shape[1]-labelSize[0][0])
        orgimg=cv2.rectangle(orgimg,(rect_area[0],int(rect_area[1]-round(1.6*labelSize[0][1]))),(int(rect_area[0]+round(1.2*labelSize[0][0])),rect_area[1]+labelSize[1]),(255,255,255),cv2.FILLED)#画文字框,背景白色
        
        if len(result)>=1:
            orgimg=cv2ImgAddText(orgimg,result_p,rect_area[0],int(rect_area[1]-round(1.6*labelSize[0][1])),(0,0,0),21)
            # orgimg=cv2ImgAddText(orgimg,result_p,rect_area[0]-height_area,rect_area[1]-height_area-10,(0,255,0),height_area)
               
    print(result_str)
    return orgimg



def get_second(capture):
    if capture.isOpened():
        rate = capture.get(5)   # 帧速率
        FrameNumber = capture.get(7)  # 视频文件的帧数
        duration = FrameNumber/rate  # 帧速率/视频总帧数 是时间,除以60之后单位是分钟
        return int(rate),int(FrameNumber),int(duration)    


if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--detect_model', nargs='+', type=str, default='weights/plate_detect.pt', help='model.pt path(s)')  #检测模型
    parser.add_argument('--rec_model', type=str, default='weights/plate_rec_color.pth', help='model.pt path(s)')#车牌识别+颜色识别模型
    parser.add_argument('--is_color',type=bool,default=True,help='plate color')      #是否识别颜色
    parser.add_argument('--image_path', type=str, default='imgs', help='source')     #图片路径
    parser.add_argument('--img_size', type=int, default=640, help='inference size (pixels)')  #网络输入图片大小
    parser.add_argument('--output', type=str, default='result', help='source')               #图片结果保存的位置
    parser.add_argument('--video', type=str, default='', help='source')                       #视频的路径
    device = torch.device("cuda" if torch.cuda.is_available() else "cpu")                     #使用gpu还是cpu进行识别
    # device =torch.device("cpu")
    opt = parser.parse_args()
    print(opt)
    save_path = opt.output                
    count=0
    if not os.path.exists(save_path): 
        os.mkdir(save_path)

    detect_model = load_model(opt.detect_model, device)  #初始化检测模型
    plate_rec_model=init_model(device,opt.rec_model,is_color=opt.is_color)      #初始化识别模型
    #算参数量
    total = sum(p.numel() for p in detect_model.parameters())
    total_1 = sum(p.numel() for p in plate_rec_model.parameters())
    print("detect params: %.2fM,rec params: %.2fM" % (total/1e6,total_1/1e6))
    
    # plate_color_model =init_color_model(opt.color_model,device)
    time_all = 0
    time_begin=time.time()
    if not opt.video:     #处理图片
        if not os.path.isfile(opt.image_path):            #目录
            file_list=[]
            allFilePath(opt.image_path,file_list)  #将这个目录下的所有图片文件路径读取到file_list里面
            for img_path in file_list:             #遍历图片文件
                
                print(count,img_path,end=" ")
                time_b = time.time()               #开始时间
                img =cv_imread(img_path)           #opencv 读取图片
                
                if img is None:                   
                    continue
                if img.shape[-1]==4:               #图片如果是4个通道的,将其转为3个通道
                    img=cv2.cvtColor(img,cv2.COLOR_BGRA2BGR)
                # detect_one(model,img_path,device)
                dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color)#检测以及识别车牌
                ori_img=draw_result(img,dict_list)  #将结果画在图上
                img_name = os.path.basename(img_path)  
                save_img_path = os.path.join(save_path,img_name)  #图片保存的路径
                time_e=time.time()
                time_gap = time_e-time_b                         #计算单个图片识别耗时
                if count:
                    time_all+=time_gap 
                cv2.imwrite(save_img_path,ori_img)               #opencv将识别的图片保存
                count+=1
            print(f"sumTime time is {time.time()-time_begin} s, average pic time is {time_all/(len(file_list)-1)}")
        else:                                          #单个图片
                print(count,opt.image_path,end=" ")
                img =cv_imread(opt.image_path)
                if img.shape[-1]==4:
                    img=cv2.cvtColor(img,cv2.COLOR_BGRA2BGR)
                # detect_one(model,img_path,device)
                dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color)
                ori_img=draw_result(img,dict_list)
                img_name = os.path.basename(opt.image_path)
                save_img_path = os.path.join(save_path,img_name)
                cv2.imwrite(save_img_path,ori_img)  
        
        
    else:    #处理视频
        video_name = opt.video
        capture=cv2.VideoCapture(video_name)
        fourcc = cv2.VideoWriter_fourcc(*'MP4V') 
        fps = capture.get(cv2.CAP_PROP_FPS)  # 帧数
        width, height = int(capture.get(cv2.CAP_PROP_FRAME_WIDTH)), int(capture.get(cv2.CAP_PROP_FRAME_HEIGHT))  # 宽高
        out = cv2.VideoWriter('result.mp4', fourcc, fps, (width, height))  # 写入视频
        frame_count = 0
        fps_all=0
        rate,FrameNumber,duration=get_second(capture)
        if capture.isOpened():
            while True:
                t1 = cv2.getTickCount()
                frame_count+=1
                print(f"第{frame_count} 帧",end=" ")
                ret,img=capture.read()
                if not ret:
                    break
                # if frame_count%rate==0:
                img0 = copy.deepcopy(img)
                dict_list=detect_Recognition_plate(detect_model, img, device,plate_rec_model,opt.img_size,is_color=opt.is_color)
                ori_img=draw_result(img,dict_list)
                t2 =cv2.getTickCount()
                infer_time =(t2-t1)/cv2.getTickFrequency()
                fps=1.0/infer_time
                fps_all+=fps
                str_fps = f'fps:{fps:.4f}'
                
                cv2.putText(ori_img,str_fps,(20,20),cv2.FONT_HERSHEY_SIMPLEX,1,(0,255,0),2)
                # cv2.imshow("haha",ori_img)
                # cv2.waitKey(1)
                out.write(ori_img)

                # current_time = int(frame_count/FrameNumber*duration)
                # sec = current_time%60
                # minute = current_time//60
                # for result_ in result_list:
                #     plate_no = result_['plate_no']
                #     if not is_car_number(pattern_str,plate_no):
                #         continue
                #     print(f'车牌号:{plate_no},时间:{minute}分{sec}秒')
                #     time_str =f'{minute}分{sec}秒'
                #     writer.writerow({"车牌":plate_no,"时间":time_str})
                # out.write(ori_img)
                
                
        else:
            print("失败")
        capture.release()
        out.release()
        cv2.destroyAllWindows()
        print(f"all frame is {frame_count},average fps is {fps_all/frame_count} fps")

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154
  • 155
  • 156
  • 157
  • 158
  • 159
  • 160
  • 161
  • 162
  • 163
  • 164
  • 165
  • 166
  • 167
  • 168
  • 169
  • 170
  • 171
  • 172
  • 173
  • 174
  • 175
  • 176
  • 177
  • 178
  • 179
  • 180
  • 181
  • 182
  • 183
  • 184
  • 185
  • 186
  • 187
  • 188
  • 189
  • 190
  • 191
  • 192
  • 193
  • 194
  • 195
  • 196
  • 197
  • 198
  • 199
  • 200
  • 201
  • 202
  • 203
  • 204
  • 205
  • 206
  • 207
  • 208
  • 209
  • 210
  • 211
  • 212
  • 213
  • 214
  • 215
  • 216
  • 217
  • 218
  • 219
  • 220
  • 221
  • 222
  • 223
  • 224
  • 225
  • 226
  • 227
  • 228
  • 229
  • 230
  • 231
  • 232
  • 233
  • 234
  • 235
  • 236
  • 237
  • 238
  • 239
  • 240
  • 241
  • 242
  • 243
  • 244
  • 245
  • 246
  • 247
  • 248
  • 249
  • 250
  • 251
  • 252
  • 253
  • 254
  • 255
  • 256
  • 257
  • 258
  • 259
  • 260
  • 261
  • 262
  • 263
  • 264
  • 265
  • 266
  • 267
  • 268
  • 269
  • 270
  • 271
  • 272
  • 273
  • 274
  • 275
  • 276
  • 277
  • 278
  • 279
  • 280
  • 281
  • 282
  • 283
  • 284
  • 285
  • 286
  • 287
  • 288
  • 289
  • 290
  • 291
  • 292
  • 293
  • 294
  • 295
  • 296
  • 297
  • 298
  • 299
  • 300
  • 301
  • 302
  • 303
  • 304
  • 305
  • 306
  • 307
  • 308
  • 309
  • 310
  • 311
  • 312
  • 313
  • 314
  • 315
  • 316
  • 317
  • 318
  • 319
  • 320
  • 321
  • 322
  • 323
  • 324
  • 325
  • 326
  • 327
  • 328
  • 329
  • 330
  • 331
  • 332
  • 333
  • 334
  • 335
  • 336
  • 337
  • 338
  • 339
  • 340
  • 341
  • 342
  • 343
  • 344
  • 345
  • 346
  • 347
  • 348
  • 349
  • 350
  • 351
  • 352
  • 353
  • 354
  • 355
  • 356
  • 357
  • 358

3.4 关键点分析

  1. 初始化参数
  • 从输入图像img获取其高度h、宽度w和通道数c。
  • 初始化一个空字典 result_dict 用于存储结果。
  • 计算线条/字体粗细tl,这里基于图像尺寸动态计算。
  1. 解析车牌位置和角点坐标
  • 从xyxy(车牌边界框的坐标,格式为[x1, y1, x2, y2])中提取车牌的左上角和右下角坐标。
  • 初始化一个 NumPy 数组 landmarks_np 用于存储车牌的四个角点坐标。
  • 遍历 landmarks(车牌角点坐标列表),将每个角点坐标(x, y)存入 landmarks_np
  1. 获取车牌类型
  • class_num 获取车牌类型(0代表单牌,1代表双层车牌)。
  1. 透视变换获取车牌小图
  • 使用 four_point_transform 函数(需要预先定义或导入)对车牌区域进行透视变换,得到车牌的正面视图 roi_img
  1. 处理双层车牌
  • 如果车牌类型为双层( class_label 为1),则调用 get_split_merge 函数(需要预先定义或导入)对车牌小图进行分割和合并处理。
  1. 车牌识别
  • 根据 is_color 参数决定是否需要识别车牌颜色。
  • 调用 get_plate_result 函数(需要预先定义或导入)对车牌小图roi_img进行识别,获取车牌号 plate_number 、识别概率 rec_prob ,以及(如果 is_colorTrue )车牌颜色 plate_color 和颜色置信度 color_conf
  1. 构建结果字典
  • 将车牌的边界框rect、检测置信度conf、角点坐标landmarks、车牌号 plate_number 、识别概率 rec_prob 、车牌高度 roi_img.shape[0]、车牌颜色(如果 is_color 为True)以及车牌类型 class_label 等信息存入result_dict。
  1. 返回结果
  • 返回包含车牌识别结果的字典 result_dict

3.5 车牌检测模型训练

  1. 下载一定量的数据集

需要下载一定量的数据集,项目的作者有提供,需要的可以联系项目作者,格式为 yolov5 格式

label x y w h  pt1x pt1y pt2x pt2y pt3x pt3y pt4x pt4y
  • 1

自己的数据集可以通过lablme 软件,create polygons标注车牌四个点即可,然后通过json2yolo.py 将数据集转为yolo格式,也可进行训练

  1. 修改 data/widerface.yaml trainval 路径,换成你的数据路径
train: /your/train/path #修改成你的训练集路径
val: /your/val/path     #修改成你的验证集路径
# number of classes
nc: 2                 #这里用的是2分类,0 单层车牌 1 双层车牌

# class names
names: [ 'single','double']
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. 训练命令
python3 train.py --data data/widerface.yaml --cfg models/yolov5n-0.5.yaml --weights weights/plate_detect.pt --epoch 120
  • 1

3.6 车牌识别模型训练

  1. 下载数据集
    数据集可以自己收集,或者找项目作者提供

  2. 数据集打上标签,生成train.txt和val.txt
    在这里插入图片描述

图片命名如上图:车牌号_序号.jpg 然后执行如下命令,得到 train.txtval.txt

python plateLabel.py --image_path your/train/img/path/ --label_file datasets/train.txt
python plateLabel.py --image_path your/val/img/path/ --label_file datasets/val.txt
  • 1
  • 2

数据格式如下:

train.txt

/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BAJ731_3.jpg 5 53 52 60 49 45 43 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BD387U_2454.jpg 5 53 55 45 50 49 70 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_ALL/冀BG150C_3.jpg 5 53 58 43 47 42 54 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖A656V3_8090.jpg 13 52 48 47 48 71 45 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖C91546_7979.jpg 13 54 51 43 47 46 48 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖G88950_1540.jpg 13 58 50 50 51 47 42 
/mnt/Gu/trainData/plate/new_git_train/CCPD_CRPD_OTHER_ALL/皖GX9Y56_2113.jpg 13 58 73 51 74 47 48 
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  1. train.txt val.txt 路径写入 lib/config/360CC_config.yaml
DATASET:
  DATASET: 360CC
  ROOT: ""
  CHAR_FILE: 'lib/dataset/txt/plate2.txt'
  JSON_FILE: {'train': 'datasets/train.txt', 'val': 'datasets/val.txt'}
  • 1
  • 2
  • 3
  • 4
  • 5
  1. 执行训练命令
python train.py --cfg lib/config/360CC_config.yaml
  • 1

3.7 图片识别测试

  1. 项目基础图片集
    在这里插入图片描述
    项目中已经预先存放了一些车牌图片,我们可以使用这些图片来测试一下

  2. 执行图片检测命令

python detect_plate.py --detect_model weights/plate_detect.pt  --rec_model weights/plate_rec_color.pth --image_path imgs --output result
  • 1

输入完命令后,大约在3秒后,程序持续输出识别结果,可以看到程序的启动速度还是挺快了,总共的识别时间在8.5秒左右,平均一张图片的识别速度在0.5秒左右,这速度已经是相当的快了

在这里插入图片描述

  1. 图片识别结果

在这里插入图片描述

3.8 视频识别测试

  1. 项目基础识别视频
    视频:

yolov2车牌识别视频

视频截图:
在这里插入图片描述
视频时间长度在 54 秒左右,视频类型为 mp4,视频内容主要是以行驶中的车尾视角拍摄马路上的车辆。

  1. 上传视频到项目文件中
    我连接软件用的 MobaXterm,不知道为什么,上传文件总是会卡住,没办法,只能用 Xftp 再连接一次然后上传视频了
    在这里插入图片描述

  2. 执行视频检测命令

python detect_plate.py --detect_model weights/plate_detect.pt  --rec_model weights/plate_rec_color.pth --video 2.mp4
  • 1

输入执行命令后,系统大约在 5 秒后启动了,然后将视频分帧处理
在这里插入图片描述
处理过程中ing
在这里插入图片描述
视频的后半部分就已经没有车了,处理显示的也都是空帧,就没有任何意义了,这里就不进行展示了。
在这里插入图片描述
可以看到,54 秒的视频,共划分了 1501 帧,香橙派 Orange pi AIpro 这块板子,处理速度在 2.7 fps 左右,相对比其他开发板子来说,速度已经可以了。

四. 踩坑问题

  1. 烧录报错
    在这里插入图片描述
    错误提示

出了点问题。如果源镜像曾被压缩过,请检查它是否已损坏。
The writer process ended unexpectedly

直接点击跳过即可
在这里插入图片描述

  1. ping 命令不能使用
    在这里插入图片描述
    解决办法:
sudo setcap cap_net_raw+p /bin/ping
  • 1

在这里插入图片描述
成功解决
在这里插入图片描述

五. 使用体验与总结

使用下来体验感还挺好的,板子在通电启动后,5秒内散热风扇的噪音还是比较大的,5秒后,声音就变的很小了,后续即使在跑项目的时候,声音也没有较大的变化,散热做的也非常的好,整体体验下来板子的温度一直维持在一个正常的温度,没有出现温度过高的情况。

除了个人体验外,OrangePi AIpro 凭借其卓越的即插即用特性,极大地加速了开发进程。通过简单的配置步骤,省去了繁琐的硬件调试环节。在软件生态方面,香橙派社区构建了一个资源丰富、文档详尽的生态系统,对初学者来说可以轻松访问并选用适合的文字识别模型和框架,通过直观易懂的指南,快速部署至开发板上。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/爱喝兽奶帝天荒/article/detail/1012582
推荐阅读
相关标签
  

闽ICP备14008679号