基于ELFBoard开发板的车牌识别系统

本项目采用的是ElfBoard ELF1开发板作为项目的核心板主要实现的功能为通过USB 摄像头对车牌进行识别,如果识别成功则会亮绿灯,并将识别的车牌号上传到手机APP上面,车牌识别的实现是通过百度OCR进行实现,手机APP是用Java语言进行编写。

有关ElfBoard 相关的介绍大家可以点击:https://www.elfboard.com/

一、车牌识别的实现方法

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拷贝到开发板,进行运行即可,这样就可以将本地的车牌图片通过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 移植到 elfboard 过程。

1、编译 jpeg 

(1) 下载 jpeg 源码压缩包,网址:jpeg

(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 源码包,网址: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)移植到elfboard开发板

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

我这里是将 mjpg-streamer 整个文件夹拷贝到开发板,当然也可以将对应的文件拷贝到开发板对应的目录,具体看自己实现。

(6)验证功能

登录开发板,运行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上面显示。具体的实现方法是当开发板成功识别车牌后,通过 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、开发板端实现

开发板端主要就是将识别成功的车牌号码通过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;
}

上面这段代码就是SocketClient 端,将识别的车牌信息发送到手机APP进行显示。

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

四、总结

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

写到这里整个车牌识别的项目就算介绍结束了,实现的功能很有限,但总的来说我对这块Elfboard开发板的体验还是非常好的。首先是板子的资料很多也很全面,还有官方的视频教程,对于新手来说还是非常友好的,容易上手;其次是板子集成有很多的外设资源,比如WiFi、蓝牙、蜂鸣器、温湿度传感器、加速度传感器等等,这样就不需要自己去接线控制,非常的方便;最后我希望在后续的学习中继续使用Elfboard开发板,实现更多的功能。

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

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

相关文章

五种多目标优化算法(MOCS、MOFA、NSWOA、MOAHA、MOPSO)性能对比(提供MATLAB代码)

一、5种多目标优化算法简介 多目标优化算法是用于解决具有多个目标函数的优化问题的一类算法。其求解流程通常包括以下几个步骤&#xff1a; 1. 定义问题&#xff1a;首先需要明确问题的目标函数和约束条件。多目标优化问题通常涉及多个目标函数&#xff0c;这些目标函数可能…

Linux基础命令—系统服务

基础知识 centos系统的开机流程 1)通电 2)BIOS硬件检查 3)MBR引导记录 mbr的引导程序 加载引导程序 让硬件加载操作系统内核 MBR在第一个磁盘第一个扇区 总大小512字节 mbr: 1.引导程序: 占用446字节用于引导硬件,加载引导程序 2.分区表: 总共占…

数学建模【插值与拟合】

一、插值与拟合简介 在数学建模过程中&#xff0c;通常要处理由试验、测量得到的大量数据或一些过于复杂而不便于计算的函数表达式&#xff0c;针对此情况&#xff0c;很自然的想法就是&#xff0c;构造一个简单的函数作为要考察数据或复杂函数的近似。插值和拟合就可以解决这…

GitHub上的GCN

在GitHub上下载GCN代码&#xff0c;可以跑通 https://github.com/tkipf/pygcn

【精简版】Ubuntu/Linux Anaconda 命令行终端安装

网上重复内容很多&#xff0c;大都啰里啰嗦&#xff0c;特作此笔记。 【精简版】Ubuntu/Linux Anaconda 命令行安装 1 下载安装包1.1 寻找适配版本安装包1.2 下载 2 运行安装程序3 设置安装路径4 添加环境变量并运行4.1 环境变量4.2 运行 5 验证安装成功感谢及参考博文 1 下载…

【设计模式】5种创建型模式详解

创建型模式提供创建对象的机制,能够提升已有代码的灵活性和复用性。 常用的有:单例模式、工厂模式(工厂方法和抽象工厂)、建造者模式。不常用的有:原型模式。一、单例模式 1.1 单例模式介绍 1 ) 定义 单例模式(Singleton Pattern)是 Java 中最简单的设计模式之一,此模…

自定义搭建管理系统

最近使用自己搭建的脚手架写了一个简易管理系统&#xff0c;使用webpackreactantd&#xff0c;搭建脚手架参考&#xff1a; 使用Webpack5搭建项目&#xff08;react篇&#xff09;_babel-preset-react-app-CSDN博客 搭建的思路&#xff1a; 1. 基建布局&#xff0c;使用antd的…

Spring ReflectionUtils 反射工具介绍和使用

一、ReflectionUtils 在 Java 中&#xff0c;反射&#xff08;Reflection&#xff09;是一种强大的机制&#xff0c;允许程序在运行时动态地检查类、获取类的信息、调用类的方法、访问或修改类的属性等。Java 的反射机制提供了一组类和接口&#xff0c;位于 java.lang.reflect…

光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测

光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测 目录 光伏预测 | Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测预测效果基本描述模型简介程序设计参考资料 预测效果 基本描述 Matlab基于CNN-SE-Attention-ITCN的多特征变量光伏预测 运行环境: Matla…

