香橙派OrangePi AI Pro测评部署车牌号识别项目

一、前言

随着智能交通系统的不断发展,车牌号识别技术在交通管理和车辆监控中发挥着越来越重要的作用。香橙派 AIpro 开发板作为一款高性能嵌入式 AI平台 ,以其强大的计算能力和丰富的接口,成为了车牌号识别项目的理想选择。在本篇测评中,我们将详细介绍如何使用香橙派 AIpro 开发板 进行 车牌号识别,并探讨其在实际应用中的表现。

香橙派 AIpro 开发板 搭载了 高效的处理器AI加速单元 ,能够 快速处理图像数据识别车牌号信息。其紧凑设计和低功耗特性使其非常适合部署在实际 交通监控系统 中。通过这次测评,我们希望展示 香橙派 AIpro 开发板 在车牌号识别任务中的潜力,并为开发者提供实用的参考和指导。

在接下来的部分,我们将从 硬件配置软件环境搭建模型训练优化 等方面进行详细介绍,并通过实际案例展示 香橙派 AIpro 开发板在车牌号识别项目中的性能表现和优势。希望通过本次测评,能够帮助读者更好地了解并利用 香橙派 AIpro 开发板 ,推动智能交通系统的发展和应用。

二、香橙派 AIpro 开发板

2.1 开发板简介

香橙派 AIpro 开发板是一款高性能的嵌入式人工智能开发平台,专为边缘计算和物联网 (IoT) 应用设计。它具有 强大的处理能力 和丰富的 扩展接口,能够满足各种 AI计算任务 的需求。

2.2 开发板硬件规格

在这里插入图片描述

在这里插入图片描述

2.3 开发板的接口详情图

在这里插入图片描述

在这里插入图片描述

2.4 开箱实物

  • 操作系统界面
    在这里插入图片描述
    这个界面还是挺简洁的。

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

  • 反面
    在这里插入图片描述

  • 外观设计

香橙派 AIpro 开发板采用紧凑而美观的设计,其巧妙布局的元器件和接口不仅实用,更让人赏心悦目。开发板表面的元器件排列整齐,布局合理,接口的位置设计合理,方便用户连接各种外设设备,同时保持整洁有序的外观。

  • 精细做工

开发板的做工非常精细,每一个接口和元器件的安装都非常牢固,避免了使用过程中可能出现的松动或接触不良问题。整体做工不仅提升了产品的耐用性,也为用户带来了极佳的使用体验。

  • 板载散热系统

香橙派 AIpro 开发板还配备了高效的散热系统,包括铝合金散热片和风扇,既美观又实用。散热片表面光滑,金属质感十足,与整板的黑色主色调相得益彰,不仅有效散热,更为开发板增添了一份科技感和时尚感。

香橙派 AIpro 开发板在颜值和做工上无可挑剔

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

3.1 开源地址

基于Yolov5的车牌识别系统GitHub地址

3.2 项目介绍

