ElfBoard开源项目|基于百度智能云平台的车牌识别项目

本项目基于百度智能云平台,旨在利用其强大的OCR服务实现车牌号码的自动识别。选择百度智能云的原因是其高效的API接口和稳定的服务质量,能够帮助开发者快速实现车牌识别应用。

本项目使用摄像头捕捉图像后,通过集成百度OCR服务的API,能够轻松识别图像中的车牌号码,并将识别结果实时显示在Qt界面上。

功能特性

1.图片处理和OCR识别:使用百度OCR服务,能够通过API轻松识别图片中的车牌号码。

2.摄像头实时采集图像并保存:使用Qt设计了直观的用户界面,控制USB摄像头的打开、关闭以及实时显示摄像头捕获的视频流,并将采集到的视频流保存为图像。

环境说明

1、开发环境操作系统:Ubuntu18.04 64位版

2、交叉编译工具链:arm-poky-linux-gnueabi-gcc 5.3.0

3、开发板使用Bootloader版本:u-boot-2016.03

4、开发板内核版本:linux-4.1.15

5、开发板移植QT版本:qt5.6.2

图片处理和OCR识别

百度智能云网址:百度智能云-云智一体深入产业 (baidu.com)

本次车牌识别的方案是通过百度智能云平台进行实现的。首先进入百度智能云网页- > 选择文字识别 - > 车牌识别。

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

1、在线识别车牌图片

在本地实现之前可通过平台提供的在线验证方法进行验证,如下图,需要在旁边输入一张车牌图片的base64 编码的字符串或者选择上传一张车牌图片,即可进行在线识别。

视频教程:百度智能云-车牌识别API接口的使用方法 (baidu.com)

2、识别本地车牌图片

本地实现车牌识别的方法需要将识别代码拷贝到本地,并需要实现一个将图片转换为base64编码的函数。需要输入自己的access_token(通过阅读文档可知怎么获取)。

#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");}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");curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);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);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, false);curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);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 = "24.d69c300e601a1d2e3f735d916d45eb5a.2592000.1724636199.282335-99367601";  //填自己的access_tockenstd::string result;std::string car_number;result = performCurlRequest("/home/root/num/1.jpg", access_token); //存放图片的路径std::string json = result;std::regex pattern("\"number\":\"(.*?)\"");std::smatch match;if (std::regex_search(json, match, pattern)) {car_number = match[1].str();std::cout << "read car number is: " << car_number << std::endl;}
}

依赖库编译

编译车牌识别的应用需要依赖Curl库、OpenSSL库、OpenCv库、JsonCPP库。详细的依赖库安装步骤请参考以下链接:

交叉编译Curlicon-default.png?t=O83Ahttps://bbs.elfboard.com/forum.php?mod=viewthread&tid=496&extra=page%3D1

交叉编译OpenSSLicon-default.png?t=O83Ahttps://bbs.elfboard.com/forum.php?mod=viewthread&tid=495&extra=page%3D1

交叉编译OpenCvicon-default.png?t=O83Ahttps://bbs.elfboard.com/forum.php?mod=viewthread&tid=497&extra=page%3D1

交叉编译JsonCppicon-default.png?t=O83Ahttps://bbs.elfboard.com/forum.php?mod=viewthread&tid=498&extra=page%3D1

应用编译

elf@ubuntu:~/work$  . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi 
elf@ubuntu:~/work$  $CXX demoCar.cpp -o demoCar -I /home/elf/work/curl-7.71.1/install/include/ -I /home/elf/work/jsoncpp-1.9.5/install/include/ -I /home/elf/work/opencv-3.4.1/install/include/ -std=c++11 -L /home/elf/work/curl-7.71.1/install/lib/ -L /home/elf/work/jsoncpp-1.9.5/install/lib/ -L /home/elf/work/opencv-3.4.1/install/lib/ -lopencv_core -lopencv_highgui -lopencv_imgproc -lopencv_videoio -lopencv_imgcodecs -lcurl

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

摄像头实时采集图像并保存

程序设计

在前面一个章节实现了对本地车牌图片的识别,下面来介绍如何通过摄像头进行车牌识别,采用USB摄像头进行识别,程序设计如下图所示。

主函数的实现main.cpp

int main(int argc, char *argv[])  
{  QApplication a(argc, argv);  Camera w;  w.setWindowFlags(w.windowFlags()& ~Qt::WindowMaximizeButtonHint& ~Qt::WindowMinimizeButtonHint );  w.showMaximized();  w.show();  return a.exec();  
}  

设置UI

