Smart parking lot - license plate recognition automatic billing system

Get into the habit of writing together! This is the 13th day of my participation in the "Nuggets Daily New Plan · April Update Challenge", click to view the event details .

1. Project introduction

License plate recognition system is a classic application of computer video image recognition technology in vehicle license plate recognition. Now high-speed electronic toll collection (ETC), illegal driving, speeding, automatic parking lot toll system, and many other scenarios use license plate recognition technology. .

This article uses the license plate number recognition interface in HUAWEI CLOUD's artificial intelligence classification to quickly build a parking lot automatic toll collection system. The hardware adopts the Raspberry Pi development board, the camera adopts the ordinary drive-free USB camera, and the ultrasonic ranging module is used for detection. Whether there is a vehicle approaching, the license plate recognition interface adopts an online method; the software background and UI interface are designed with QT and C++, which supports cross-platform, which is more convenient. After the code is written once, the mainstream platform can be compiled and run.

This project is just to demonstrate the use of the license plate number recognition interface, and quickly build an application scenario, many details have not been considered perfect.

Recognition idea: Use two USB cameras as the entrance and exit, respectively use the ultrasonic ranging module to continuously measure the distance of the object in front of the camera. When it is detected that the vehicle is approaching, read a frame of data from the current camera, and pass the license plate number of HUAWEI CLOUD. The identification interface performs identification and returns the identification result; if it is an entrance camera, then the identified license plate is stored in the database, and the current entry time is recorded. If it is an exit, it is compared with the license plate data in the current database to find the license plate to enter the venue. The parking time is subtracted from the current time, and then according to the charging rules set by the parking lot, the fee prompt and voice broadcast are completed to tell the car owner how much to pay.

image-20211227011717512

image-20211227011113372

image-20211227011134316

2. Configure HUAWEI CLOUD interface

2.1 Open license plate recognition service

The current experience is the online API license plate interface. You need to activate the license plate recognition service before you can use the interface (you need to register a HUAWEI CLOUD account to log in).

License plate recognition service opening address: console.huaweicloud.com/ocr/?region…

image-20211226231518223

Interface usage billing description page: www.huaweicloud.com/pricing.htm…

image-20211226231637159

可以看到,如果使用在线API接口实现车牌识别,每月免费1000次,作为体验来讲已经足够了。

2.2 车牌识别接口使用介绍

在线文档地址: support.huaweicloud.com/api-ocr/ocr…

在这个页面可以看到在线请求的接口地址,参数、响应结果等详细介绍。

image-20211226232044413

如果想快速体验效果,可以直接使用在线调试功能,这个功能非常好用,可以快速体验各种接口,参数的功能。

在线调试地址: apiexplorer.developer.huaweicloud.com/apiexplorer…

准备一张待测试识别的车牌:

image-20211226232703680

使用接口调试:

image-20211226233107253

调试的时候需要填入图片的base64编码,可以直接使用浏览器自带的功能实现。

官网文档: support.huaweicloud.com/ocr_faq/ocr…

image-20211226234844770

实操:

image-20211226234944137

2.3 接口总结

 请求方式: post
 ​
 URL地址格式: POST https://{endpoint}/v2/{project_id}/ocr/license-plate
 ​
 实际地址: (下面填的是我的项目ID,需要替换成自己,服务器域名也是一样)
 https://ocr.cn-north-4.myhuaweicloud.com/v2/0e5957be8a00f53c2fa7c0045e4d8fbf/ocr/license-plate
 ​
 请求头: 
 {
  "User-Agent": "API Explorer",
  "X-Auth-Token": "******", 这里填Token
  "Content-Type": "application/json;charset=UTF-8"
 }
 ​
 ​
 请求体:
 {
  "image": "/9j/4AAQSkZJRgABAQEAkACQAAD/2wBDAAMCAgMCAgMDAwME.........这里是图片的base64编码,非常长,这里就省略了,明白意思就行....."
 }
 ​
 响应头:
 {
  "Darklaunch-Rule-Name": "s-bdc8-1254-202112061537",
  "Server": "api-gateway",
  "X-Request-Id": "6b9a88702fe419acd8b638d35a9bf523",
  "Connection": "keep-alive",
  "X-ModelArts-Trace": "6b9a88702fe419acd8b638d35a9bf523",
  "Content-Length": "544",
  "X-ModelArts-Latency": "100",
  "Date": "Sun, 26 Dec 2021 15:29:46 GMT",
  "Instance-Request-Count": "1",
  "Content-Type": "application/json"
 }
 ​
 响应体:
 {
  "result": [
   {
    "plate_number": "京A33333",
    "plate_color": "blue",
    "plate_location": [
     [
      236,
      331
     ],
     [
      882,
      331
     ],
     [
      882,
      542
     ],
     [
      236,
      542
     ]
    ],
    "confidence": 0.9964
   }
  ]
 }
复制代码

2.4 接口参数解释

上面2.3小节里总结了接口地址一些详细参数,这里把接口里的一些重要参数解释一遍。

车牌识别的URL:

 POST https://{endpoint}/v2/{project_id}/ocr/license-plate
复制代码

endpoint 是指定承载REST服务端点的服务器域名或IP,不同服务不同区域的endpoint不同,可以从终端节点中获取。

例如,OCR服务在“华北-北京四”区域的 “endpoint” 为“ocr.cn-north-4.myhuaweicloud.com”。

image-20211227000018117

URL里还有一个project_id参数,这是项目ID,可以从获取项目ID中获取。

