在上一篇车牌识别与标注:基于百度OCR与OpenCV的实现(一)中,我们介绍了如何在macOS系统下,利用百度OCR API进行车牌识别,并结合OpenCV库在图片上绘制标注框和车牌号码,实现了一个完整的车牌识别与标注流程。本文将继续深入探讨如何通过API的方式接入百度OCR的车辆服务,打通整个流程 。
帐号开通
按照百度智能云官方文档的指引,开通对应的OCR服务。百度OCR服务提供了免费使用次数,不用担心费用问题。以下是详细的步骤:
1. 登录并实名认证
- STEP1:在百度智能云登录页完成登录。您可以选择以百度账号登录或以云账号登录。百度账号与百度APP、百度网盘、百度地图等产品通用,如您是个人开发者,可直接使用百度账号登录;如您是企业用户,为了避免后续的账号归属问题,建议您注册云帐号并登录。
- STEP2:完成实名认证。您可以在个人实名和企业实名之间选择一种完成实名认证。
- STEP3:通过控制台左侧导航,选择产品服务-人工智能,进入具体AI服务项的控制台(如文字识别、人脸识别),进行相关业务操作。
如果您的账号已经完成了实名认证,首次进入具体AI服务的控制台,系统会自动为您的账号发放免费测试资源。测试资源会在您进入控制台后约10分钟内发放。
2. 创建应用
应用是调用服务的主体,您可以划定该应用有权限调用的接口范围,以此实现权限管理。后续也可以查看每个应用上产生的接口调用量。
方式一:在概览页上快速创建应用
- 进入文字识别控制台,点击使用指引模块的快速接入服务按钮。
- 应用名称和应用描述应当尽量反映应用的实际用途,方便您后续管理应用。在服务接口列表勾选您希望该应用能够调用的接口,勾选完毕后点击“立即创建”。
方式二:在应用管理页创建应用
- 进入文字识别控制台,选择左侧导航的“应用列表”,点击“创建应用”。
- 应用名称和应用描述应当尽量反映应用的实际用途,方便您后续管理应用。在服务接口列表勾选您希望该应用能够调用的接口,勾选完毕后点击“立即创建”。
创建成功后,您可以在应用列表页里查看应用的API Key和Secret Key。API Key和Secret Key是您调用该应用内接口的凭证,如果泄露会导致资源被盗刷,请妥善保管,避免外泄。
3. 获取密钥(API Key和Secret Key)
创建成功后,您可以在应用列表页里查看应用的API Key和Secret Key。API Key和Secret Key是您调用该应用内接口的凭证,如果泄露会导致资源被盗刷,请妥善保管,避免外泄。
4. 生成签名
您需要使用创建应用所分配到的AppID、API Key及Secret Key,进行Access Token(用户身份验证和授权的凭证)的生成,方法详见Access Token获取。我们为您准备了几种常见语言的请求示例代码。
温馨提示:Access Token的有效期为30天(以秒为单位),请您集成时注意在程序中定期请求新的token。
实际代码
以下是完整的代码实现,包括调用百度OCR API获取车牌信息,并使用OpenCV在图片上绘制标注框和车牌号码。
import cv2
import numpy as np
import math
from PIL import Image, ImageDraw, ImageFont
import base64
import urllib
import requests
import time
def draw_parallelogram_with_text(image_path, coords, text="车牌区域", width_ratio=0.60, font_path="STHeiti Light.ttc"):
"""
在图片上绘制平行四边形并添加对齐且宽度按比例缩放的中文文本
:param image_path: 图片路径
:param coords: 平行四边形的四个坐标点,格式为[(x1, y1), (x2, y2), (x3, y3), (x4, y4)]
:param text: 要添加的文本,默认为"唯普汽车"
:param width_ratio: 文本宽度占平行四边形宽度的比例,默认为 0.6
:param font_path: 中文字体文件路径
:return: 处理后的图片
"""
# 读取图片
image = cv2.imread(image_path)
if image is None:
raise FileNotFoundError(f"无法加载图片:{image_path}")
# 绘制平行四边形
cv2.fillPoly(image, [np.array(coords)], (255, 0, 0)) # 蓝色填充
# 计算平行四边形宽度(取前两点之间的距离作为参考宽度)
p1, p2 = coords[0], coords[1]
parallelogram_width = math.hypot(p2[0] - p1[0], p2[1] - p1[1])
# 获取包围盒
x_coords = [p[0] for p in coords]
y_coords = [p[1] for p in coords]
min_x, max_x = min(x_coords), max(x_coords)
min_y, max_y = min(y_coords), max(y_coords)
# 居中位置(先估算)
pil_image = Image.fromarray(cv2.cvtColor(image, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(pil_image)
# 初始字体大小
init_font_size = 30
font = ImageFont.truetype(font_path, init_font_size)
# 【关键修改】获取文本宽度(新方法)
init_text_width = font.getlength(text)
init_text_height = font.getmetrics()[0] # 获取字体高度(ascent)
# 根据比例调整字体大小
scale = (parallelogram_width * width_ratio) / init_text_width
font_size = int(init_font_size * scale)
font = ImageFont.truetype(font_path, font_size)
# 再次获取实际文本尺寸
text_width = font.getlength(text)
text_height = font.getmetrics()[0]
# 居中计算
text_x = min_x + (max_x - min_x - text_width) // 2
text_y = min_y + (max_y - min_y - text_height) // 2
# 创建空白图像用于绘制文字
text_layer = Image.new("RGBA", pil_image.size, (0, 0, 0, 0))
draw = ImageDraw.Draw(text_layer)
draw.text((text_x, text_y), text, fill=(255, 255, 255, 255), font=font)
# 计算旋转角度
def get_angle(p1, p2):
dx = p2[0] - p1[0]
dy = p2[1] - p1[1]
return math.degrees(math.atan2(dy, dx))
angle = get_angle(coords[0], coords[1])
# 旋转文本图层
rotated_text = text_layer.rotate(-angle, center=(text_x + text_width // 2, text_y + text_height // 2), expand=0)
# 合并到原图
pil_image.paste(rotated_text, mask=rotated_text.split()[3]) # 使用 alpha 通道做透明融合
# 转回 OpenCV 格式
result_image = cv2.cvtColor(np.array(pil_image), cv2.COLOR_RGB2BGR)
return result_image
API_KEY = "替换具体的key"
SECRET_KEY = "替换具体的key"
def main():
image_path = "../test6.jpg"
url = "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate?access_token=" + get_access_token()
image_data = get_file_content_as_base64(image_path)
headers = {
'Content-Type': 'application/x-www-form-urlencoded',
'Accept': 'application/json'
}
# 构造带有 'image' 字段的请求体
payload = {
'image': image_data
}
start_time = time.time()
response = requests.post( url, headers=headers, data=payload)
end_time = time.time() # 记录结束时间
elapsed_time = end_time - start_time # 计算耗时
print(f"OCR API 请求耗时: {elapsed_time:.2f} 秒")
print(f"OCR 服务返回数据:{response.text}")
# {"words_result":{"number":"晋A027W1","vertexes_location":[{"x":171,"y":216},{"x":254,"y":217},{"x":254,"y":241},{"x":171,"y":240}],"color":"blue","probability":[0.9999978542,1,1,1,1,1,0.9999997616]},"log_id":1938050504404585758}
# 解析结果,获取出vertexes_location的四个坐标点
vertexes_location = response.json().get("words_result", {}).get("vertexes_location", [])
if vertexes_location:
coords = [(vertex["x"], vertex["y"]) for vertex in vertexes_location]
print(f"车牌矩形区域的四个点坐标:,{coords}")
result_image = draw_parallelogram_with_text(image_path, coords)
# 显示结果
cv2.imshow("Result", result_image)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 保存结果图片
cv2.imwrite("result_image.jpg", result_image)
def get_file_content_as_base64(path, urlencoded=False):
"""
获取文件base64编码
:param path: 文件路径
:param urlencoded: 是否对结果进行urlencoded
:return: base64编码信息
"""
with open(path, "rb") as f:
content = base64.b64encode(f.read()).decode("utf8")
if urlencoded:
content = urllib.parse.quote_plus(content)
return content
def get_access_token():
"""
使用 AK,SK 生成鉴权签名(Access Token)
:return: access_token,或是None(如果错误)
"""
url = "https://aip.baidubce.com/oauth/2.0/token"
params = {"grant_type": "client_credentials", "client_id": API_KEY, "client_secret": SECRET_KEY}
return str(requests.post(url, params=params).json().get("access_token"))
# 示例使用
if __name__ == "__main__":
main()
运行结果
以我之思,借AI之力