轻量级模型,重量级性能,TinyLlama、LiteLlama小模型火起来了,针对特定领域较小的语言模型是否与较大的模型同样有效?

轻量级模型&#xff0c;重量级性能&#xff0c;TinyLlama、LiteLlama小模型火起来了&#xff0c;针对特定领域较小的语言模型是否与较大的模型同样有效? 当大家都在研究大模型&#xff08;LLM&#xff09;参数规模达到百亿甚至千亿级别的同时&#xff0c;小巧且兼具高性能的小…

多目标追踪概述

1. 目标跟踪分类 单目标跟踪&#xff1a;在视频的初始帧画面上框出单个目标&#xff0c;预测后续帧中该目标的大小与位置多目标跟踪&#xff1a;追踪多个目标的大小和位置&#xff0c;且每一帧中目标的数量和位置都可能变化 2. 多目标跟踪目前的主要问题 形态变化&#xff1a…

Android 获取USB相机支持的分辨率有多少

直接上代码 private fun getCamera() {// 获取系统相机服务val cameraManager requireContext().getSystemService(Context.CAMERA_SERVICE) as? CameraManagerif (cameraManager ! null) {// 在这里进行相机管理器的操作// 获取相机设备的 ID&#xff08;这里假设使用第一个相…

小封装高稳定性振荡器新系列(2.0 x 1.6 mm) 用于光学应用

小封装高稳定性振荡器新系列(2.0 x 1.6 mm) 用于光学应用&#xff0c;兼容OIF标准 Sg2016egn / sg2016vgn, sg2016ehn / sg2016vhn 来自光模块市场的需求爱普生提供SG2016系列解决方案SG2016系列:高稳定性&#xff0c;低抖动晶体振荡器规格尺寸&#xff0c;框图&#xff0c;引…

Java零基础 - 关键字 instanceof

哈喽&#xff0c;各位小伙伴们&#xff0c;你们好呀&#xff0c;我是喵手。 今天我要给大家分享一些自己日常学习到的一些知识点&#xff0c;并以文字的形式跟大家一起交流&#xff0c;互相学习&#xff0c;一个人虽可以走的更快&#xff0c;但一群人可以走的更远。 我是一名后…

无限创意之旅:深度挖掘Sora AI视频模型的可能性【文章底部添加可得内推码汇总表】

目录 引言 第一部分&#xff1a;Sora AI视频模型的特性 第二部分&#xff1a;Sora在创意领域的应用 第三部分&#xff1a;Sora对影视产业的影响 【文章底部添加可得内推码汇总表】 引言 21世纪&#xff0c;随着AI人工智能的迅猛发展&#xff0c;AI视频模型正成为数字创意领…

17.材质和外观

1.图形学中的材质 在图形学中&#xff0c;材质&#xff08;Material&#xff09;是用来描述物体外观和表面特性的属性集合。它包含了控制光的反射、折射、吸收以及其他光学效果的信息&#xff0c;从而决定了物体在渲染过程中的外观。 渲染方程中那一项和材质有关&#xff1f; …

HSE化工应急安全生产管理平台:信息化、流程化的安全管理新模式

随着化工行业的快速发展&#xff0c;安全生产管理日益成为企业发展的关键所在。在这一背景下&#xff0c;HSE化工应急安全生产管理平台应运而生&#xff0c;以信息平台为载体&#xff0c;数据驱动、风险管理为中心&#xff0c;致力于实现安全生产的动态、实时和智能化管理。本文…

【工具分享】批量查找文件并移动复制,咕嘎批量文件清单快速查找搜索文件,比bat批量查找文件并复制更简单一些

在工作中&#xff0c;像电商或者照相馆以及政府工程的工作人员&#xff0c;整理文件时&#xff0c;我们经常遇到批量查找部分文件&#xff0c;比如在10万个文件内查找5000个文件&#xff0c;把5000个文件分离出来&#xff0c;存在另外一个地方 如果是在电脑中挨个搜那要搜很久&…

客户至上!CRM系统如何助力企业提升客户满意度?

产品复购率是企业经营中的重要指标。要提升产品的复购率&#xff0c;除了产品质量需要过硬&#xff0c;客户服务的质量和效率也是重要影响因素&#xff0c;而CRM管理系统能够帮助达成这一点。 我们将通过这篇文章讲解CRM系统为何能提高客户满意度。 1.协助掌握客户的需要 企业…

【小尘送书-第十四期】《高效使用Redis:一书学透数据存储与高可用集群》

大家好&#xff0c;我是小尘&#xff0c;欢迎你的关注&#xff01;大家可以一起交流学习&#xff01;欢迎大家在CSDN后台私信我&#xff01;一起讨论学习&#xff0c;讨论如何找到满意的工作&#xff01; &#x1f468;‍&#x1f4bb;博主主页&#xff1a;小尘要自信 &#x1…