ui->setupUi(this);  timer = new QTimer;  QDesktopWidget* desktopWidget = QApplication::desktop();  QRect screenRect = desktopWidget->screenGeometry();  qDebug("screen.width = %d , screen.height = %d",screenRect.width(),screenRect.height());  this->imageWidget = new ImageWidget(this);  this->imageWidget->setBackgroundRole(QPalette::Dark);  this->imageWidget->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);  this->imageWidget->setObjectName(QString::fromUtf8("imageWidget"));  if(screenRect.width()==800)  {  ui->pbt_start->setGeometry(60,300,70,50);  ui->pbt_stop->setGeometry(190,300,70,50);  this->imageWidget->setGeometry(QRect(5, 30, 350, 250));  }  else if(screenRect.width()>800)  {  ui->pbt_start->setGeometry(80,400,70,70);  ui->pbt_stop->setGeometry(260,400,70,70);  this->imageWidget->setGeometry(QRect(6, 37, 500, 330));  }  

打开摄像头设备

void deviceOpen(void)  
{  fd = open(deviceName, O_RDWR | O_NONBLOCK, 0);  if (-1 == fd)  {  QMessageBox::about(NULL, "About", "camera open error");  exit(EXIT_FAILURE);  }  
}   

初始化摄像头设备

void deviceInit(void)  
{  struct v4l2_capability cap;  struct v4l2_cropcap cropcap;  struct v4l2_crop crop;  struct v4l2_format fmt;  struct v4l2_streamparm sparm;  unsigned int min;  if (-1 == xioctl(fd, VIDIOC_QUERYCAP, &cap))  {  if (EINVAL == errno)  {  QMessageBox::about(NULL,"Information"," no V4L2 device");  exit(EXIT_FAILURE);  }  else  {  errno_exit("VIDIOC_QUERYCAP");  }  }  if (!(cap.capabilities & V4L2_CAP_VIDEO_CAPTURE))  {  QMessageBox::about(NULL,"Information"," no video capture device");  exit(EXIT_FAILURE);  }  struct v4l2_input input;  input.index = 0;  if ( ioctl(fd, VIDIOC_ENUMINPUT, &input) != 0)  {  QMessageBox::about(NULL,"Information","set input error");  exit(0);  }  if ((ioctl(fd, VIDIOC_S_INPUT, &input)) < 0)  {  QMessageBox::about(NULL,"Information","set s_input error");  exit(0);  }  CLEAR(cropcap);  cropcap.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  if (0 == xioctl(fd, VIDIOC_CROPCAP, &cropcap))  {  crop.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  crop.c.top = 0;  crop.c.left = 0;  crop.c.height = 720;  crop.c.width = 1280;  if (-1 == xioctl(fd, VIDIOC_S_CROP, &crop))  {  switch (errno)  {  case EINVAL:  break;  default:  break;  }  }  }  CLEAR (fmt);  // v4l2_format  fmt.type                = V4L2_BUF_TYPE_VIDEO_CAPTURE;  fmt.fmt.pix.width       = width;  fmt.fmt.pix.height      = height;  fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;  fmt.fmt.pix.field       = V4L2_FIELD_ANY;  if (-1 == xioctl(fd, VIDIOC_S_FMT, &fmt))  errno_exit("VIDIOC_S_FMT");  /* Note VIDIOC_S_FMT may change width and height.*/  if (width != fmt.fmt.pix.width)  {  width = fmt.fmt.pix.width;  //fprintf(stderr,"Image width set to %i by device %s.\n",width,deviceName);  }  if (height != fmt.fmt.pix.height)  {  height = fmt.fmt.pix.height;  //fprintf(stderr,"Image height set to %i by device %s.\n",height,deviceName);  }  /*Buggy driver paranoia. */  min = fmt.fmt.pix.width * 2;  if (fmt.fmt.pix.bytesperline < min)  fmt.fmt.pix.bytesperline = min;  min = fmt.fmt.pix.bytesperline * fmt.fmt.pix.height;  if (fmt.fmt.pix.sizeimage < min)  fmt.fmt.pix.sizeimage = min;  CLEAR (sparm);  sparm.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  sparm.parm.capture.capturemode = 0;  sparm.parm.capture.timeperframe.numerator = 1;  sparm.parm.capture.timeperframe.denominator = 30;  if(xioctl(fd,VIDIOC_S_PARM,&sparm) < 0){  errno_exit("cam s parm");  // exit(1);  }  mmapInit();  
}  

开启视频流捕获

void captureStart(void)  
{  unsigned int i;  enum v4l2_buf_type type;  for (i = 0; i < n_buffers; ++i)  {  struct v4l2_buffer buf;  CLEAR (buf);  buf.type        = V4L2_BUF_TYPE_VIDEO_CAPTURE;  buf.memory      = V4L2_MEMORY_MMAP;  buf.index       = i;  if (-1 == xioctl(fd, VIDIOC_QBUF, &buf))  errno_exit("VIDIOC_QBUF");  }  type = V4L2_BUF_TYPE_VIDEO_CAPTURE;  if (-1 == xioctl(fd, VIDIOC_STREAMON, &type))  errno_exit("VIDIOC_STREAMON");  
}  

