项目分享|基于ELF 1开发板的车牌识别系统

该项目选用ElfBoard ELF 1开发板作为核心硬件平台,利用USB接口连接的摄像头捕捉并识别车牌信息。一旦车牌成功识别,系统会触发绿灯指示,并将识别所得的车牌号码实时传输至手机APP。车牌识别技术方面,借助了百度提供的OCR(光学字符识别)服务来确保准确高效地读取车牌数据。同时,手机APP则是采用Java编程语言进行开发,可以便捷地接收和查看识别结果。

一、车牌识别的实现方法

1、车牌识别平台简介

本次车牌识别的实现方案是通过百度智能云平台进行实现,具体实现方法如下:

进入百度智能云网页- > 选择文字识别 - > 车牌识别

图片

图片

进入车牌识别页面之后可通过阅读技术文档来学习车牌识别的使用方法。

2、安装 OpenSSL

因为百度智能云是通过libcurl的https进行访问,而https的访问需要openSSL的支持,所以先编译OpenSSL。

wget https://www.openssl.org/source/openssl-1.1.1a.tar.gz
tar xvf openssl-1.1.1a.tar.gz
./config
make
sudo make install

3、安装curl

wget https://curl.se/download/curl-7.71.1.tar.bz2
tar -xjf curl-7.71.1.tar.bz2
cd curl-7.71.1/
./configure --prefix=$PWD/_INSTALL_ARM --host=arm-linux-gnueabihf --with-openssl
#./configure --prefix=$PWD/_INSTALL_GCC --with-openssl 为了在本地运行用GCC编译
make 
make install

4、车牌识别过程

(在做本次步骤之前请先去阅读百度智能云车牌识别的使用方法)

在本地实现之前可通过平台提供的在线验证方法进行验证,如下图,需要在旁边输入access_token(通过阅读文档可知怎么获取)和一张车牌图片的base64 编码的字符串即可进行在线识别。

图片

本地实现车牌识别的方法需要将识别代码拷贝到本地,并需要实现一个将图片转换为base64编码的函数,详细代码如下: 