image-20211227000326180

There is a relatively common parameter in the request header: X-Auth-Token , Almost all API interface request headers on HUAWEI CLOUD need to be filled X-Auth-Tokenin. The method to obtain it is here: bbs.huaweicloud.com/blogs/31775… Turn to Section 3.

image-20211227000642651

3. Project implementation code

3.1 License Plate Recognition Request Code

 //车牌识别接口
 void Widget::car_distinguish(QImage imag)
 {
     function_select=0;
     QString requestUrl;
     QNetworkRequest request;
 ​
     //存放图片BASE64编码
     QString imgData;
 ​
     //设置请求地址
     QUrl url;
 ​
     //车牌识别请求地址
     requestUrl = QString("https://ocr.%1.myhuaweicloud.com/v2/%2/ocr/license-plate")
             .arg(SERVER_ID)
             .arg(PROJECT_ID);
 ​
     //设置数据提交格式
     request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));
 ​
     //将图片进行Base64编码
     imgData = QString(toBase64(imag)); //编码后的图片大小不超过2M
     //设置token
     request.setRawHeader("X-Auth-Token",Token);
 ​
     //构造请求
     url.setUrl(requestUrl);
     request.setUrl(url);
 ​
     QString post_param=QString("{"image": "%1"}").arg(imgData);
 ​
     //发送请求
     manager->post(request, post_param.toUtf8());
 }
复制代码

3.2 Image base64 encoding

 /*
 将图片进行base64编码
 */
 QByteArray Widget::toBase64(const QImage &image)
 {
     //将要检测的图片进行BASE64编码
     QByteArray ba;
     QBuffer buffer(&ba);
     buffer.open(QIODevice::WriteOnly);
     //以png格式将图片数据写入ba
     image.save(&buffer,"jpg");
 ​
     buffer.close();
     return ba.toBase64();
 }
复制代码

3.3 Ultrasonic Module Driver Code

 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
 #include <linux/io.h>
 #include <linux/irq.h>
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/gpio.h>
 #include <mach/gpio.h>
 #include <plat/gpio-cfg.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/poll.h>
 #include <linux/fcntl.h>
 #include <linux/interrupt.h>
 #include <linux/ktime.h>
 ​
 static unsigned int distance_irq; /*存放中断号*/
 static u32 *GPB_DAT=NULL;
 static u32 *GPB_CON=NULL;
 ​
 /*
 工作队列处理函数: 
 */
 static void distance_work_func(struct work_struct *work)
 {
     u32 time1,time2;
     time1=ktime_to_us(ktime_get()); /*获取当前时间,再转换为 us 单位*/
 ​
     /*等待高电平时间结束*/
     while(gpio_get_value(EXYNOS4_GPX1(0))){}
     
     time2=ktime_to_us(ktime_get()); /*获取当前时间,再转换为 us 单位*/
 ​
     printk("us=%d\n",time2-time1);  /*us/58=厘米*/
 }
 ​
 /*静态方式初始化工作队列*/
 static DECLARE_WORK(distance_work,distance_work_func);
 ​
 /*
 中断处理函数: 用于检测超声波测距的回波
 */
 static irqreturn_t distance_handler(int irq, void *dev)
 {
     /*调度工作队列*/
     schedule_work(&distance_work);
     return IRQ_HANDLED;
 }
 ​
 static void distance_function(unsigned long data);
 /*静态方式定义内核定时器*/
 static DEFINE_TIMER(distance_timer,distance_function,0,0);
 ​
 /*内核定时器超时处理函数: 触发超声波发送方波*/
 static void distance_function(unsigned long data)
 {
     static u8 state=0;
     state=!state;
     
     /*更改GPIO口电平*/
     if(state)
     {
         *GPB_DAT|=1<<7;
     }
     else
     {
         *GPB_DAT&=~(1<<7);
     }
     
     /*修改定时器的超时时间*/
     mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100));
 }
 ​
 static int __init tiny4412_distance_dev_init(void) 
 {
     int err;
     /*1. 映射GPIO口地址*/
     GPB_DAT=ioremap(0x11400044,4);
     GPB_CON=ioremap(0x11400040,4);
 ​
     *GPB_CON&=~(0xF<<4*7);
     *GPB_CON|=0x1<<4*7; /*配置输出模式*/
     
     /*2. 根据GPIO口编号,获取中断号*/
     distance_irq=gpio_to_irq(EXYNOS4_GPX1(0));
     
     /*3. 注册中断*/
     err=request_irq(distance_irq,distance_handler,IRQ_TYPE_EDGE_RISING,"distance_device",NULL);
     if(err!=0)printk("中断注册失败!\n");
     else printk("中断:超声波测距驱动安装成功!\n");
 ​
     /*4. 修改定时器超时时间*/
     mod_timer(&distance_timer,jiffies+msecs_to_jiffies(100));
     
     return 0;
 }
 ​
 static void __exit tiny4412_distance_dev_exit(void) 
 {
     /*5. 注销中断*/
     free_irq(distance_irq,NULL);
 ​
     /*6. 停止定时器*/
     del_timer(&distance_timer);
     
     /*7. 取消IO映射*/
     iounmap(GPB_DAT);
     iounmap(GPB_CON);
     printk("中断:超声波测距驱动卸载成功!\n");
 }
 ​
 module_init(tiny4412_distance_dev_init);
 module_exit(tiny4412_distance_dev_exit);
 MODULE_LICENSE("GPL");
复制代码

Guess you like

Origin juejin.im/post/7085895808792395789