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.rhkb.cn/news/487681.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【51单片机】程序实验1112.外部中断-定时器中断

主要参考学习资料&#xff1a;B站【普中官方】51单片机手把手教学视频 前置知识&#xff1a;C语言 单片机套装&#xff1a;普中STC51单片机开发板A4标准版套餐7 码字不易&#xff0c;求点赞收藏加关注(•ω•̥) 有问题欢迎评论区讨论~ 目录 程序实验11&12.外部中断-定时器…

Linux基础(2)完结

声明 学习视频来自 B 站up主泷羽sec&#xff0c;如有涉及侵权马上删除文章。 在学习的过程中记笔记&#xff0c;分享笔记方便各位师傅学习&#xff0c;以下内容只涉及学习内容&#xff0c;任何其他违法行为与本人及泷羽sec无关&#xff0c;请务必遵守法律法规&#xff0c;切莫逾…

【重生之我在B站学MySQL】

MySQL笔记 文章目录 MySQL的三层结构SQL语句分类sql语句数据库操作创建数据库查看、删除数据库 表操作创建表mysql常用数据类型(列类型)查询表、插入值创建表练习创建一个员工表emp 修改表mysql约束primary key(主键)not null(非空)unique(唯一)foreign key(外键)check自增长 索…

springSecurity自定义登陆接口和JWT认证过滤器

下面我会根据该流程图去自定义接口&#xff1a; 我们需要做的任务有&#xff1a; 登陆&#xff1a;1、通过ProviderManager的方法进行认证&#xff0c;生成jwt&#xff1b;2、把用户信息存入redis&#xff1b;3、自定义UserDetailsService实现到数据库查询数据的方法。 校验&a…

【adb】iqoo系统精简垃圾内置应用

免责声明 这个得谨慎点&#xff0c;虽然我验证过两部手机和不同版本的系统&#xff0c;但是总会有特殊的存在、 本教程来自于互联网搜集整理&#xff0c; 按照本教程造成的用户设备硬件或数据损失&#xff0c;本人概不承担任何责任&#xff0c;如您不同意此协议&#xff0c;请不…

计算机视觉:学习指南

一、引言 计算机视觉作为人工智能领域的一个重要分支&#xff0c;致力于让计算机理解和解释视觉信息&#xff0c;近年来取得了令人瞩目的进展&#xff0c;广泛应用于安防监控、自动驾驶、图像编辑、医学影像分析等众多领域。从入门到精通计算机视觉需要系统地学习一系列知识和…

汽车升级到底应不应该设置“可取消“功能

最近&#xff0c;汽车OTA&#xff08;Over-the-Air&#xff09;升级频频成为车主讨论的热点。有些车主反映&#xff0c;一些升级增加了实用功能&#xff0c;而另一些却让体验变得复杂甚至带来不便。于是&#xff0c;大家不禁发问&#xff1a;汽车升级功能究竟应不应该允许“可取…

三菱FX3uPLC输入接线注意事项

FX3u微型控制器(DC输入型)的输入根据外部接线&#xff0c;漏型输入和源型输入都可使用。 但是,一定要连接S/S端子的接线。 详细事宜请参考“FX3U系列微型控制器硬件说明手册 AC电源型的输入接线事例(FX3U-囗MR/UA1除外) DC电源型的输入接线事例 *请不要与(0V)、(24V)端子接线…

一文说清flink从编码到部署上线

引言&#xff1a;目前flink的文章比较多&#xff0c;但一般都关注某一特定方面&#xff0c;很少有一个文章&#xff0c;从一个简单的例子入手&#xff0c;说清楚从编码、构建、部署全流程是怎么样的。所以编写本文&#xff0c;自己做个记录备查同时跟大家分享一下。本文以简单的…

过滤器Filter,ajax异步请求,服务器响应的数据类型,json

1.过滤器Filter 按照过滤规则筛选出想要的资源 很多地方都需要判断是否登录&#xff0c;对每个资源进行判断&#xff0c;非常麻烦&#xff0c;可以使用过滤器在访问这些资源前进行判断。 案例&#xff1a; package com.ghx.filter;import javax.servlet.*; import javax.ser…

