基于香橙派AIpro搭建的车牌识别系统

news2024/10/6 10:30:06

引言

本人正有学习嵌入式的想法,正好碰到机会让我搞了块OrangePi AIpro(香橙派AIpro)开发板,正合我意,直接上手进行体验,顺便给大家分享下我的实践过程。

开发板介绍与初次启动

OrangePiAIPro开发板是香橙派联合华为精心打造的高性能AI开发板,其搭载了异腾AI处理器,可提供8TOPS INT8的计算能力,内存提供了8GB和16GB两种版本。可以实现图像、视频等多种数据分析与推理计算,可广泛用于教育、机器人、无人机等场景。

微信图片_20240704225225.jpg
(这张是我自己拍的实体图)

资源介绍

开发板具有丰富的外设资源,详细情况如下表所示:

异腾AI处理器4核64位Arm处理器+AI处理器
AI算力半精度(FP16): 4TFL0PS
整数精度(INT8) :8 T0PS
内存类型: LPDDR4X
容量: 8GB或16GB
储存板载32MB的SPI Flash
Micro SD卡插槽
eMMC 插座:可外接eMMC模块
M.2 M-Key接口:可接2280规格的NVMe SSD 或SATA SSD
以太网支持10/100/ 1000Mbps
板载PHY芯片: RTL8211F
WiFi+蓝牙支持2.4G和5G双频WIFI
BT4.2
模组:欧智通6221BUUC
USB接口2个USB3.0 Host接口
1个Type-C接口(注:只支持USB3.0,不支持USB2.0)
摄像头2个MIPICSI2Lane接口
显示接口2个HDMI接口
1个MIPIDSI2Lane接口
音频接口1个3.5mm耳机孔,支持音频输入输出
2个HDMI音频输出
40 pin扩展口用于扩展UART、I2C、 SPI、 PWM和GPI0等接口
其他硬件接口4pin 风扇接口,用于接12V风扇,支持PWM调节
2pin 电池接口,用于接3串电池,支持快充
Micro USB串口调试接口
1个MIPIDSI2Lane接口

开发板资源位置说明如下图
image.png

注:关机键只能用于强制关机,但是不能用于开机;而RESET键既可以用于开机也可以用于开发板重启。

image.png

镜像介绍与烧入

开发板支持的操作系统有:ubuntu 22.04与openEuler 22.03,👉点击即可下载镜像。

开发板支持多种镜像烧入方式:烧写Linux镜像到TF卡中、烧写 Linux 镜像到NVMe SSD中、烧写 Linux 镜像到 eMMC 中三中方式,由于在一般情况下使用方法一更多,因此在本文中就只介绍使用方法一烧写Linux镜像到TF卡中:

  1. 准备一张 32GB 或更大容量的 TF 卡(推荐使用 64GB 或以上容量的 TF 卡),并准备一个读卡器。
  2. 从官网Orange Pi - Orangepi下载 Linux 镜像与烧入软件balenaEtcher压缩包。
  3. 烧录镜像:将TF卡插入读卡器并连接到电脑。打开balenaEtcher,选择下载的Linux镜像文件和TF卡,然后点击"Flash"开始烧录。
  4. 烧录完成后,将TF卡插入香橙派Alpro的TF卡槽即可。

这些东西我就不详细介绍了,不懂的朋友可以参考下这篇:https://www.hiascend.com/forum/thread-0260140249549075069-1-1.html

串口调试

开发板默认使用uart0做为调试串口,但是需要注意的是,uart0的tx和rx引脚同时接到了两个地方,因此有两种使用调试串口的方法:

1.借助USB转TTL模块完成串口数据传输

uart0的tx和rx引脚接到了40 pin扩展接口中的8号和10号引脚,此种方式需要准备一个3.3v的USB转TTL模块和相应的杜邦线,然后才能正常使用开发板的调试串口功能。开发板上预留的串口接口如下图所示:image.png
2.借助Micro USB接口的数据线完成串口数据传输

