基于Qt和百度AI智能云实现的智能车牌识别系统,具体可实现为停车场管理系统、智能计费停车系统…等。
注:详细资料/教程/帮助请联系作者(见文末)。
1.系统实现思路及框架
1.1实现思路
要实现一个车牌识别系统,有多种方法,例如用opencv图像算法实现,或用第三方算法接口,选择一种合适的方式。除算法部分外,还需要有用户交互界面即UI,UI界面的实现也有多种方法,也需要多种方法对比选出适合的一种。
此外,还有很重要的一项,用哪种语言实现,如C/C++,python,java …等。
1.1.1系统功能需求
要做一个项目,首先要明确系统的功能有哪些,再根据功能思考该如何实现。该项目的功能有如下:
- 打开摄像头并能实时显示画面;
- 车牌识别,能准确识别出摄像头拍到的车牌号码;
- 识别到车牌后,能显示车牌号码,并截下车辆图片;
- 若是车库或收费系统,还需要录入/删除车牌,计费等功能。
关于编译语言,多种语言均可实现,这里选择C/C++。
1.1.2界面实现
UI界面的实现,本系统选择最常用的QT库,本系统的所有UI界面都能实现,包括各种界面显示,如视频显示,文字/图像等,还有用户交互的部分,如按钮,输入框等操作控件。此外,QT库学习入门快、网上资料教程多等也是选择的原因之一。
1.1.3车牌识别实现
车牌识别,不选择算法复杂的opencv,而是选用简单调用接口的百度AI平台。用百度AI平台,具体算法方面不用关心,只需要按照其访问要求来对接即可,即发送的内容要按照百度AI定义的协议要求来组织,具体要查看百度AI官方文档,后续再具体讲解。
1.2系统框架
1.2.1硬件框架
系统的硬件主要分为两大部分:PC主机和ARM开发板,即需要一块ARM-Linux开发板(带屏幕),一个摄像头,一台PC主机,一根网线(开发板与PC主机连接)。
硬件框架
1.2.2软件框架
系统的软件框架主要分为三大部分:前台(ARM开发板)、后台(PC主机)、百度智能云。
前台(ARM开发板)主要功能是采集图像、信息显示等;后台(PC主机,ubuntu)主要是车牌管理(录入/删除车牌等)、对接百度智能云平台;百度智能云主要是识别车牌信息。
2.系统开发环境搭建
PC主机的运行环境是在windows上运行的虚拟机ubuntu系统。
2.1 Qt开发环境
界面采用QT进行开发,主要安装qt creator即可。
qt creator安装程序是图形化界面的,像在windows上安装软件一样,比较简单,不再累述。
2.2百度AI开发环境
与百度AI的通信方式是https,因此,百度AI相关的环境主要有OpenSSL库、Curl库和Json库的安装。
2.2.1 OpenSSL库安装
下载openssl库:/source/index.html (openssl.org)
实验版本:openssl-1.1.1s.tar.gz
将openssl库源码包放到ubuntu下,解压出来,并进入解压出来的目录。
配置编译选项:主要配置安装路径
$ ./config –prefix=/usr/local/openssl
编译:
$ make
安装:
$ sudo make install
安装完成,可在安装路径下见到openssl
2.2.2 Curl库安装
下载curl源码包:curl-7.88.0.tar.gz
下载地址:curl downloads
亦可用命令下载:
$ wget https://curl.se/download/curl-7.88.0.tar.gz
将源码包放入ubuntu,解压出来,并进入解压出来的目录:
配置编译选项:指定安装在/usr/local/curl目录,指定openssl的路径,
$ ./configure --prefix=/usr/local/curl --with-ssl=/usr/local/openssl
编译
$ make
安装
$ sudo make install
2.2.3 Jsoncpp安装
下载jsoncpp库:jsoncpp-master.tar.gz
open-source-parsers/jsoncpp: A C++ library for interacting with JSON. (github.com)
把源码包放到ubuntu上,解压出来并进入解压出来的目录:
执行amalgamate.py脚本,会在当前目录生成dist目录:
dist目录就是我们需要的源码文件,共有3个文件:
jsoncpp.cpp、json-forwards.h、json.h
将其包含在我们的工程源码一起编译即可使用json接口了。
使用时,只需包含头文件json.h
#include "json/json.h"
3.系统实现步骤
整个系统的实现,分功能分模块逐个实现,由简入深,先表面再内部,就是说,先做界面和图像采集及显示的,然后调前台和后台之间的通信,最后再实现百度AI算法接口的调用。
3.1 Qt界面
3.1.1 界面显示及而已
界面显示及布局可直接在Qt creator上添加想要的控件及设定其坐标位置即可,十分的直观快捷。
前台界面设计如下:
注:中间大图区域显示摄像头画面,右侧显示识别出来的车牌号信息。
后台界面设计如下:
注:中间大图区域显示摄像头画面或出入记录表格,右侧为识别结果及车牌管理相关功能。
3.1.2 摄像头图像采集及显示
对摄像头的驱动,采用的是linux系统的V4L2框架,这是linux系统内部的,不需要我们来实现,只管调用即可。
V4L2流程:申请若干个buffer,组成一个队列,每个buffer用于存放一帧图像,当摄像头有图像时便会填充到到这些buffer中,要读取数据时实际是取出一个已填充图像的buffer,读完图像又将该buffer塞入队列中。
采集到图像后,将送至屏幕显示以及传输给后台并由后台发送到百度AI平台识别,百度AI再返回识别结果,这样图像的流程就走完了。
图像流程
3.2 前后台通信
前后台通信采用的是socket套接字TCP连接,一切数据交互都是基于TCP连接的,后台为服务器,前台为客户端。
具体通信数据内容可以定义一种协议,通信双方按照协议所规定的格式对数据进行封装及解析,这种通信内容就清晰可见。本系统的通信协议定义如下:
格式如下:
字段 | 协议头 HEAD | 校验码 VERIFY | 顺序号 SEQ | 命令号 CMD | 数据长度 LEN | 数据 DATA | 协议尾 TAIL |
内容 | 0xFF | “ABCD” | 0~255 | 0x00~ | … | … | 0xFE |
长度/byte | 1 | 4 | 1 | 1 | 4 | LEN | 1 |
可见,一个协议数据包有头有尾及校验等格式字段,还包含命令号、数据等内容部分,具体的命令号及数据可再自定义,例如登陆的命令号为0x01、发送图像0x02、识别结果0x03等。
3.3 百度AI调用
百度车牌识别:支持识别中国大陆机动车蓝牌、黄牌(单双行)、绿牌、大型新能源(黄绿)、领使馆车牌、警牌、武警牌(单双行)、军牌(单双行)、港澳出入境车牌、农用车牌、民航车牌、非机动车车牌(北京地区)的地域编号和车牌号,并能同时识别图像中的多张车牌。
百度智能云(百度AI)算法接口的调用是基于http协议(Hypertext Transfer Protocol,超文本传输协议),http是一个简单的请求-响应协议,它通常运行在TCP之上。它指定了客户端可能发送给服务器什么样的消息以及得到什么样的响应。
3.3.1 创建百度设备
首先要在百度智能云官网上创建自己的账号,然后创建一个人车牌识别的项目/设备,具体操作请自行了解,这里不再展开。
3.3.2 鉴权认证
鉴权的主要目的是获取Access_token。Access_token是用户的访问令牌,承载了用户的身份、权限等信息。鉴权主要分为以下两步:1、获取AK/SK;2、获取Access_token。
在应用列表下,AK和SK均可见,直接复制即可,后续需要用到,如下:
获取Access_token:
百度AI开放平台使用OAuth2.0授权调用开放API,调用API时必须在URL中带上Access_token参数,Access token默认有效期为30天,获取Access_token的流程如下:
请求URL数据格式:
向授权服务地址https://aip.baidubce.com/oauth/2.0/token发送请求(推荐使用POST),并在URL中带上以下参数:
- grant_type: 必须参数,固定为client_credentials;
- client_id: 必须参数,应用的API Key;
- client_secret: 必须参数,应用的Secret Key;
例如:
https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=Va5yQRHlA4Fq5eR3LT0vuXV4&client_secret=0rDSjzQ20XUj5itV6WRtznPQSzr5pVw2&
获取access_token的C++代码:
#include <stdio.h>
#include <iostream>
#include <string.h>
#include <curl/curl.h>
#include <json/json.h>
#include <fstream>
inline size_t onWriteData(void * buffer, size_t size, size_t nmemb, void * userp)
{
std::string * str = dynamic_cast<std::string *>((std::string *)userp);
str->append((char *)buffer, size * nmemb);
return nmemb;
}
int main(int argc, char *argv[])
{
std::string result;
CURL *curl;
CURLcode res;
curl = curl_easy_init();
if(curl) {
curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");
curl_easy_setopt(curl, CURLOPT_URL, "https://aip.baidubce.com/oauth/2.0/token?client_id=&client_secret=&grant_type=client_credentials");
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
struct curl_slist *headers = NULL;
headers = curl_slist_append(headers, "Content-Type: application/json");
headers = curl_slist_append(headers, "Accept: application/json");
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);
const char *data = "";
curl_easy_setopt(curl, CURLOPT_POSTFIELDS, data);
curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onWriteData);
res = curl_easy_perform(curl);
std::cout<<result;
}
curl_easy_cleanup(curl);
return (int)res;
}
运行程序后,百度AI服务器返回json文本参数,如下:
由上可见,成功获取到access_token。
后续的算法接口都需要用到该access_token来鉴权验证,否则无法访问。
3.3.3 百度AI算法的调用
百度AI算法的调用是基于https协议的,向百度AI服务器使用post发送请求,带上验证信息、图片数据等,百度AI处理post请求并识别图片中的车牌号后,再返回结果。
具体post内容如下:
HTTP POST请求URL:https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate
URL参数:access_token
Header如下:
参数 | 值 |
Content-Type | application/x-www-form-urlencoded |
Body中放置请求参数,参数详情如下:
百度AI处理识别图片后,返回参数如下:
示例代码,C++如下:
#include <iostream>
#include <curl/curl.h>
// libcurl库下载链接:https://curl.haxx.se/download.html
// jsoncpp库下载链接:https://github.com/open-source-parsers/jsoncpp/
const static std::string request_url = "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate";
static std::string licensePlate_result;
/**
* curl发送http请求调用的回调函数,回调函数中对返回的json格式的body进行了解析,解析结果储存在全局的静态变量当中
* @param 参数定义见libcurl文档
* @return 返回值定义见libcurl文档
*/
static size_t callback(void *ptr, size_t size, size_t nmemb, void *stream) {
// 获取到的body存放在ptr中,先将其转换为string格式
licensePlate_result = std::string((char *) ptr, size * nmemb);
return size * nmemb;
}
/**
* 车牌识别
* @return 调用成功返回0,发生错误返回其他错误码
*/
int licensePlate(std::string &json_result, const std::string &access_token) {
std::string url = request_url + "?access_token=" + access_token;
CURL *curl = NULL;
CURLcode result_code;
int is_success;
curl = curl_easy_init();
if (curl) {
curl_easy_setopt(curl, CURLOPT_URL, url.data());
curl_easy_setopt(curl, CURLOPT_POST, 1);
curl_httppost *post = NULL;
curl_httppost *last = NULL;
curl_formadd(&post, &last, CURLFORM_COPYNAME, "image", CURLFORM_COPYCONTENTS, "【base64_img】", CURLFORM_END);
curl_easy_setopt(curl, CURLOPT_HTTPPOST, post);
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, callback);
result_code = curl_easy_perform(curl);
if (result_code != CURLE_OK) {
fprintf(stderr, "curl_easy_perform() failed: %s
",
curl_easy_strerror(result_code));
is_success = 1;
return is_success;
}
json_result = licensePlate_result;
curl_easy_cleanup(curl);
is_success = 0;
} else {
fprintf(stderr, "curl_easy_init() failed.");
is_success = 1;
}
return is_success;
}
结果返回示例:
{
"words_result": [
{
"color": "blue",
"number": "京KBT355",
"probability": [
0.9999992847,
0.999999404,
0.9999910593,
0.9999765158,
0.999994874,
0.9998959303,
0.9999984503
],
"vertexes_location": [
{
"x": 495,
"y": 589
},
{
"x": 800,
"y": 587
},
{
"x": 800,
"y": 676
},
{
"x": 496,
"y": 678
}
]
}
],
"log_id": "6845817085824549137"
}
从结果可见,可得知车牌号、颜色、位置坐标等信息。
4. 系统实现效果
后台PC端效果图:
前面ARM开发板效果图:
最后:
资料/指导答疑/技术交流/选题/帮助,请点链接:
linux_face.txt · zengzr/share_contact - Gitee.com
如有任何问题,请联系作者,谢谢!