此项目是一个基于深度学习的 车牌号检测和识别系统 ,旨在提供一个高效、准确的解决方案,用于识别 中国车牌号 。该项目利用先进的卷积神经网络 (CNN) 技术,实现了从图像中 自动检测识别车牌号 的功能,是智能交通系统中的重要组成部分。支持``12种中文车牌支持双层车牌` 的目标识别系统。

支持如下:

  • 1.单行蓝牌
  • 2.单行黄牌
  • 3.新能源车牌
  • 4.白色警用车牌
  • 5.教练车牌
  • 6.武警车牌
  • 7.双层黄牌
  • 8.双层白牌
  • 9.使馆车牌
  • 10.港澳粤Z牌
  • 11.双层绿牌
  • 12.民航车牌

3.3 拉取项目并部署

  • 设置 Git 使用 GnuTLS

    git config --global http.sslBackend gnutls
    
  • 检查配置

    git config --global --get http.sslBackend
    

    这个命令应该返回 gnutls

  • 克隆仓库

    git clone https://github.com/we0091234/Chinese_license_plate_detection_recognition.git
    

    在这里插入图片描述

  • 进入项目文件

    cd Chinese_license_plate_detection_recognition/
    
  • 下载解决依赖文件

    由于项目所需要依赖过多,下载时间会稍微有一点长

    pip install -r ./requirements.txt -i https://mirrors.aliyun.com/pypi/simple
    

    在这里插入图片描述

  • 项目文件目录

    在这里插入图片描述

3.4 图片识别

  • 验证集

    在这里插入图片描述

  • 运行

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

    测试文件夹 imgs ,结果保存再 result 文件夹

  • 运行结果

    • 命令行

      在这里插入图片描述

    • 实际结果

      在这里插入图片描述

3.5 视频识别

  • 验证视频

车牌号识别项目demo视频

  • 运行

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

    视频文件为 2.mp4. 保存为 result.mp4

  • 运行结果

    • 命令行

      在这里插入图片描述

    • 实际效果

车牌号识别项目demo输出视频

3.6 模型训练

在使用过程中,肯定是要自己配置 训练的AI大模型.当我们需要训练自己的模型时只需要更改data/widerface.yaml 文件中的train与val路径即可。

train: /mnt/Gpan/Mydata/pytorchPorject/yolov5-face/ccpd/train_detect 
val: /mnt/Gpan/Mydata/pytorchPorject/yolov5-face/ccpd/val_detect

说明:

train: /your/train/path: #修改成你的训练集路径

val: /your/val/path: #修改成你的验证集路径

更改完成后可直接使用命令开始训练

python3 train.py --data data/widerface.yaml --cfg models/yolov5n-0.5.yaml --weights weights/plate_detect.pt --epoch 120
  1. python3 train.py
    • 运行 Python 脚本 train.py,这是 YOLOv5 的训练脚本。
  2. --data data/widerface.yaml
    • 指定数据集的配置文件。data/widerface.yaml 是一个YAML 文件,包含训练数据和验证数据的路径、类别信息等。
  3. --cfg models/yolov5n-0.5.yaml
    • 指定模型配置文件。models/yolov5n-0.5.yaml 是一个 YAML 文件,定义了 YOLOv5 模型的结构和参数。
  4. --weights weights/plate_detect.pt
    • 指定预训练权重文件。weights/plate_detect.pt 是一个权重文件,通常是一个预训练的模型,用于加速训练过程或提高模型性能。
  5. --epoch 120
    • 指定训练的轮数。120 表示训练将进行 120 个 epoch(轮次)。

3.7 代码

# -*- 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")

3.8 关键的分析

库和依赖项

  • 使用了 cv2(OpenCV)进行图像处理。
  • 使用 torch 进行深度学习模型的加载和推理。
  • 包含自定义的工具和模块,如 models.experimental, utils.datasets, utils.general 等。

功能模块

  • 车牌检测:通过 attempt_load 函数加载预训练模型,然后使用 non_max_suppression_face 进行非最大值抑制以过滤检测结果。
  • 车牌识别:通过 get_plate_result 函数对检测到的车牌区域进行字符识别。
  • 图像处理:包括透视变换(four_point_transform 函数)和文字绘制(cv2ImgAddText 函数)。

数据处理

  • 使用 letterbox 函数调整图像大小以适应模型输入。
  • 使用 scale_coords 函数将检测结果映射回原始图像尺寸。

3.9 笔者的一些想法

  • 批处理处理

    • 原代码:

      没有批处理逻辑,一次只能处理一张图像。

      def process_image(image_path, model, recognizer, device):
          image = cv_imread(image_path)
          plates = detect_plate(image, model, device)
          results = []
          for plate in plates:
              plate_image = extract_plate_image(image, plate)
              result = recognize_plate(plate_image, recognizer)
              results.append(result)
          return results
      
    • 改成:

      添加了批处理逻辑,提升了处理效率。

      def batch_process_images(image_paths, model, recognizer, device, batch_size=8):
          results = []
          for i in range(0, len(image_paths), batch_size):
              batch_paths = image_paths[i:i + batch_size]
              batch_images = [cv2.imread(str(path)) for path in batch_paths]
              
              batch_detections = [detect_plate(img, model, device) for img in batch_images]
              for img, detections in zip(batch_images, batch_detections):
                  for bbox in detections:
                      plate_image = extract_plate_image(img, bbox[0])
                      result = recognize_plate(plate_image, recognizer)
                      results.append(result)
          return results
      

    效率提升:优化后的代码使用批处理方法,一次处理多张图像,减少了重复调用函数的开销,提高了整体处理速度。

    代码简洁:通过批处理,减少了重复代码,使逻辑更加简洁明了。

  • 配置管理

    • 原代码

      所有参数都在代码中硬编码,缺乏灵活性。

      if __name__ == "__main__":
          parser = argparse.ArgumentParser()
          parser.add_argument('--image_folder', type=str, required=True, help='Path to the folder containing images')
          parser.add_argument('--weights', type=str, default='weights/best.pt', help='Path to weights file')
          parser.add_argument('--recognizer_weights', type=str, default='weights/recognizer.pth', help='Path to recognizer weights')
          parser.add_argument('--device', default='', help='Device to run on (e.g. 0 or 0,1,2,3 or cpu)')
          args = parser.parse_args()
      
    • 改成

      def load_config(config_path):
          with open(config_path, 'r') as file:
              config = yaml.safe_load(file)
          return config
      
      if __name__ == "__main__":
          parser = argparse.ArgumentParser()
          parser.add_argument('--config_path', type=str, default='config.yaml', help='Path to the config file')
          args = parser.parse_args()
      
          config = load_config(args.config_path)
          device = select_device(config['device'])
          model = attempt_load(config['weights'], map_location=device)
          recognizer = init_model(config['recognizer_weights'])
      
      

    灵活性:优化后的代码通过配置文件管理参数,便于修改和扩展,适应不同的应用场景。

    可维护性:参数集中管理,使代码更加整洁,便于维护和升级。

四、使用香橙派 AIpro 开发板遇到的问题和总结

4.1 遇到的问题

在使用串口调试香橙派 AIpro 开发板时,遇到了输入命令时出现 文字乱跳、乱码 的问题。这导致第一次开机时无法顺利配置网络,从而不能使用 ssh。具体问题如下:

  1. 使用 openEuler 系统时
    • 串口输入直接卡死,无法输入命令。
    • 即使重新复位也无效,只有断电重新开机才能恢复。
  2. 更换 Ubuntu 系统后
    • 串口输入虽然没有再卡死,但文字乱跳的问题依然存在,影响正常输入。

这种现象严重影响了系统的初始配置和使用体验,需要寻找解决方案来确保串口调试的稳定性和可靠性。

在这里插入图片描述

4.2 运行车牌号识别项目的感受

香橙派 AIpro 开发板在开机时风扇声音较大,但启动后声音会立即减小。在运行模型期间,风扇声音保持稳定,没有 明显变化。我已经连续工作了 十几个小时 ,期间风扇的声音一直很小。同时,散热器的温度不高表明该产品本身的散热性能相当出色

4.3 总结

香橙派 AIpro 开发板有着其 强大的性能丰富的接口 ,开发者进行 AI物联网项目 的时候是一个很好的选择。虽然在初始配置和兼容性方面存在一些挑战,但通过适当的调整和配置,这些问题都可以得到解决。并不会影响正常使用。

总体而言,香橙派 AIpro 开发板为边缘计算和智能应用提供了一个高效灵活 的平台,具有广泛的应用前景和发展潜力,作为一款国产化开发板,它在 本地支持适应本土需求具有独特优势,与树莓派相比,香橙派 AIpro 在 性能扩展性上 还有 价格上更具优势,特别适合 高级开发者专业项目

值得一提的是,香橙派 AIpro 的颜值和做工优于市面上许多其他产品,使其在外观和质量上也具备很强的竞争力

  • 27
    点赞
  • 22
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

^Lim

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

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

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

打赏作者

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

抵扣说明:

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

余额充值