提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
非标车牌识别主要用于识别和区分不符合安全标准的车牌,本次案例应用于厂区内部车辆限速控制,便于执法部门快速定位违规车辆,减少交通违法行为。
一、PaddleOCR是什么?
PaddleOCR,全称Paddle Optical Character Recognition,是百度基于其深度学习框架PaddlePaddle开发的一款功能强大的开源OCR工具。它利用深度学习技术,实现了高精度的文字检测、文字识别及版面分析等功能,广泛应用于文档数字化、车牌识别、验证码识别等多个领域。本文将简明扼要地介绍PaddleOCR的核心技术、应用场景及实践方法。
二、yolov5在项目中的作用?
通过yolov5实现自定义非标车牌的模型训练及检测车牌位置,并剪切车牌,用于OCR识别。
三、使用步骤
1.引入库
代码如下:
# -*- coding: utf-8 -*-
import asyncio
import logging
import os
import threading
import time
from collections import deque
from datetime import date
from requests_toolbelt import MultipartEncoder
import cv2
import numpy as np
import torch
from paddleocr import TextRecognition
import cgi
import requests
import re
from socketserver import ThreadingMixIn
from http.server import HTTPServer, BaseHTTPRequestHandler
2.OCR识别车牌
代码如下:
# 请求去重缓存
processed_requests = deque(maxlen=1000)
# 配置日志
logging.basicConfig(
level=logging.DEBUG, # 设置日志级别
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
filename='logs/app.log', # 日志文件名
filemode='a' # 追加模式
)
def cv_imread(file_path):
# 使用二进制方式读取文件并解码
img_array = np.fromfile(file_path, np.uint8)
img = cv2.imdecode(img_array, cv2.IMREAD_COLOR)
return img[..., ::-1] # BGR to RGB
class FileUploadHandler(BaseHTTPRequestHandler):
# 用于存储最近请求的时间戳
recent_requests = {}
recent_requests_time = {}
# 设置请求间隔时间(例如,1秒)
request_interval = 2.0
def do_POST(self):
# 设置返回类型为 HTML
self.send_response(200)
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
bodystr = self.path
if bodystr.find("uploadImg") > -1:
request_key = f"{self.client_address[0]}:{self.path}"
# {self.client_address[1]}:
current_time = time.time()
print(request_key)
if request_key in self.recent_requests and (current_time - self.recent_requests[request_key] < self.request_interval):
logging.warning("重复请求: " + request_key)
self.send_response(200)
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
self.wfile.write(bytes('{"code":201,"msg":"request already processed"}', "utf8"))
return
# 更新最近请求的时间戳
self.recent_requests[request_key] = current_time
# 解析表单数据
form = cgi.FieldStorage(fp=self.rfile, headers=self.headers,
environ={'REQUEST_METHOD': 'POST', 'CONTENT_TYPE': self.headers['Content-Type']})
self.send_response(200)
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
# 获取当前日期
today = date.today()
# 格式化为年-月-日
date_str = today.strftime('%Y%m%d')
fileName = ''
# 获取图片
for field in form.keys():
item = form[field]
if item.filename: # 文件上传字段
imgfile = f'carimg/' + item.filename
fileName = item.filename
with open(f'carimg/{item.filename}', 'wb') as f:
f.write(item.file.read())
# print(f'Saved file: {item.filename}')
logging.info(f'Saved file:{item.filename}')
if os.path.exists(imgfile):
equipment_No = form.getvalue('equipment_No') # 设备唯一编号
shotTime = form.getvalue('shotTime') # 抓拍时间 241031153119
carNumber = form.getvalue('carNumber') # 车牌号 黑A 123456
plateColor = form.getvalue('plateColor') # 车牌颜色
vehicleColor = form.getvalue('vehicleColor') # 车辆颜色
vehicleType = form.getvalue('vehicleType') # 车辆类型
speed = form.getvalue('speed') # 速度
alarm = form.getvalue('alarm') # 报警阈值
add_osd = form.getvalue('add_osd') # 默认”0”
type = form.getvalue('type') # 默认”car”,报警事件为”alarm”
AlarmEventType = form.getvalue('AlarmEventType') # 仅报警事件上传此字段
dev_address = form.getvalue('dev_address') # 速设备点位地址信息
alarm_type = form.getvalue('alarm_type') # 报警类型 0 未超速 1 超速
ongitude = form.getvalue('ongitude') # 经度
latitude = form.getvalue('latitude') # 纬度
message = "{\"code\":200,\"result\":{\"url\":\"/image/car/"+date_str+"/"+equipment_No+"_"+fileName+"\"},\"msg\":\"ok\"}"
logging.info("retrun msg : " + message)
self.wfile.write(bytes(message, "utf8"))
# 异步处理
# asyncio.run(process_image_async(fileName,imgfile,equipment_No,shotTime,carNumber,plateColor,vehicleColor,vehicleType,speed,alarm,add_osd,type,AlarmEventType,dev_address,alarm_type,ongitude,latitude))
# thread = threading.Thread(target=self.process_image_async, args=(form,))
# thread.start()
# 创建并启动一个新线程来运行异步任务
thread = threading.Thread(target=thread_function,args=(fileName,imgfile,equipment_No,shotTime,carNumber,plateColor,vehicleColor,vehicleType,speed,alarm,add_osd,type,AlarmEventType,dev_address,alarm_type,ongitude,latitude))
thread.start()
# thread.join() # 等待线程完成其工作
else:
self.send_response(200)
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
message = "{\"code\":201,\"result\":{\"fuck\":},\"msg\":\"ok\"}"
self.wfile.write(bytes(message, "utf8"))
def do_GET(self):
self.send_response(200)
self.send_header('Content-type', 'application/json;charset=utf-8')
self.end_headers()
message = b"<html><body><form method='post' action='' enctype='multipart/form-data'>Upload a file: <input type='file' name='file'><br><input type='submit' value='Upload'></form></body></html>"
self.wfile.write(bytes(message, "utf8"))
async def process_image_async(fileName,imgfile,equipment_No,shotTime,carNumber,plateColor,vehicleColor,vehicleType,speed,alarm,add_osd,type,AlarmEventType,dev_address,alarm_type,ongitude,latitude):
form_data = {}
files = {}
# 获取图片
logging.warning("接收数据:" + imgfile + "--" + str(equipment_No) + "--" + str(shotTime))
# img = cv2.imread(imgfile)[..., ::-1]
img = cv_imread(imgfile)
results = model(img) # batch of images
results_ = results.pandas().xyxy[0].to_numpy()
# results.print()
wuliuflag = 0
left_up_y = -1
right_down_y = -1
left_up_x = -1
right_down_x = -1
# 获取车牌区域并识别
for box in results_:
l, t, r, b = box[:4].astype('int') # 获取边界框坐标
confidence = str(round(box[4], 1)) # 获取置信度
cls_name = box[6]
if float(confidence) > 0.4 and cls_name == "carposi":
left_up_y = t
right_down_y = b
left_up_x = l
right_down_x = r
if right_down_x>0 and left_up_x > 0:
plate_region = img[int(left_up_y):int(right_down_y), int(left_up_x):int(right_down_x)]
# 1.灰度图
gray = cv2.cvtColor(plate_region, cv2.COLOR_BGR2GRAY)
# 2. 去噪和增强
blurred = cv2.GaussianBlur(gray, (3, 3), 0)
equalized = cv2.equalizeHist(blurred)
# cv2.imwrite("D:\\soft\\car_regnize\\carimg\\blurred.jpg", equalized)
# 3. 二值化 参数: 图像, 阈值, 最大值, 二值化类型
# _, binary = cv2.threshold(equalized, 60, 255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
# 4. 形态学操作
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (1, 1))
cleaned = cv2.morphologyEx(equalized, cv2.MORPH_CLOSE, kernel)
name = int(time.time() * 1000)
cut_img = "D:\\soft\\car_regnize\\carimg\\cut\\" + str(name) + ".jpg"
# cut_img = "D:\\yolov5-master\\carimg\\cut\\" + str(name) + ".jpg"
cv2.imwrite(cut_img, cleaned)
# PaddleOCR OCR 推理
paddleresult = ocr_model.predict(input=cut_img)
ocr_smart_text = ""
# 可视化结果并保存 json 结果
for res in paddleresult:
# res.print()
# res.save_to_img("output")
# res.save_to_json("output")
rec_text = res['rec_text']
rec_score = res['rec_score']
cleaned_text = re.sub(r'[^A-Za-z0-9]', '', rec_text)
print(rec_text + " length: " + str(len(rec_text)) + " " + str(rec_score) + " " + cleaned_text)
if rec_score > 0.5:
ocr_smart_text = cleaned_text
if len(cleaned_text) >= 6 :
wuliuflag = 0
print('正常车牌不处理' + cut_img)
elif len(cleaned_text) == 3:
wuliuflag = 1
print('物流车辆' + cut_img)
else:
wuliuflag = 2
ocr_smart_text = ""
# 识别到非标车牌
if wuliuflag == 1:
ocr_smart_text = "物流 " + ocr_smart_text[-3:]
print(ocr_smart_text)
# 准备文件数据
form_data = {
"equipment_No": equipment_No,
"shotTime": shotTime,
"carNumber": ocr_smart_text,
"plateColor": plateColor,
"vehicleColor": vehicleColor,
"vehicleType": vehicleType,
"speed": speed,
"alarm": alarm,
"add_osd": add_osd,
"type": type,
"AlarmEventType": AlarmEventType,
"dev_address": dev_address,
"alarm_type": alarm_type,
"ongitude": ongitude,
"latitude": latitude
}
files = {
'file': (fileName, open(imgfile, 'rb'), 'image/jpeg')
}
logging.warning("识别wl发送数据:" + imgfile + str(equipment_No) + "--" + str(shotTime))
elif wuliuflag == 0:
# 准备文件数据
form_data = {
"equipment_No": equipment_No,
"shotTime": shotTime,
"carNumber": carNumber,
"plateColor": plateColor,
"vehicleColor": vehicleColor,
"vehicleType": vehicleType,
"speed": speed,
"alarm": alarm,
"add_osd": add_osd,
"type": type,
"AlarmEventType": AlarmEventType,
"dev_address": dev_address,
"alarm_type": alarm_type,
"ongitude": ongitude,
"latitude": latitude
}
files = {
'file': (fileName, open(imgfile, 'rb'), 'image/jpeg')
}
logging.warning("识别正常发送数据:" + imgfile + str(equipment_No) + "--" + str(shotTime))
else:
logging.warning("识别cw不发送数据:" + imgfile + str(equipment_No) + "--" + str(shotTime))
else:
print("标准车牌不需处理直接返给平台")
# 准备文件数据
form_data = {
# 'file': (imgfile, file),
"equipment_No": equipment_No,
"shotTime": shotTime,
"carNumber": carNumber,
"plateColor": plateColor,
"vehicleColor": vehicleColor,
"vehicleType": vehicleType,
"speed": speed,
"alarm": alarm,
"add_osd": add_osd,
"type": type,
"AlarmEventType": AlarmEventType,
"dev_address": dev_address,
"alarm_type": alarm_type,
"ongitude": ongitude,
"latitude": latitude
}
files={
'file':(fileName, open(imgfile, 'rb'), 'image/jpeg')
}
try:
headers = {
'Content-type': "application/form-data", # 如果需要认证的话
}
# 发送POST请求
# data=form_data
# response = requests.post(post_url, files=files, verify=False, timeout=3)
response = requests.request("POST", post_url, files=files,data=form_data,verify=False, timeout=3)
print(response.text)
except requests.exceptions.HTTPError as errh:
print(f'Http Error: {errh}')
except requests.exceptions.ConnectionError as errc:
print(f'Error Connecting: {errc}')
except requests.exceptions.Timeout as errt:
print(f'Timeout Error: {errt}')
except requests.exceptions.RequestException as err:
print(f'OOps: Something Else {err}')
class ThreadedHTTPServer(ThreadingMixIn, HTTPServer):
"""Handle requests in a separate thread."""
pass
def thread_function(fileName,imgfile,equipment_No,shotTime,carNumber,plateColor,vehicleColor,vehicleType,speed,alarm,add_osd,type,AlarmEventType,dev_address,alarm_type,ongitude,latitude):
loop = asyncio.new_event_loop() # 为新线程创建一个事件循环
asyncio.set_event_loop(loop) # 设置当前线程的事件循环为新创建的loop
loop.run_until_complete(process_image_async(fileName,imgfile,equipment_No,shotTime,carNumber,plateColor,vehicleColor,vehicleType,speed,alarm,add_osd,type,AlarmEventType,dev_address,alarm_type,ongitude,latitude)) # 运行异步任务直到完成
loop.close() # 关闭事件循环
print("Thread finished its job")
ocr_model_dir="D:\\soft\\car_regnize\\PP-OCRv5_server_rec"
# ocr_model_dir="D:\\yolov5-master\\PP-OCRv5_server_rec"
port = 9988 # Change this port if needed
server_address = ('10.180.40.101', port) # Use '' for localhost or '0.0.0.0' for all interfaces
# server_address = ('127.0.0.1', port) # Use '' for localhost or '0.0.0.0' for all interfaces
httpd = ThreadedHTTPServer(server_address, FileUploadHandler)
model = torch.hub.load('D:\\soft\\car_regnize', 'custom', 'D:\\soft\\car_regnize\\pt\\posicar.pt', source='local')
# model = torch.hub.load('D:\\yolov5-master', 'custom', 'D:\\yolov5-master\\pt\\posicar.pt', source='local')
device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
ocr_model = TextRecognition(model_name="PP-OCRv5_server_rec",model_dir=ocr_model_dir)
post_url = "http://10.180.40.100:8889/uploadImg"
# post_url = "http://192.168.2.9:9001/uploadImg"
# 使用示例
if __name__ == "__main__":
print('Starting server, use <Ctrl-C> to stop')
httpd.serve_forever() # Start the server loop to handle requests in separate threads。
---
674

被折叠的 条评论
为什么被折叠?