uart0的tx和rx引脚又接到了开发板的CH343P芯片上,再通过CH343P芯片引出到MicroUSB接口.上。此种方式只需要一根MicroUSB接口的数据线将开发板连接到电脑的USB接口就可以开始使用开发板的调试串口功能了,无需购买USB转TTL模块。这种方法是推荐的方法。

启动开发板

  1. 将烧录好镜像的TF卡或者eMMC模块或者SSD插入开发板对应的插槽中。
  2. 连接电源,板子会自己启动。

开发板正常启动后:

微信图片_20240704225230.jpg

连接开发板

首先得让开发连上网络,咱给他插上网线,然后到路由器的管理系统里去找到那个插网线的设备ip地址。
image.png
接下来我们就可以通过这个ip来连接设备了,我使用的是finalShell,个人比较习惯一点。

默认账号是 HwHiAiUser,密码默认是 Mind@123,然后就可以连上开发板了。
image.png

登录成功:

image.png

接下来我们弄个项目来体验下这块 OrangePi AIpro 开发板。

车牌识别系统

基于Opencv的车牌识别系统

这个程序是参考博客【OpenCV实战】简洁易懂的车牌号识别Python+OpenCV实现“超详解”(含代码),然后手动创建的项目代码。
首先给出我们要识别的目标原图(注:图片来源于网上)

image.png
车牌定位是车牌识别过程中的关键步骤,它旨在从图像中准确地找到车牌的位置,定位结果通常以车牌区域的最小外接矩形形式给出,该矩形精确地标记了车牌在图像中的位置。以下是一些关键的步骤和方法:

  1. 颜色空间转换
    • HSV颜色空间:由于车牌颜色(如蓝色、黄色等)在HSV颜色空间中具有较高的饱和度,因此可以将图像从RGB颜色空间转换到HSV颜色空间,然后基于颜色阈值来检测车牌区域。
    • 阈值处理:根据车牌颜色的HSV值范围设置阈值,将图像二值化,突出车牌区域。
  2. 形态学操作
    • 腐蚀与膨胀:使用形态学操作中的腐蚀和膨胀操作来去除噪声和填补车牌区域中的小洞。
    • 开运算与闭运算:结合腐蚀和膨胀操作,形成开运算和闭运算,进一步清理车牌区域边界。
  3. 轮廓检测
    • findContours函数:使用OpenCV中的findContours函数检测图像中的轮廓。
    • 轮廓筛选:根据轮廓的面积、长宽比、形状等特征筛选出车牌轮廓。
  4. 车牌区域提取
    • 最小外接矩形:对于筛选出的车牌轮廓,使用最小外接矩形来标记车牌区域。
    • 裁剪:从原图中裁剪出车牌区域,用于后续的字符分割和识别。

代码实现如下:

# 读取图像  
origin_image = cv2.imread('car.jpg')
if origin_image is None:
    print("Error: Image not found.")
    return

    # 图像预处理
    gray_image = preprocess_image(origin_image)
# 边缘检测  
sobel_x = cv2.Sobel(gray_image, cv2.CV_16S, 1, 0)
abs_sobel_x = cv2.convertScaleAbs(sobel_x)
# 阈值化  
_, binary_image = cv2.threshold(abs_sobel_x, 0, 255, cv2.THRESH_OTSU)

# 形态学操作  
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (30, 10))
binary_image = cv2.morphologyEx(binary_image, cv2.MORPH_CLOSE, kernel, iterations=1)
# 腐蚀和膨胀  
kernel_x = cv2.getStructuringElement(cv2.MORPH_RECT, (50, 1))
kernel_y = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 20))
binary_image = cv2.dilate(binary_image, kernel_x)
binary_image = cv2.erode(binary_image, kernel_x)
binary_image = cv2.erode(binary_image, kernel_y)
binary_image = cv2.dilate(binary_image, kernel_y)
binary_image = cv2.medianBlur(binary_image, 21)