#include <stdio.h>
#include <iostream>
#include <string.h>
#include <curl/curl.h>
#include <json/json.h>
#include <fstream>
#include <memory>
#include <cstdlib>
#include <regex>
#include <string>
#include <unistd.h>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;
}std::string getFileBase64Content(const char * path,  bool urlencoded=false)
{const std::string base64_chars ="ABCDEFGHIJKLMNOPQRSTUVWXYZ""abcdefghijklmnopqrstuvwxyz""0123456789+/";std::string ret;int i = 0;int j = 0;unsigned char char_array_3[3];unsigned char char_array_4[4];unsigned int bufferSize = 1024;unsigned char buffer[bufferSize];std::ifstream file_read;file_read.open(path, std::ios::binary);while (!file_read.eof()){file_read.read((char *) buffer, bufferSize * sizeof(char));int num = file_read.gcount();int m = 0;while (num--){char_array_3[i++] = buffer[m++];if(i == 3){char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);char_array_4[3] = char_array_3[2] & 0x3f;for(i = 0; (i <4) ; i++)ret += base64_chars[char_array_4[i]];i = 0;}}}file_read.close();if(i){for(j = i; j < 3; j++)char_array_3[j] = '\0';char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);char_array_4[3] = char_array_3[2] & 0x3f;for(j = 0; (j < i + 1); j++)ret += base64_chars[char_array_4[j]];while((i++ < 3))ret += '=';}if (urlencoded)ret = curl_escape(ret.c_str(), ret.length());return ret;
}std::string performCurlRequest(const char *pic_path, const std::string &token) {std::string result;char *web_curl = nullptr;CURL *curl = curl_easy_init();CURLcode res;if (!asprintf(&web_curl, "https://aip.baidubce.com/rest/2.0/ocr/v1/license_plate?access_token=%s", token.c_str())) {perror("asprintf error");}if (curl) {curl_easy_setopt(curl, CURLOPT_CUSTOMREQUEST, "POST");curl_easy_setopt(curl, CURLOPT_URL, web_curl);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/x-www-form-urlencoded");headers = curl_slist_append(headers, "Accept: application/json");curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headers);std::string base64_image = getFileBase64Content(pic_path, true);std::string post_data = "image=" + base64_image + "&multi_detect=false&multi_scale=false";curl_easy_setopt(curl, CURLOPT_POSTFIELDS, post_data.c_str());curl_easy_setopt(curl, CURLOPT_WRITEDATA, &result);curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, onWriteData);if(curl_easy_perform(curl) != CURLE_OK)fprintf(stderr, "Curl request failed: %s\n", curl_easy_strerror(res));}curl_easy_cleanup(curl);free(web_curl);return result;
}int main(int argc, char *argv[]) {std::string access_token = "填自己的access_tocken";std::string result = performCurlRequest("./车牌图片.jpg", access_token);std::cout << result << std::endl;std::string json = result;std::regex pattern("\"number\":\"(.*?)\"");std::smatch match;if (std::regex_search(json, match, pattern)) {std::cout << "read car number is:" << match[1].str() << std::endl;}return 0;
}

编译

gcc demoCar.c -I ./curl-7.71.1/_INSTALL_GCC/include/ -L ./curl-7.71.1/_INSTALL_GCC/lib/ -l curl

编译完成将文件通过scp拷贝到ELF 1开发板进行运行即可,这样就可以将本地的车牌图片通过HTTPS发送到百度智能云进行识别,并将识别结果返回完成车牌识别。

注意:这里运行时可能会出现CA证书验证失败

root@ELF1:~# ./a.out
OK:60

只需运行 date  --s="2024-01-12 21:40:00" 将时间设置正确即可。

二、移植 mjpg-streamer

在前面一个章节实现了对本地车牌图片的的识别,那如果需要通过摄像头进行车牌识别就需要借助 mjpg-streamer来实现,采用USB摄像头进行识别。

关于什么是 mjpg-streamer 我这里就不在解释,大家可以自行查阅资料进行了解,这里只介绍一下 mjpg-streamer 移植到 ELF 1开发板的过程。

1、编译 jpeg 

(1) 下载 jpeg 源码压缩包

网址:http://www.ijg.org/files/

(2) tar -xvf jpegsrc.v8b.tar.gz

(3) 编译配置

cd jpeg-8d
./configure --prefix=$PWD/_INSTALL --host=arm-linux-gnueabihf
make -j8
make install

2、编译 mjpg-streamer

(1) 下载 mjpg-streamer 源码包

网址:https://sourceforge.net/projects/mjpg-streamer/

svn checkout https://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code

(2)tar -xvf mjpg-streamer.tar.gz

(3)配置

cd mjpg-streamer-code/mjpg-streamer/plugins/input_uvc
vim Makefile

打开 Makefile 文件按照下图进行修改:

图片

(4)编译 mjpg-streamer

因为mjpg-streamer默认是用GCC进行编译,所以要先将GCC改成自己的交叉编译工具,先安装需要用到的库。

sudo apt install graphicsmagick-imagemagick-compat
sudo apt install imagemagick-6.q16
sudo apt install imagemagick-6.q16hdri

更改GCC有两种方法:

方法一:

cd ~/mjpg-streamer-code/mjpg-streamer
make CC=arm-linux-gnueabihf-gcc

方法二:

find -name "Makefile" -exec sed -i "s/CC = gcc/CC = arm-linux-gnueabihf-gcc/g" {} \;
grep "arm-linux-gnueabihf-gcc" * -nR

搜索当前目录及其子目录下的所有Makefile文件,并将Makefile里的CC变量设置为arm-linux-gnueabihf-gcc。(注:arm-linux-gnueabihf-gcc 需要换成自己的交叉编译工具。)

如下图所示所有目录下的Makefile中的CC都等于设置的交叉编译工具。

图片

做完上面这些步骤之后编译代码:

make -j8

编译完成后会生成下图文件 :

图片

.so :动态库

mjpg_streamer:提供可执行命令

www:摄像头输出的网页

(5)移植到ELF 1开发板

scp -r mjpg-streamer/ root@192.168.0.106:~

(6)验证功能

登录ELF 1开发板,运行mjpg_streamer

cd mjpg-streamer
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/mjpg-streamer./mjpg_streamer

图片

当开发板运行mjpg_streamer成功后,在浏览器中输入开发板的IP地址和8080端口号,比如我的是192.168.0.106:8080,点击Stream选项就会出现摄像头中的实时画面,如下图所示。                                                  

图片

                                                                                                       

这样就完成了mjpg_streamer 的移植,后续就可以mjpg_streamer实现一些具体的需求,比如打开摄像头视频:

 mjpg_streamer -i "input_uvc.so -d /dev/video2 -f 30 -q 90 -n" -o "output_http.so -w /opt/www"

截取摄像头中的画面:

wget http://192.168.0.106:8080/?action=snapshot -O ./1.jpg

在这里就可以和前面车牌识别结合起来了,比如摄像头里面的画面是一张车牌信息,通过截取摄像头中的实时画面到本地,然后上传到百度智能云的后台进行识别,至此就完成通过摄像头进行车牌识别。         

三、Android APP的实现

Android APP 的实现很简单,主要功能就是将识别成功的车牌号在APP上面显示。具体的实现方法是当ELF 1开发板成功识别车牌后,通过 Socket 将车牌发送到 Android APP 上面即可。由于这部分代码比较简单,大致如下。

1、Android 端XML代码实现

<Buttonandroid:id="@+id/Z"android:layout_width="match_parent"android:layout_height="wrap_content"android:text="license plate number"android:onClick="sendMessage"android:textColor="#ffffff"android:name=".MainActivity"/>
<TextViewandroid:id="@+id/text"android:layout_width="wrap_content"android:layout_height="wrap_content"android:textSize="30dp"android:textColor="#ffffff"android:layout_centerInParent="true"/>

XML 这部分只实现了两个功能,Button 用来显示车牌号的提示,TextView用来显示识别的车牌号。

2、Android端Socket实现

private Handler handler;
private TextView textView;@Override
protected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);textView = findViewById(R.id.text);handler = new Handler(Looper.getMainLooper()) {@Overridepublic void handleMessage(Message msg) {super.handleMessage(msg);Bundle bundle = msg.getData();String receivedMessage = bundle.getString("msg");textView.setText(receivedMessage);}};
}new Thread(new Runnable() {@Overridepublic void run() {try {Socket client = new Socket("192.168.0.104", 8374);InputStream inputStream = client.getInputStream();while (true) {byte[] data = new byte[128];int len = inputStream.read(data);if (len > 0) {String str = new String(data, 0, len);Message message = new Message();Bundle bundle = new Bundle();bundle.putString("msg", str);message.setData(bundle);}}} catch (IOException e) {e.printStackTrace();}
}).start();

上面这段代码就实现了通过Socket接收来自开发板的车牌数据并将显示到TextView。

3、ELF 1开发板端实现

开发板端主要就是将识别成功的车牌号码通过Socket发送到 Android APP上面,代码如下:

int main(int argc, char *argv[]) {int sockfd = socket(AF_INET, SOCK_STREAM, 0);if (sockfd < 0) {std::cerr << "Error creating socket" << std::endl;return 1;}struct sockaddr_in serv_addr;serv_addr.sin_family = AF_INET;serv_addr.sin_addr.s_addr = inet_addr("192.168.0.104");serv_addr.sin_port = htons(8374);if (bind(sockfd, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0)return 1;if (listen(sockfd, 5) < 0)return 1;struct sockaddr_in cli_addr;socklen_t clilen = sizeof(cli_addr);int newsockfd = accept(sockfd, (struct sockaddr*)&cli_addr, &clilen);if (newsockfd < 0)std::cerr << "Accept failed" << std::endl;const char* reply = match[1].str().c_str();int bytes_sent = send(newsockfd, reply, strlen(reply), 0);if (bytes_sent < 0)std::cerr << "Error sending data" << std::endl;close(newsockfd);close(sockfd);return 0;
}

Android APP 部分就介绍结束,具体的运行界面效果如下图所示:

图片

四、总结

整个项目的识别过程如下图所示,首先运行程序,启动摄像头运行,然后会获取摄像头中的实时画面进行识别,识别成功就会将车牌的关键字检索出来上传到手机APP上面,这就是整个项目的关键运行流程。

图片

(上述全部内容由ElfBoard的共创官提供,所有分享内容仅供学习交流使用,严禁任何商业用途。)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/2814648.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

Java+SpringBoot+Vue+MySQL:狱内罪犯危险性评估系统全栈开发

✍✍计算机毕业编程指导师 ⭐⭐个人介绍&#xff1a;自己非常喜欢研究技术问题&#xff01;专业做Java、Python、微信小程序、安卓、大数据、爬虫、Golang、大屏等实战项目。 ⛽⛽实战项目&#xff1a;有源码或者技术上的问题欢迎在评论区一起讨论交流&#xff01; ⚡⚡ Java、…

postman访问k8s api

第一种方式&#xff1a; kubectl -n kubesphere-system get sa kubesphere -oyaml apiVersion: v1 kind: ServiceAccount metadata:annotations:meta.helm.sh/release-name: ks-coremeta.helm.sh/release-namespace: kubesphere-systemcreationTimestamp: "2023-07-24T07…

vue2后台管理系统demo,包含增删查改、模糊搜索、分页

因一直敲小程序&#xff0c;vue不熟练&#xff0c;自己练手项目&#xff0c;就包含增删查改以及模糊搜索分页 一、页面简单但功能齐全 二、数据是mock模拟 三、启动步骤 1、 json-server --watch data.json 启动mock数据 2、npm i 下载依赖 3、npm run serve 四、github地址…

最新IE跳转Edge浏览器解决办法(2024.2.26)

最新IE跳转Edge浏览器解决办法&#xff08;2024.2.26&#xff09; 1. IE跳转原因1.1. 原先解决办法1.2. 最新解决办法1.3. 最后 1. IE跳转原因 关于IE跳转问题是由于在2023年2月14日&#xff0c;微软正式告别IE浏览器&#xff0c;导致很多使用Windows10系统的电脑在打开IE浏览…

PHP请求示例获取淘宝商品详情数据API接口(按关键词搜索商品列表)

请求示例&#xff0c;API接口接入Anzexi58 item_get-获得淘宝商品详情 taobao.item_get 公共参数 名称类型必须描述keyString是调用key&#xff08;必须以GET方式拼接在URL中&#xff09;secretString是调用密钥WeChat18305163218api_nameString是API接口名称&#xff08;包…

存储卡0字节危机:原因解析与数据拯救之道

存储卡0字节现象揭秘 在数字时代&#xff0c;存储卡作为我们存储重要数据的主要工具之一&#xff0c;一旦遭遇“0字节”的困境&#xff0c;无疑是一场数据灾难。所谓存储卡0字节&#xff0c;即存储卡的文件系统显示容量为0&#xff0c;所有文件仿佛凭空消失&#xff0c;用户无…

Ubuntu服务器fail2ban的使用

作用&#xff1a;限制ssh远程登录&#xff0c;防止被人爆破服务器&#xff0c;封禁登录ip 使用lastb命令可查看到登录失败的用户及ip&#xff0c;无时无刻的不在爆破服务器 目录 一、安装fail2ban 二&#xff0c;配置fail2ban封禁ip的规则 1&#xff0c;进入目录并创建ssh…

在TMP中计算书名号《》高度的问题

1&#xff09;在TMP中计算书名号《》高度的问题 2&#xff09;FMOD设置中关于Virtual Channel Count&Real Channel Count的参数疑问 3&#xff09;Unity 2021.3.18f1 ParticleSystemTrailGeometryJob粒子拖尾系统崩溃 4&#xff09;XLua打包Lua文件粒度问题 这是第375篇UWA…

Simulink搭建一阶低通数字滤波器(设定X(n)为非0起始值)

一、一阶低通数字滤波器原理 一阶滤波&#xff0c;亦称一阶惯性滤波或一阶低通滤波。其数学表达式如下&#xff1a; 其中&#xff1a;α代表滤波系数&#xff1b;X(n)表示本次采样值&#xff1b;Y(n-1) 为上次滤波输出值&#xff1b;Y(n) 为本次滤波输出值。一阶低通滤波方法通…

让两个电脑通信的方法(TCP连接,UDP连接,C/S架构)

目录 TCP-面向连接UDP-面向无连接C/S架构服务器和客户端的工作过程C/S架构例子 让两个电脑通信的方法是 在C/S的基础上&#xff0c;采用TCP和UDP的方式连接 TCP-面向连接 UDP-面向无连接 C/S架构 服务器和客户端的工作过程 C/S架构例子 服务器与客户端通信的过程类似公司与客户…

http模块-通过创建的服务器将本地文件转换成web资源

案例-通过创建的服务器将本地文件转换成web资源 目的&#xff1a;将本地文件转换成web资源思路&#xff1a;将文件实际存放的地址作为每个资源的请求url地址。大致流程&#xff1a; 浏览器–请求->自己写的web服务器–读文件->磁盘目录–读取完毕->自己写的web服务器…

WinForms中的Timer探究:Form Timer与Thread Timer的差异

WinForms中的Timer探究&#xff1a;Form Timer与Thread Timer的差异 在Windows Forms&#xff08;WinForms&#xff09;应用程序开发中&#xff0c;定时器&#xff08;Timer&#xff09;是一个常用的组件&#xff0c;它允许我们执行定时任务&#xff0c;如界面更新、周期性数据…

Python实现自动检测设备连通性并发送告警到企业微信

背景&#xff1a;门禁机器使用的WiFi连接&#xff0c;因为某些原因会不定期自动断开连接&#xff0c;需要人工及时干预&#xff0c;以免影响门禁数据同步&#xff0c;故写此脚本&#xff0c;定时检测门禁网络联通性。 #首次使用要安装tcping模块 pip install tcpingfrom tcpin…

vue3第三节(v-model 执行原理)

特殊说明&#xff1a; 以下vue3语法是基于 3.4之前版本进行使用的&#xff0c;3.4之后的版本 引入了 defineModel 宏&#xff0c;后续会介绍defineModel 1、vue3 与vue2 中v-model区别 vue3 中v-model绑定的不再是value&#xff0c;而是modelValue&#xff0c;接收的方法也不再…

【Python_Zebra斑马打印机编程学习笔记(三)】解决ZPL指令无法显示中文的问题

解决ZPL指令无法显示中文的问题 解决ZPL指令无法显示中文的问题前言一、问题描述二、字符集、码表文件、字库文件1、字符集2、码表文件3、字库文件 三、两种设置中文字体的方式1、通过设置字符集、码表文件、字库文件改变默认字体2、通过^CF指令设置标准字体名称改变默认字体 解…

计讯物联5G RedCap网关TG463化繁为简,推动5G赋能千行百业

5G RedCap&#xff0c;全称为Reduced Capability&#xff0c;即在5G的基础上&#xff0c;对部分功能进行化繁为简后形成的新技术标准&#xff0c;故又称轻量化5G。作为高性价比下的精简技术&#xff0c;5G RedCap技术具备成本低、低功耗、兼顾5G等特点&#xff0c;能够在确保应…

ai电话机器人真的有那么好用吗?不需要神话它各版本搭建

如果您在互联网上搜索“电话机器人”&#xff0c;您会发现各种各样的电话机器人品牌&#xff0c;但功能描述&#xff0c;操作背景等等都会给您几乎相同的感受。无非就是代替人工打电话然后大规模的外拨电话&#xff0c;对目标客户的有效筛选等等。我们来看看机器人还不好用&…

论文设计任务书学习文档|基于Java的超市管理系统的设计与实现

文章目录 论文(设计)题目:基于Java的超市管理系统的设计与实现1、论文(设计)的主要任务及目标2、论文(设计)的主要内容3、论文(设计)的基本要求4、进度安排论文(设计)题目:基于Java的超市管理系统的设计与实现 1、论文(设计)的主要任务及目标 基于Java的超市管…

搭建sql-labs-master

环境&#xff1a;win10 解压sql-labs-master靶场文件&#xff0c;会提示有重复&#xff0c;直接覆盖就好。 将sql-labs-master文件拖到phpstudy/www目录下 打开浏览器访问“本机ip/sql-labs-master或localhost/sql-labs-master或127.0.0.1/sql-labs-master” 页面底部就是此靶…

Swagger接口文档管理工具

Swagger 1、Swagger1.1 swagger介绍1.2 项目集成swagger流程1.3 项目集成swagger 2、knife4j2.1 knife4j介绍2.2 项目集成knife4j 1、Swagger 1.1 swagger介绍 官网&#xff1a;https://swagger.io/ Swagger 是一个规范和完整的Web API框架&#xff0c;用于生成、描述、调用和…