---------------
7月更新训练项目:
新的车牌检测+关键点检测+车牌矫正:
https://aistudio.baidu.com/aistudio/projectdetail/6545272
LPRNet矫正后的车牌识别:
https://aistudio.baidu.com/aistudio/projectdetail/5628649
---------------
3月14日更新内容:
网络训练:添加了yolov5和LPRNet的训练过程
https://aistudio.baidu.com/aistudio/projectdetail/5557065
https://aistudio.baidu.com/aistudio/projectdetail/5628649
模型转换:总结了onnx转tflite的更多细节
https://blog.csdn.net/kalahali/article/details/129538442
部署:新增aistudio项目模型部署差异
----------------
AidLux智慧社区AI实战总结之车牌检测与识别,基于yolov5实现车牌检测,加上LPRNet对检测到的车牌进行识别来实现整个识别流程,最后通过AidLux实现在手机端的部署
https://pan.baidu.com/s/147gi2MLqC6KiBGHyzSsbkw 提取码:aid3
手机端需要下载aidlux软件
算法方案需要考虑应用场景,不同场景,车牌识别的算法方案也不一样,比如:
本项目正是基于智慧社区的应用场景,所以选择算法方案为车牌检测yolov5和车牌识别LPRNet
注意,在实际应用场景中,如果车牌在图片中的倾角较大,一般车牌的水平度和垂直度超过15°,则需要考虑加入矫正,算法方案应为:车牌检测+车牌矫正+车牌识别
这里的智慧社区的车与相机位置可以相对平行固定,故不添加矫正
考虑到智慧社区中,在社区内很少出现工程车辆,所以只需要覆盖大部分的蓝牌和绿牌的场景即可。最普遍的开源车牌数据集是中科大的CCPD数据集,官网链接是:https://github.com/detectRecog/CCPD
中科大车牌数据集有CCPD2019和CCPD2020,其中CCPD2019主要为蓝牌,CCPD2020为绿牌。其中蓝牌是燃油车,绿牌是电动车。
这里我们主要用CCPD2019的蓝牌来作为我们的任务,官网有百度网盘链接:
Images in CCPD-Base is split to train/val set. Sub-datasets (CCPD-DB, CCPD-Blur, CCPD-FN, CCPD-Rotate, CCPD-Tilt, CCPD-Challenge) in CCPD are exploited for test.
用于训练的数据在CCPD-Base中,从这里划分训练集和验证集
用于测试的数据则有:
CCPD-DB:车牌区域交亮,较暗或则不均匀
CCPD-Blur:由于相机抖动而导致的模糊车牌
CCPD-FN: 车牌距离摄像头较近或则较远
CCPD-Rotate: 旋转/倾角
CCPD-Challenge: 有挑战性
CCPD-Tilt:
每张图片的标签为文件名:
图片命名:“0019-1_1-340&500_404&526-404&524_340&526_340&502_404&500-0_0_11_26_25_28_17-66-3.jpg”
# 详细解释:
"""
0019:
车牌区域占整个画面的比例;
1_1:
车牌水平和垂直角度, 水平1°, 竖直1°
340&500_404&526:
标注框左上、右下坐标,左上(154, 383), 右下(386, 473)
404&524_340&526_340&502_404&500:
标注框四个角点坐标,顺序为右下、左下、左上、右上
0_0_11_26_25_2_8:
车牌号码, 映射关系如下:
第一个0为省份 对应省份字典provinces中的’皖’,;
第二个0是该车所在地的地市一级代码,对应地市一级代码字典alphabets的’A’;
后5位为字母和文字, 查看车牌号ads字典,如11为M,26为2,25为1,2为C,8为J 最终车牌号码为皖AM21CJ
映射列表:
省份:[“皖”, “沪”, “津”, “渝”, “冀”, “晋”, “蒙”, “辽”, “吉”, “黑”, “苏”, “浙”, “京”, “闽”, “赣”, “鲁”, “豫”, “鄂”, “湘”, “粤”, “桂”, “琼”, “川”, “贵”, “云”, “藏”, “陕”, “甘”, “青”, “宁”, “新”]
地市:[‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’,‘X’, ‘Y’, ‘Z’]
车牌字典:[‘A’, ‘B’, ‘C’, ‘D’, ‘E’, ‘F’, ‘G’, ‘H’, ‘J’, ‘K’, ‘L’, ‘M’, ‘N’, ‘P’, ‘Q’, ‘R’, ‘S’, ‘T’, ‘U’, ‘V’, ‘W’, ‘X’,‘Y’, ‘Z’, ‘0’, ‘1’, ‘2’, ‘3’, ‘4’, ‘5’, ‘6’, ‘7’, ‘8’, ‘9’]
"""
需要先对图片的标签解析,解析完后才能对其进行训练。
因为中科大在安徽采集数据较多,其中“皖”字占整个数据集汉字的90%,所以如果是对智慧社区定制化开发,需考虑社区所在的地理位置,针对性采集数据,或者模拟数据,优化模型。
因要做两个任务,车牌检测、车牌识别。所以将车牌数据集整理分成两个部分:一是整理成检测任务需要的数据集,二是整理成车牌识别任务需要的数据集。
由于数据量较大,为防止出错,这里分为两步:
简单验证:
先将几张图片标签转成yolo文件,并通过yolo转成voc xml格式,用labelimg打开校验。
批量转换:
确认转换的方式没有问题后,将所有标签直接转换成yolo格式保存。
转yolo格式以及yolo转voc格式的脚本在代码资源中位置:tools/ParaseData.py
转换voc之后用labelimg打开图片文件夹,并查看xml_labels结果,标注的label转换没有问题:
检查没问题后将脚本中的validation设置成False,修改图片路径和保存txt路径:
考虑训练时长等因素,可以使用脚本tools/cp10000.py,将数据随机抽取1万张来训练,若后期效果不好,可以用8w多张数据重新训练。
对于车牌识别步骤,需要将车牌裁切出来作为训练数据,脚本为ools/ccpd2lpr.py,生成以车牌号为文件名的数据集。
训练部分就是yolov5和lprnet的训练。
本人没有GPU电脑,这里选择的是云服务器,除了AutoDL平台,这次白嫖百度飞浆AIStudio平台的算力来训练,项目地址如下,可以直接fork后开启训练:
直接使用PaddleYOLO项目快速开启训练
https://aistudio.baidu.com/aistudio/projectdetail/5557065
以下是转写paddle后的训练项目:
https://aistudio.baidu.com/aistudio/projectdetail/5628649
在云服务器上训练并生成onnx文件后,将onnx下载到本地准备下一步部署
若使用torch,可以参考项目资料里的参考代码train_yolov5.py和train_lprnet.py
训练完后保存好pt模型。
yolov5测试代码参考detect_yolov5.py(输出结果在demo/detect_results)
测试车牌识别的脚本test_lprnet.py
需要注意的是车牌识别作为车牌检测的下游任务,其输入图片需要将检测到的裁剪车牌
整个流程串联起来的测试脚本detect_torch_pipeline.py
AidLux是安装在ARM架构下的,跨生态(Android/鸿蒙+Linux)一站式开发和部署平台APP。必须要在安卓手机或者安卓的平板上或ARM板卡才能下载运行,设备需要满足ARM64位,安卓6.0以上。可以在手机应用商城搜索下载。
当然如果后面在手机上操作编程有点麻烦,可以通过IP的方式,在局域网内直接映射到电脑上操作。可以点击页面最上方的Cloud_ip,浏览器在手机访问。
浏览器进入桌面的默认密码是:aidlux
可以浏览器桌面方便的传输文件。
这里贴上aidlux图像处理相关的文档地址:https://docs.aidlux.com/#/api/?id=%e5%9b%be%e5%83%8f%e5%a4%84%e7%90%86
使用vscode的remote功能,可以远程连接手机,方便编写代码,ssh配置如下:
hostname需要为cloud_ip里的地址,连接的密码都是aidlux
pt模型移植到Android还需要转换成Android端适配的模型,一般适配的轻量化模型如ncnn, tflite, paddlelite等,这里选择这里我们选择的tflite模型,不过pytorch直接转tflite的工具不齐全,一般都会转成序列化成onnx,再轻量化模型, 以pytorch->onnx->tflite 方式。
yolov5代码中自带导出代码,配置export_yolov5.py中的配置代码,修改weights路径导出onnx
可以在netron查看网络结构https://netron.app/
lprnet的导出代码在export_lprnet.py
注意lprnet网络中的maxpool3d没有被官方支持,这里将maxpool3d用两个maxpool2d去实现(代码里已经修改了)
基于onnx的前向推理可参考detect_onnx_inference.py
模型转换的注意事项还可参考总结:
https://blog.csdn.net/kalahali/article/details/129538442
参考代码export_tflite.py
from onnx_tf.backend import prepare
import onnx
TF_PATH = "weights/LPRNet_Simplified.pb" # where the representation of tensorflow model will be stored
ONNX_PATH = "weights/LPRNet_Simplified.onnx" # path to my existing ONNX model
onnx_model = onnx.load(ONNX_PATH) # load onnx model
tf_rep = prepare(onnx_model) # creating TensorflowRep object
tf_rep.export_graph(TF_PATH)
import tensorflow as tf
TF_PATH = "weights/LPRNet_Simplified.pb"
TFLITE_PATH = "weights/LPRNet_Simplified.tflite"
converter = tf.lite.TFLiteConverter.from_saved_model(TF_PATH)
converter.optimizations = [tf.lite.Optimize.DEFAULT]
tf_lite_model = converter.convert()
with open(TFLITE_PATH, 'wb') as f:
f.write(tf_lite_model)
pc端的tflite推理参考detect_tflite_pipeline.py
需要注意,在netron中看到yolov5.tflite模型的输出output顺序是40,20,80,在tflite模型输出后处理的时候需要注意anchor的对应。
参考代码detect_aidlux_inference.py
需要注意模型的in_shape 和out_shape 要与netron中查看的输入输出保持一致,并且还要*4,表示float32有4个字节
跟多关于aidlite.ANNModel的详细信息可以在前面提到文档中查看:https://docs.aidlux.com/#/api/?id=annmodel
修改自己的两个模型路径后,运行
另外关于cv2不支持中文可以参考下面测试案例,利用PIL实现和cv2.putText的相同效果:
import numpy as np
from PIL import Image, ImageDraw, ImageFont
import cv2
def cv2AddChinese(img, text, position, fontScale=1., textColor=(0,255,0)):
if (isinstance(img, np.ndarray)):
img = Image.fromarray(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
baseFontSize = 34 # 以此字体大小进行缩放,字体高度
height = baseFontSize*0.8 # 字体实际高度,去空白
x, y = position
position_new = (x, y-fontScale*height)
fontsize = int(fontScale * baseFontSize)
draw = ImageDraw.Draw(img)
# SimHei.ttf为字体文件,可在网上下载,若读取失败,改为完整路径
fontStyle = ImageFont.truetype("SimHei.ttf", fontsize, encoding="utf-8")
# width, height = fontStyle.getsize(text) # 获取字体宽高
draw.text(position_new, text, textColor, font=fontStyle)
return cv2.cvtColor(np.asarray(img), cv2.COLOR_RGB2BGR)
text = "Chines中文"
img_dir = 'test.JPG' # 自己的测试图片
position = (0, 40)
fontScale = 1.5
img_data = cv2.imread(img_dir)
img_data = cv2AddChinese(img_data, text, position, fontScale, (0,255,0))
# t_size = cv2.getTextSize(text, 0, fontScale, thickness=2) # cv2获取字体宽高
cv2.putText(img_data, text, position, 0, fontScale, (255,0,0), 2)
cv2.imshow('demo', img_data)
cv2.waitKey(1000)
这里新增一小节,对上文中提到的aistudio训练项目模型与本文资料包代码的区别做个说明
# 模型的导入
det_model_path = '模型的存放位置'
in_shape0 = [1 * 3* 640 * 640 * 4] # 4是4个字节,float32
out_shape0 = [1 * 25200 * 5 * 4]
aidlite.ANNModel(det_model_path, in_shape0, out_shape0, 4, -1)
def det_poseprocess(outputs, imgsz, scale, left, top ,conf_thresh, iou_thresh):
# nms
true_conf = outputs[..., 4]
mask = true_conf > conf_thresh
# 调整为原图下的坐标
pred = outputs[mask][:, :4]
boxes = np.zeros_like(pred)
boxes[:, 0] = pred[:, 0] - left
boxes[:, 2] = pred[:, 2] - left
boxes[:, 1] = pred[:, 1] - top
boxes[:, 3] = pred[:, 3] - top
boxes /= scale
confs = true_conf[mask]
keep = non_max_suppression(boxes, confs, iou_thresh=0.5)
boxes = boxes[keep]
confs = confs[keep].reshape((-1, 1))
classes = np.zeros_like(confs).reshape((-1, 1))
return boxes, confs, classes
# reg_preprocess
img_crop = cv2.cvtColor(img_crop, cv2.COLOR_BGR2RGB)
使用aidlux在手机端部署车牌检测识别