# 轮廓检测  
contours, _ = cv2.findContours(binary_image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
for contour in contours:
    rect = cv2.boundingRect(contour)
    x, y, width, height = rect
    if width > height * 3 and width <= height * 4:
        plate_image = origin_image[y:y + height, x:x + width]
        plt_show_color(plate_image)
        break  # 假设只处理一个车牌

输出的过程图片如下:
image.png
字符分割是将车牌区域中的字符逐一分离出来的过程,为后续的字符识别做准备。以下是一些常用的方法:

  1. 投影法
    • 水平投影:对车牌区域进行水平方向的投影,统计每行的像素和,找到字符之间的分隔线。
    • 垂直投影:类似地,也可以进行垂直方向的投影,但通常用于后续字符的微调。
  2. 连通区域分析
    • 标记连通组件:使用连通区域分析算法(如标签连通组件)来标记车牌区域中的每个字符。
    • 分割:根据连通组件的边界分割出每个字符。
  3. 字符归一化
    • 大小调整:将所有分割出的字符调整到统一的大小,以便于后续的字符识别。
    • 位置校正:对字符进行必要的旋转或倾斜校正,以提高识别准确率。

代码实现如下:

# 字符分割和模板匹配  
gray_plate = preprocess_image(plate_image)
_, binary_plate = cv2.threshold(gray_plate, 0, 255, cv2.THRESH_OTSU)
binary_plate = cv2.dilate(binary_plate, cv2.getStructuringElement(cv2.MORPH_RECT, (2, 2)))

contours, _ = cv2.findContours(binary_plate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
words = sorted(contours, key=lambda x: cv2.boundingRect(x)[0])
word_images = []
for contour in words:
    rect = cv2.boundingRect(contour)
    x, y, width, height = rect
    if height > width * 1.5 and height < width * 3.5 and width > 25:
        word_img = binary_plate[y:y + height, x:x + width]
        word_images.append(word_img)

    # 显示分割后的字符  
    for i, img in enumerate(word_images):
        plt.subplot(1, len(word_images), i + 1)
        plt.imshow(img, cmap='gray')
plt.show()

过程结果如下:
image.png
字符识别是车牌识别过程中的最后一步,目的是将分割出的字符图像转换为对应的文本信息。以下是一些常用的方法:

  1. 特征提取
    • 传统特征:如HOG(方向梯度直方图)、LBP(局部二值模式)等特征提取方法。
    • 深度学习特征:使用卷积神经网络(CNN)等深度学习模型自动提取字符图像的特征。
  2. 分类器训练
    • 传统分类器:如SVM(支持向量机)、KNN(K最近邻)等分类器。
    • 深度学习模型:如CNN、RNN(循环神经网络)等深度学习模型,特别是针对字符识别优化的网络结构。
  3. 模型评估
    • 测试集评估:使用独立的测试集来评估模型的性能,包括准确率、召回率等指标。
    • 交叉验证:采用交叉验证方法来提高模型的泛化能力。

代码实现如下:

# 对分割得到的字符逐一匹配
def template_matching(word_images):
	results = []
	for index, word_image in enumerate(word_images):
		if index == 0:
			best_score = []
			for chinese_words in chinese_words_list:
				score = []
				for chinese_word in chinese_words:
					result = template_score(chinese_word, word_image)
					score.append(result)
				best_score.append(max(score))
			i = best_score.index(max(best_score))
			# print(template[34+i])
			r = template[34 + i]
			results.append(r)
			continue
		if index == 1:
			best_score = []
			for eng_word_list in eng_words_list:
				score = []
				for eng_word in eng_word_list:
					result = template_score(eng_word, word_image)
					score.append(result)
				best_score.append(max(score))
			i = best_score.index(max(best_score))
			# print(template[10+i])
			r = template[10 + i]
			results.append(r)
			continue
		else:
			best_score = []
			for eng_num_word_list in eng_num_words_list:
				score = []
				for eng_num_word in eng_num_word_list:
					result = template_score(eng_num_word, word_image)
					score.append(result)
				best_score.append(max(score))
			i = best_score.index(max(best_score))
			# print(template[i])
			r = template[i]
			results.append(r)
			continue
	return results

word_images_ = word_images.copy()
# 调用函数获得结果
result = template_matching(word_images_)
print(result)
# "".join(result)函数将列表转换为拼接好的字符串,方便结果显示
print("".join(result))

代码搞定之后,我们把代码上传到 OrangePi AIpro 上,然后安装下Python环境什么的,直接运行就好了,这步比较简单,就不多说了。
最终识别出来的结果如下:

image.png

由于我这里给的数据集比较少,所以识别的不太准确,但也识别出了个大概(也可能是我代码写太烂了,玩的就是一个真实😅)。
所以我又找了基于Yolov5的车牌识别,想要识别出更加准确的结果。

基于Yolov5的车牌识别系统

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

相关知识介绍

深度学习(Deep Learning, DL)是机器学习(Machine Learning, ML)领域中一个重要的研究方向,旨在通过构建多层人工神经网络(Artificial Neural Networks, ANNs)来模拟人脑的学习过程,从而实现对复杂数据的自动分析和理解。深度学习具有多层结构、自动特征提取、非线性建模、大规模数据处理的能力,目前广泛应用于计算机视觉、自然语言处理、语音识别等领域。
YOLOv5(You Only Look Once version 5)是YOLO系列算法的最新版本之一,其具备高速和高精度的特点,在实时目标检测任务中表现出色。它继承了YOLO系列算法的核心思想,即将目标检测任务视为一个回归问题,通过卷积神经网络直接预测目标的边界框和类别概率。其网络结构可以分为三个部分:Backbone(主干网络)、Neck(颈部网络)和Head(头部网络),适用于多种实时目标监测场景,如:视频监控、自动驾驶、工业检测等。

项目拉取步骤

使用git命令拉取项目

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

image.png
拉取完成后,需要下载相关依赖,大家可直接使用下面的下载命令

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

由于项目所需要依赖过多,下载时间会稍微有一点长,这里建议大家在下载过程中可以伸个懒腰休息一下,O(∩_∩)O哈哈~。(如果在下载过程中遇到问题,可以到后面的报错解决方法中看看)

image.png

模型训练

该项目中各种路径都已配置完成,当我们需要训练自己的模型时只需要更改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

命令解析

  • python3 train.py:使用Python 3解释器来运行名为train.py的脚本文件。这个脚本很可能是YOLOv5框架中用于训练模型的脚本。
  • –data data/widerface.yaml:这个参数指定了训练数据集的配置文件路径。widerface.yaml文件应该包含了训练所需的数据集路径、类别信息、增强策略等配置信息。
  • –cfg models/yolov5n-0.5.yaml:这个参数指定了模型配置文件的路径。yolov5n-0.5.yaml文件定义了YOLOv5模型的结构,包括网络的层数、参数、锚点(anchors)等配置。
  • –weights weights/plate_detect.pt:这个参数指定了预训练权重的路径。这表示训练过程将从plate_detect.pt这个预训练的车牌检测模型开始,而不是从头开始训练。这有助于加速训练过程,并可能提高最终模型的性能。
  • –epoch 120:这个参数指定了训练的轮次(epoch)数。这意味着整个训练数据集将被遍历120次,以进行模型的学习和优化。

最终训练的结果都保存在run文件夹中。

关键函数介绍

识别车牌,包括车牌的边界框、四个角点坐标、车牌号以及(可选地)车牌颜色。下面是该函数的详细实现步骤:函数的主要逻辑如下:

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

注意

  • four_point_transform和get_split_merge函数需要用户根据具体需求实现或导入相应的库。
  • get_plate_result函数同样需要用户根据车牌识别模型的实际情况进行实现或调用已有的识别库。
  • 在实际应用中,可能还需要对输入参数进行验证,以确保函数的健壮性。

代码实现如下所示

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

在给定的原始图片上绘制车牌识别的结果的函数流程:

  1. 初始化结果字符串:首先,创建一个空字符串result_str,用于拼接所有检测到的车牌号码,以便后续打印。

  2. 遍历检测结果:对于dict_list中的每一个结果(字典),执行以下操作:

    a. 调整矩形区域:从结果字典中获取车牌的矩形区域rect_area(通常是一个包含四个整数的列表,表示矩形左上角的x、y坐标以及右下角的x、y坐标)。然后,根据车牌的宽度和高度,计算并调整矩形区域的大小,以确保车牌区域有适当的内边距,并且不会超出原始图片的边界。
    b. 处理车牌类型和颜色:根据plate_type(车牌类型,0表示单层,非0表示双层)和plate_color(车牌颜色),构建车牌号码字符串result_p。对于双层车牌,会在车牌号码后附加“双层”字样。
    c. 绘制关键点:如果结果中包含车牌的关键点(landmarks),则使用cv2.circle函数在原始图片上绘制这些点。颜色clors(注意这里可能是个笔误,通常应该是colors)应该是一个包含四种颜色的列表或元组,但由于在函数定义中没有提供colors,这里假设它是全局定义的。
    d. 绘制车牌矩形框:使用cv2.rectangle函数在原始图片上绘制车牌的矩形框,颜色为红色。
    e. 绘制车牌号码文本:首先,计算车牌号码文本的大小,以确保文本不会超出图片边界。然后,在车牌矩形框的上方绘制一个白色的背景框,用于突出显示车牌号码文本。最后,使用cv2ImgAddText(注意这个函数不是OpenCV的一部分,可能是自定义的)在白色背景框上绘制车牌号码文本,颜色为黑色。

  3. 打印结果字符串:在控制台打印出所有检测到的车牌号码字符串result_str。

  4. 返回处理后的图片:函数返回处理后的原始图片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

运行结果

在本次测试中,我直接了使用开源项目中的模型,开源项目中识别车牌的demo运行命令如下

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

命令解析

  • python detect_plate.py:这部分指示操作系统使用Python解释器来运行名为detect_plate.py的脚本文件。这是执行Python脚本的基本方式。
  • –detect_model weights/plate_detect.pt:这是一个命令行参数,用于指定车牌检测模型的文件路径。–detect_model是参数名,用于告诉脚本应该使用哪个模型进行车牌检测;weights/plate_detect.pt是参数值,即模型文件的实际路径。这里的.pt文件很可能是PyTorch模型文件的扩展名,表明该模型可能是用PyTorch框架训练的。
  • –rec_model weights/plate_rec_color.pth:与上一个参数类似,这个参数指定了车牌识别模型的文件路径。–rec_model是参数名,weights/plate_rec_color.pth是参数值。这里的.pth文件也是PyTorch模型文件的常见扩展名,表明该模型同样可能是用PyTorch框架训练的。
  • –image_path imgs:这个参数指定了输入图像(或图像文件夹)的路径。
  • –output result:这个参数指定了输出结果的存储位置。

在本次运行中,所有参与图片整合后如图 识别目标(由单个目标组合而成):
识别目标(由单个目标组合而成)
命令行结果

image.png
使用香橙派Aipro进行这组图片的识别,一共花了大约7.3 秒左右,平均每张0.45s左右,识别速度还是非常快的,可以做到秒级识别车牌号。

在本次运行中,所有结果图片整合后如图 识别目标结果(由单个目标结果组合而成):
识别目标结果(由单个目标结果组合而成)

运行过程中出现的报错与解决方法

报错1

Traceback (most recent call last):
File “openvino_infer.py”, line 4, in
from openvino.runtime import Core Module Not Found
Error: No module named ‘openvino’

解决方法:使用 pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple openvino-dev下载工具包

报错2

Traceback (most recent call last):
File “detect_plate.py”, line 12, in
from models.experimental import attempt_load
File “/home/topeet/Desktop/Chinese_license_plate_detection_recognition/models/experimental.py”, line 7, in
from models.common import Conv, DWConv
File “/home/topeet/Desktop/Chinese_license_plate_detection_recognition/models/common.py”, line 11, in
from utils.datasets import letterbox
File “/home/topeet/Desktop/Chinese_license_plate_detection_recognition/utils/datasets.py”, line 23, in
from utils.general import xyxy2xywh, xywh2xyxy, xywhn2xyxy, clean_str
File “/home/topeet/Desktop/Chinese_license_plate_detection_recognition/utils/general.py”, line 16, in
import torchvision
ModuleNotFoundError: No module named ‘torchvision’

解决方法:pip3 install -i https://pypi.tuna.tsinghua.edu.cn/simple torchvision下载工具包

报错3

pip._vendor.urllib3.exceptions.ReadTimeoutError: HTTPSConnectionPool(host=‘pypi.tuna.tsinghua.edu.cn’, port=443): Read timed out.

这个问题一看就是网络不行超时了嘛,重新执行命令下载即可。

报错4
结果出现了杂项信息

Namespace(detect_model=[‘weights/plate_detect.pt’], image_path=‘imgs’, img_size=640, is_color=True, output=‘result’, rec_model=‘weights/plate_rec_color.pth’, video=‘’)
Fusing layers…
/home/topeet/.local/lib/python3.6/site-packages/torch/functional.py:445: UserWarning: torch.meshgrid: in an upcoming release, it will be required to pass the indexing argument. (Triggered internally at …/aten/src/ATen/native/TensorShape.cpp:2157.)
return _VF.meshgrid(tensors, **kwargs) # type: ignore[attr-defined]

解决方法:这是一个警告,自于 PyTorch 库,可能是在某个依赖库(如 torchvision 或其他你正在使用的深度学习库)中使用了 torch.meshgrid,并且没有指定 indexing 参数。

项目对比

就上面两个小项目而言,基于OpenCV的车牌识别系统依赖于边缘检测、形态学操作、模板匹配等图像处理技术,而基于YOLOv5的车牌识别系统则展现了显著的技术进步,采用端到端的深度神经网络架构,通过大规模数据训练自动学习车牌特征。
而YOLOv5作为先进的目标检测算法,其高效的特征提取能力在性能上表现为更快的处理速度和更高的识别准确率,单次前向传播即可直接输出目标类别与位置,简化了后处理流程。在复杂环境如光线变化、车牌污损、角度倾斜等挑战下,YOLOv5凭借其强大的特征提取能力,往往能提供更准确的车牌识别结果,相比之下,OpenCV系统在这些场景中的表现可能受限。此外,YOLOv5通过多尺度特征融合与跨层连接等技术,展现了对光照、遮挡、角度变化等复杂环境因素的强鲁棒性,而OpenCV系统虽具一定鲁棒性,但在极端或复杂条件下性能可能下降。
因此,无论是从技术先进性、处理性能、识别结果的准确性还是系统鲁棒性来看,基于深度学习与YOLOv5的车牌识别系统均全面超越了基于OpenCV的传统方法,预示着随着深度学习技术的持续发展,YOLOv5将在智能交通管理领域都会扮演愈发重要的角色。

使用体验与结论

体验

OrangePi AIpro 凭借其卓越的即插即用特性,极大地加速了开发进程。通过简单的配置步骤,我能够迅速将这款开发板无缝集成至我的开发环境中,省去了繁琐的硬件调试环节,从而节省了宝贵的研发时间。
在软件生态方面,香橙派社区构建了一个资源丰富、文档详尽的生态系统,这对初学者而言无疑是巨大的助力,让我能够轻松访问并选用适合的文字识别模型和框架,通过直观易懂的指南,快速部署至开发板上。此外,开发板还广泛兼容多种操作系统和编程环境,让我能根据个人偏好和项目需求灵活选择开发工具,进一步优化了开发流程,提高了工作效率。这边也贴一个OrangePi AIpro的学习资源一站式导航:https://www.hiascend.com/forum/thread-0285140173361311056-1-1.html。

结论

针对我做的这个项目,在实际应用场景下,可以给 OrangePi AIpro 加多一个摄像头模组,然后通过每0.5秒拍摄一张图片的方式,调用Yolov5的模型,进行实时的车牌号识别,这样咱们就很方便的完成了一个高效的车牌识别摄像头😋。
香橙派AIpro开发板在文字识别项目中展现出了卓越的性能和易用性,它不仅为开发者提供了强大的硬件支持,还通过丰富的社区资源和完善的软件生态,降低了开发门槛,提升了开发效率。对于希望在AI领域进行探索和应用的开发者来说,香橙派AIpro无疑是一个值得推荐的选择。我相信,在未来的项目中,它将继续发挥重要作用,助力我实现更多创新想法。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1895547.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

7_1_SVPWM概述

1、SPWM 正弦脉宽调制法&#xff08;SPWM&#xff09;是将每一正弦周期内的多个脉冲作自然或规则的宽度调制&#xff0c;使其依次调制出相当于正弦函数值的相位角和面积等效于正弦波的脉冲序列&#xff0c;形成等幅不等宽的正弦化电流输出。 通过调整占空比使等效电流近似为正弦…

【BUUCTF-PWN】13-jarvisoj_level2_x64

参考&#xff1a;BUU pwn jarvisoj_level2_x64 64位函数调用栈 - Nemuzuki - 博客园 (cnblogs.com) 64位&#xff0c;开启了NX保护 执行效果如下&#xff1a; main函数&#xff1a; vulnerable_function函数 read函数存在栈溢出&#xff0c;溢出距离为0x808 查找后门…

YOLOv8改进 | 代码逐行解析(三) | YOLO中的Mosaic增强详解(带你分析你的数据集是如何输入给模型,mosaic)

一、本文介绍 本文给大家带来的是YOLOv8中的Mosaic增强代码的详解,可能有部分人对于这一部分比较陌生,有的读者可能知道Mosaic增强但是不知道其工作原理,具体来说Mosaic增强就是指我们的数据集中的图片在输入给模型之前的一个处理过程(我们的图片并不是直接就输入给模型了…

信号量——Linux并发之魂

欢迎来到 破晓的历程的 博客 引言 今天&#xff0c;我们继续学习Linux线程本分&#xff0c;在Linux条件变量中&#xff0c;我们对条件变量的做了详细的说明&#xff0c;今天我们要利用条件变量来引出我们的另一个话题——信号量内容的学习。 1.复习条件变量 在上一期博客中&…

音频流格式启用数据流

音频流格式启用数据流 音频流格式启用数据流使用 AudioStreamBasicDescription 结构在哪里以及如何设置流格式 音频流格式启用数据流 在单个样本帧级别处理音频数据时&#xff0c;就像使用音频单元一样&#xff0c;仅仅指定正确的数据类型来表示音频是不够的。单个音频样本值中…

【spring MVC的执行流程】

SpringMVC可以说是Servlet的封装&#xff0c;屏蔽了Servlet的很多细节&#xff0c;比如Servlet再获取参数的时候需要不停地getParameter,现在只要在SpringMVC方法定义对应的JavaBean&#xff0c;只要属性和参数名一致&#xff0c;SpringMVC就可以帮我们实现将参数封装到JavaBea…

android应用的持续构建CI(三)-- 手动签名

一、背景 关于android应用的签名及其原理&#xff0c;很多文章都有讲述&#xff0c;无意重复赘述。 本文紧接上文&#xff0c;站在运维的角度&#xff0c;对开发是透明的。 但是它又和gradle build 构建动作是紧密相关的。 第一步使用jdk的keytool生成证书文件&#xff0c;…

kubeadm快速部署k8s集群

Kubernetes简介 Kubernetes&#xff0c;简称k8s&#xff0c;容器编排引擎&#xff0c;以API编程的方式管理安排各个容器的引擎。 k8s会在多台node服务器上调度pod进行部署和扩缩容每个pod内部可以含&#xfeff;有多个container每个container本质上就是一个服务进程 1、k8s集…

Python 3.x 下的 3D 游戏引擎

在 Python 3.x 中&#xff0c;有几个比较流行的用于开发 3D 游戏的引擎和库。虽然 Python 自身不是一个主流的游戏开发语言&#xff0c;但是可以通过这些库和引擎结合其它语言或者底层渲染引擎来实现复杂的游戏开发。 1、问题背景 在 Linux 系统中&#xff0c;尤其是 Debian 7…

clone()方法

在Java中&#xff0c;clone() 方法是一个非常有趣且强大的工具&#xff0c;用于创建对象的一个副本。这个方法位于 Object 类中&#xff0c;因此可以被所有类使用。让我们讨论一下它的几个要点&#xff1a; 什么是克隆&#xff1f; 克隆就是创建一个对象的新副本&#xff0c;这…

3-1 激活函数和神经网络思想

3-1 激活函数和神经网络思想 主目录点这里

机器学习原理之 -- 梯度提升树(GBT)原理详解

梯度提升树&#xff08;Gradient Boosting Trees, GBT&#xff09;是一种强大的机器学习算法&#xff0c;广泛应用于分类和回归任务。它通过集成多个弱学习器&#xff08;通常是决策树&#xff09;来构建一个强大的预测模型&#xff0c;具有较高的准确性和鲁棒性。本文将详细介…

android应用的持续构建CI(四)-- 依赖环境(兼容多版本的gradle和jdk)

一、背景 android应用的构建前提是&#xff0c;安装好了gradle和jdk。在实际使用的过程中&#xff0c;不同的android应用&#xff0c;对gradle和jdk的版本要求不一。 于是&#xff0c;在jenkins服务器上&#xff0c;我们需要安装多种版本的gradle和jdk。 安装过jdk的小伙伴应…

Rethinking Federated Learning with Domain Shift: A Prototype View

CVPR2023,针对分布式数据来自不同的域时,私有模型在其他域上表现出退化性能(具有域转移)的问题。提出用于域转移下联邦学习的联邦原型学习(FPL)。核心思想是构建集群原型和无偏原型,提供富有成效的领域知识和公平的收敛目标。将样本嵌入拉近到属于相同语义的集群原型,而…

昇思25天学习打卡营第10天|利用 MindSpore 实现 BERT 对话情绪识别的完整攻略

目录 环境配置 导入模块和库 准备数据集 数据集下载和压缩 数据加载和数据预处理 进行模型的构建和优化器的设置 配置和准备模型的训练过程 测量训练操作的执行时间 模型验证 模型推理 自定义推理数据集 环境配置 首先&#xff0c;利用“%%capture captured_output”来捕获…

银湖资本在中国设立公司运营点,全球投资巨头的新篇章!

近日&#xff0c;全球知名私募股权投资公司银湖资本宣布在中国设立公司运营点。一点是银湖资本在国内安置了两个办事营业点&#xff0c;一个在黑龙江&#xff0c;一个在广州等一线城市。这一举动标志着银湖资本在全球范围内的扩展进入了新的阶段&#xff0c;同时也展示了其对中…

iOS手机竖着拍的照片被旋转了90°的原因以及解决方案

EXIF.getData(IMG_FILE, function () { // IMG_FILE为图像数据 var orientation EXIF.getTag(this, “Orientation”); console.log(“Orientation:” orientation); // 拍照方向 }); 获取拍照方向的结果为1-8的数字&#xff1a; 注意&#xff1a;对于上面的八种方向中&a…

Xilinx FPGA:vivado关于真双端口的串口传输数据的实验

一、实验内容 用一个真双端RAM&#xff0c;端口A和端口B同时向RAM里写入数据0-99&#xff0c;A端口读出单数并存入单端口RAM1中&#xff0c;B端口读出双数并存入但端口RAM2中&#xff0c;当检测到按键1到来时将RAM1中的单数读出显示到PC端&#xff0c;当检测到按键2到来时&…

从单体服务到微服务:预初始化属性多模式 Web 应用开发记录<四> FreeMarker 视图首次渲染优化

欢迎关注公众号&#xff1a;冬瓜白 相关文章&#xff1a; 多模式 Web 应用开发记录<一>背景&全局变量优化多模式 Web 应用开发记录<二>自己动手写一个 Struts多模式 Web 应用开发记录<三>预初始化属性 经过一段时间的开发和测试&#xff0c;我们成功地…

java的工厂设备管理系统-计算机毕业设计源码16179

摘要 在现代制造业中&#xff0c;高效的设备管理对于确保生产过程的顺利进行至关重要。为了满足工厂对于设备管理的需求&#xff0c;我们设计并实现了一个基于 Java 的工厂设备管理系统。 该系统旨在提供一个全面、可靠且易于使用的解决方案&#xff0c;以帮助工厂有效地管理…