超时处理

void Camera::up_date()  
{  unsigned char image_buf[921600+54];  frameRead(image_buf);  this->imageWidget->setPixmap(image_buf);  
}  

应用编译及测试

编译

elf@ubuntu:~/work/camera-demo$ . /opt/fsl-imx-x11/4.1.15-2.0.0/environment-setup-cortexa7hf-neon-poky-linux-gnueabi 
elf@ubuntu:~/work/camera-demo$ qmake
elf@ubuntu:~/work/camera-demo$ make

拷贝camera-demo到ELF 1开发板的/home/root路径下,运行测试

root@ELF1:~# cp /run/media/sda1/camera-demo ./
root@ELF1:~# chmod 777 camera-demo
root@ELF1:~# export DISPLAY=:0.0
root@ELF1:~# ./camera-demo

点击start按钮之后,使用ls num路径下查看会有摄像头拍摄的图片。液晶屏上会实时预览摄像头拍到的图像,如下图所示:

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

项目测试

在此基础上再次完善应用,识别车牌的应用将识别到的车牌信息保存到文本中,基于摄像头的应用读取文档中的车牌信息显示在Qt界面中。

1、确保开发板已连接USB摄像头和屏幕

2、设置Wi-Fi连接

root@ELF1:~# elf1_cmd_wifi.sh -i 8723 -s 账号 -p 密码

执行应用

root@ELF1:~# ./camera-demo &
root@ELF1:~# ./demoCar

单击“start”按钮,识别结果如下图所示

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

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

相关文章

应对超声波测试挑战,如何选择合适的数字化仪?

一、数字化仪的超声波应用 超声波是频率大于人类听觉范围上限的声学声压&#xff08;声学&#xff09;波。超声波设备的工作频率为20 kHz至几千MHz。表1总结了一些更常见的超声波应用的特征。 每个应用中使用的频率范围都反映了实际情况下的平衡。提高工作频率可以通过提高分…

product/admin/list?page=0size=10field=jancodevalue=4562249292272

文章目录 1、ProductController2、AdminCommonService3、ProductApiService4、ProductCommonService5、ProductSqlService https://api.crossbiog.com/product/admin/list?page0&size10&fieldjancode&value45622492922721、ProductController GetMapping("ad…

博物馆导览系统方案(一)背景需求分析与核心技术实现

维小帮提供多个场所的室内外导航导览方案&#xff0c;如需获取博物馆导览系统解决方案可前往文章最下方获取&#xff0c;如有项目合作及技术交流欢迎私信我们哦~撒花&#xff01; 一、博物馆导览系统的背景与市场需求 在数字化转型的浪潮中&#xff0c;博物馆作为文化传承和知…

Flink学习连载文章11--双流Join

双流 Join 和两个流合并是不一样的 两个流合并&#xff1a;两个流变为 1 个流 union connect 双流 join: 两个流 join&#xff0c;其实这两个流还是原来的&#xff0c;只是满足条件的数据会变为一个新的流。 可以结合 sql 语句中的 union 和 join 的区别。 在离线 Hive 中&…

vue3+wangeditor富文本编辑器详细教程

一、前言 在这篇教程中&#xff0c;我将指导如何使用 Vue 3 和 WangEditor 创建一个功能丰富的富文本编辑器。WangEditor 是一个轻量级的富文本编辑器&#xff0c;它非常适合集成到 Vue 项目中。这个例子展示了如何配置富文本编辑器&#xff0c;包括工具栏、编辑器配置以及如何…

Python学习39天