【网络协议栈】TCP/IP协议栈中重要协议和技术(DNS、ICMP、NAT、代理服务器、以及内网穿透)

每日激励&#xff1a;“请给自己一个鼓励说&#xff1a;Jack我很棒&#xff01;—Jack” 绪论​&#xff1a; 本章是TCP/IP网络协议层的完结篇&#xff0c;本章将主要去补充一些重要的协议和了解一些网络中常见的名词&#xff0c;具体如&#xff1a;DNS、ICMP、NAT、代理服务器…

服务器数据恢复—LINUX下各文件系统删除/格式化的数据恢复可行性分析

Linux操作系统是世界上流行的操作系统之一&#xff0c;被广泛用于服务器、个人电脑、移动设备和嵌入式系统。Linux系统下数据被误删除或者误格式化的问题非常普遍。下面北亚企安数据恢复工程师简单聊一下基于linux的文件系统&#xff08;EXT2/EXT3/EXT4/Reiserfs/Xfs&#xff0…

因果推荐CIKM24 | 通过偏好感知因果干预和反事实数据增强来提升序列推荐

论文来源&#xff1a;CIKM 24 论文链接&#xff1a;PACIFIC: Enhancing Sequential Recommendation via Preference-aware Causal Intervention and Counterfactual Data Augmentation | Proceedings of the 33rd ACM International Conference on Information and Knowledge …

如何在 Odoo18 视图中添加关联数据看板按钮 | 免费开源ERP实施诀窍

文 / 开源智造 Odoo亚太金牌服务 引言 关联数据看板按钮乃是 Odoo 当中的一项强效功能&#xff0c;它容许用户顺遂地访问相关记录&#xff0c;或者直接从模型的表单视图施行特定操作。它们为用户给予了对重要信息的疾速访问途径&#xff0c;并简化了工作流程&#xff0c;由此…

提升网站流量的关键:AI在SEO关键词优化中的应用

内容概要 在当今数字时代&#xff0c;提升网站流量已成为每个网站管理员的首要任务。而人工智能的技术进步&#xff0c;为搜索引擎优化&#xff08;SEO&#xff09;提供了强有力的支持&#xff0c;尤其是在关键词优化方面。关键词是连接用户需求与网站内容的桥梁&#xff0c;其…

腾讯图标/百并发

腾讯新图标&#xff0c;识别速度7毫秒&#xff0c; 百并发无压力

python和C++中的逻辑与/或、位与/或

在 Python 和 C 中&#xff0c;“与”和“或”的实现逻辑相似&#xff0c;但符号和使用方式有区别。 1.Python 中的与、或 与&#xff08;AND&#xff09;&#xff1a;and或&#xff08;OR&#xff09;&#xff1a;or 1.1 逻辑与、或&#xff1a; 用于布尔值&#xff08;Tr…

PR基本操作

将剪辑添加到序列 1.在项目面板中选择素材&#xff0c;右击插入或覆盖选项&#xff0c;添加的素材依指针所在位置为起点。 上图画框位置会影响素材插入的轨道。 2.直接拖动素材到对应的时间轴轨道即可 3.拖动素材到节目监视器 在此项前插入&#xff1a;在V1轨道当前指针所…

如何配置Github并在本地提交代码

前提: 可以流畅访问github, 需要一些上网技巧, 这就自行处理了 申请一个github账号 Github官网地址 首先就是邮箱注册啦, github没有对邮箱的限制, 只要是能收邮件的就ok, qq邮箱, 163等都可以使用. 然后和普通注册账号一样, 一路填写需要的信息, 验证邮箱即可. 如何新增代…

nacos服务注册流程

一、客户端自动注册实例流程 1.首先客户端需要引入服务发现包 <groupId>com.alibaba.cloud</groupId><artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId><version>2.2.6.RELEASE</version>2. NacosServiceRegistryA…