my_tools.py文件提供工具函数 """ 此文件编写工具函数&#xff0c;供程序员使用 my_tools """def read_confirm_select():"""让用户输入&#xff1a;Y/N&#xff0c;不区分大小写&#xff0c;将用户输入值转为小写返回&#xff…

LCA - Lowest Common Ancestor

LCA - Lowest Common Ancestor https://www.luogu.com.cn/problem/SP14932 题目描述 A tree is an undirected graph in which any two vertices are connected by exactly one simple path. In other words, any connected graph without cycles is a tree. - Wikipedia T…

unity打包web,发送post请求,获取地址栏参数,解决TypeError:s.replaceAll is not a function

发送post请求 public string url "http://XXXXXXXXX";// 请求数据public string postData "{\"user_id\": 1}";// Start is called before the first frame updatevoid Start(){// Post();StartCoroutine(PostRequestCoroutine(url, postData…

恒创科技:如何区分网站的域名主机名

如何区分网站的域名主机名?它们都是网址机制的一部分&#xff0c;当你在地址栏输入它们&#xff0c;就能访问互联网上想去的地方。你可曾思考过主机名和域名的区别呢? 简单来说&#xff0c;域名就像网址&#xff0c;而主机名用于标识网络中的设备。不过&#xff0c;这只是表面…

【技巧学习】ArcGIS如何计算水库库容量?

ArcGIS如何计算水库库容量? 一、数据获取 DEM数据来源于地理空间数据云&#xff0c;该网站是由中科院计算机网络信息中心于2008年创立的地学大数据平台。 二、填洼 将DEM数据中凹陷的区域填充至与倾斜点同样高度&#xff0c;这里的【Z限制】说的是设定一个特定的值&#x…

机器学习——感知机模型

文章目录 前言1.感知机模型介绍1.1基本概念1.2数学表达1.3几何解释1.4优缺点 2.二分类应用2.1应用介绍2.2准备数据集2.2.1环境检查2.2.2数据集介绍2.2.3获取数据2.2.4划分数据集 2.3可视化训练集2.4训练过程2.4.1首轮梯度下降2.4.2多轮梯度下降 2.5可视化分类结果2.6在验证集验…

11.20[JAVAEXP3]重定向细究【DEBUG】

设置了根域名访问为testServlet,让他重定向到首页为test.jsp&#xff0c;事实上也都触发了&#xff0c;但是最后显示的为什么不是test.jsp生成页面&#xff0c;依然还是index.jsp生成的页面&#xff1f;&#xff1f; 重定向是通过Dispatcher进行的&#xff0c;而不是sendRedir…

YOLOv11模型改进-注意力-引入卷积和注意力融合模块(CAFM) 提升小目标和遮挡检测

本篇文章将介绍一个新的改进机制——卷积和注意力融合模块CAFM&#xff0c;并阐述如何将其应用于YOLOv11中&#xff0c;显著提升模型性能。首先&#xff0c;CAFM是为了融合卷积神经网络&#xff08;CNNs&#xff09;和 Transformer 的优势&#xff0c;同时对全局和局部特征进行…

APM装机教程(五):测绘无人船

文章目录 前言一、元生惯导RTK使用二、元厚HXF260测深仪使用三、云卓H2pro遥控器四、海康威视摄像头 前言 船体&#xff1a;超维USV-M1000 飞控&#xff1a;pix6c mini 测深仪&#xff1a;元厚HXF160 RTK&#xff1a;元生惯导RTK 遥控器&#xff1a;云卓H12pro 摄像头&#xf…

基于MinIO打造高可靠分布式“本地”文件系统

MinIO是一款高性能的对象存储服务&#xff0c;而S3协议是由亚马逊Web服务&#xff08;AWS&#xff09;制定的一种标准协议&#xff0c;用于云存储服务之间的数据交换。MinIO与S3协议的关系在于&#xff0c;MinIO实现了S3协议的接口&#xff0c;这意味着用户可以使用与AWS S3相同…

Luma 视频生成 API 对接说明

Luma 视频生成 API 对接说明 随着 AI 的应用变广&#xff0c;各类 AI 程序已逐渐普及。AI 已逐渐深入到人们的工作生活方方面面。而 AI 涉及的行业也越来越多&#xff0c;从最初的写作&#xff0c;到医疗教育&#xff0c;再到现在的视频。 Luma 是一个专业高质量的视频生成平…

基础算法——搜索与图论

搜索与图论 图的存储方式2、最短路问题2.1、Dijkstra算法&#xff08;朴素版&#xff09;2.2、Dijkstra算法&#xff08;堆优化版&#xff09;2.3、Bellman-Ford算法2.4、SPFA求最短路2.5、SPFA判负环2.6、Floyd算法 图的存储方式 2、最短路问题 最短路问题可以分为单源最短路…

Online Monocular Lane Mapping

IROS 2023 港科大 文章链接&#xff1a;http://arxiv.org/abs/2307.11653 github&#xff1a;GitHub - HKUST-Aerial-Robotics/MonoLaneMapping: Online Monocular Lane Mapping Using Catmull-Rom Spline (IROS 2023) 动机 摆脱高精地图&#xff0c;使用车端的传感器来实现车端…

29.两数相除 python

两数相除 题目题目描述示例 1:示例 2:提示&#xff1a;题目链接 题解解题思路python实现代码解释提交结果 题目 题目描述 给你两个整数&#xff0c;被除数 dividend 和除数 divisor。将两数相除&#xff0c;要求 不使用 乘法、除法和取余运算。 整数除法应该向零截断&#x…

MicroBlaze软核开发(二):GPIO

实现功能&#xff1a;使用 MicroBlaze软核&#xff0c;配置GPIO用拨码开关控制LED灯 Vivado版本&#xff1a;2018.3 目录 引言 vivado部分&#xff1a; 一、配置GPIO 二、生成HDL文件编译 SDK部分&#xff1a; 一、导出硬件启动SDK 二、新建应用程序工程 三、编写程序代…