該項(xiàng)目選用ElfBoard ELF 1開(kāi)發(fā)板作為核心硬件平臺(tái),利用USB接口連接的攝像頭捕捉并識(shí)別車(chē)牌信息。一旦車(chē)牌成功識(shí)別,系統(tǒng)會(huì)觸發(fā)綠燈指示,并將識(shí)別所得的車(chē)牌號(hào)碼實(shí)時(shí)傳輸至手機(jī)APP。車(chē)牌識(shí)別技術(shù)方面,借助了百度提供的OCR(光學(xué)字符識(shí)別)服務(wù)來(lái)確保準(zhǔn)確高效地讀取車(chē)牌數(shù)據(jù)。同時(shí),手機(jī)APP則是采用Java編程語(yǔ)言進(jìn)行開(kāi)發(fā),可以便捷地接收和查看識(shí)別結(jié)果。
一、車(chē)牌識(shí)別的實(shí)現(xiàn)方法
1、車(chē)牌識(shí)別平臺(tái)簡(jiǎn)介
本次車(chē)牌識(shí)別的實(shí)現(xiàn)方案是通過(guò)百度智能云平臺(tái)進(jìn)行實(shí)現(xiàn),具體實(shí)現(xiàn)方法如下:進(jìn)入百度智能云網(wǎng)頁(yè)- >選擇文字識(shí)別- > 車(chē)牌識(shí)別

進(jìn)入車(chē)牌識(shí)別頁(yè)面之后可通過(guò)閱讀技術(shù)文檔來(lái)學(xué)習(xí)車(chē)牌識(shí)別的使用方法。
2、安裝 OpenSSL
因?yàn)榘俣戎悄茉剖峭ㄟ^(guò)libcurl的https進(jìn)行訪問(wèn),而https的訪問(wèn)需要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 為了在本地運(yùn)行用GCC編譯 make make install
4、車(chē)牌識(shí)別過(guò)程
(在做本次步驟之前請(qǐng)先去閱讀百度智能云車(chē)牌識(shí)別的使用方法)
在本地實(shí)現(xiàn)之前可通過(guò)平臺(tái)提供的在線驗(yàn)證方法進(jìn)行驗(yàn)證,如下圖,需要在旁邊輸入access_token(通過(guò)閱讀文檔可知怎么獲取)和一張車(chē)牌圖片的base64 編碼的字符串即可進(jìn)行在線識(shí)別。

本地實(shí)現(xiàn)車(chē)牌識(shí)別的方法需要將識(shí)別代碼拷貝到本地,并需要實(shí)現(xiàn)一個(gè)將圖片轉(zhuǎn)換為base64編碼的函數(shù),詳細(xì)代碼如下:



編譯
gcc demoCar.c -I ./curl-7.71.1/_INSTALL_GCC/include/ -L ./curl-7.71.1/_INSTALL_GCC/lib/ -l curl
編譯完成將文件通過(guò)scp拷貝到ELF 1開(kāi)發(fā)板進(jìn)行運(yùn)行即可,這樣就可以將本地的車(chē)牌圖片通過(guò)HTTPS發(fā)送到百度智能云進(jìn)行識(shí)別,并將識(shí)別結(jié)果返回完成車(chē)牌識(shí)別。
注意:這里運(yùn)行時(shí)可能會(huì)出現(xiàn)CA證書(shū)驗(yàn)證失敗
root@ELF1:~# ./a.out OK:60
只需運(yùn)行 date --s="2024-01-12 21:40:00"將時(shí)間設(shè)置正確即可。
二、移植 mjpg-streamer
在前面一個(gè)章節(jié)實(shí)現(xiàn)了對(duì)本地車(chē)牌圖片的的識(shí)別,那如果需要通過(guò)攝像頭進(jìn)行車(chē)牌識(shí)別就需要借助 mjpg-streamer來(lái)實(shí)現(xiàn),采用USB攝像頭進(jìn)行識(shí)別。
關(guān)于什么是 mjpg-streamer 我這里就不在解釋?zhuān)蠹铱梢宰孕胁殚嗁Y料進(jìn)行了解,這里只介紹一下 mjpg-streamer 移植到 ELF 1開(kāi)發(fā)板的過(guò)程。
1、編譯 jpeg
(1)下載 jpeg 源碼壓縮包網(wǎng)址: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 源碼包
網(wǎng)址:https://sourceforge.net/projects/mjpg-streamer/
svn checkout https://svn.code.sf.net/p/mjpg-streamer/code/ mjpg-streamer-code
(2)tar -xvfmjpg-streamer.tar.gz
(3)配置
cd mjpg-streamer-code/mjpg-streamer/plugins/input_uvc vim Makefile
打開(kāi) Makefile 文件按照下圖進(jìn)行修改:

(4)編譯mjpg-streamer
因?yàn)閙jpg-streamer默認(rèn)是用GCC進(jìn)行編譯,所以要先將GCC改成自己的交叉編譯工具,先安裝需要用到的庫(kù)。
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
搜索當(dāng)前目錄及其子目錄下的所有Makefile文件,并將Makefile里的CC變量設(shè)置為arm-linux-gnueabihf-gcc。(注:arm-linux-gnueabihf-gcc 需要換成自己的交叉編譯工具。)
如下圖所示所有目錄下的Makefile中的CC都等于設(shè)置的交叉編譯工具。

做完上面這些步驟之后編譯代碼:
make -j8
編譯完成后會(huì)生成下圖文件:

.so :動(dòng)態(tài)庫(kù)
mjpg_streamer:提供可執(zhí)行命令
www:攝像頭輸出的網(wǎng)頁(yè)
(5)移植到ELF 1開(kāi)發(fā)板
scp -r mjpg-streamer/ root@192.168.0.106:~
(6)驗(yàn)證功能
登錄ELF 1開(kāi)發(fā)板,運(yùn)行mjpg_streamer
cd mjpg-streamer export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:~/mjpg-streamer ./mjpg_streamer

當(dāng)開(kāi)發(fā)板運(yùn)行mjpg_streamer成功后,在瀏覽器中輸入開(kāi)發(fā)板的IP地址和8080端口號(hào),比如我的是192.168.0.106:8080,點(diǎn)擊Stream選項(xiàng)就會(huì)出現(xiàn)攝像頭中的實(shí)時(shí)畫(huà)面,如下圖所示。

這樣就完成了mjpg_streamer 的移植,后續(xù)就可以mjpg_streamer實(shí)現(xiàn)一些具體的需求,比如打開(kāi)攝像頭視頻:
mjpg_streamer -i "input_uvc.so -d /dev/video2 -f 30 -q 90 -n" -o "output_http.so -w /opt/www"
截取攝像頭中的畫(huà)面:
wget http://192.168.0.106:8080/?action=snapshot -O ./1.jpg
在這里就可以和前面車(chē)牌識(shí)別結(jié)合起來(lái)了,比如攝像頭里面的畫(huà)面是一張車(chē)牌信息,通過(guò)截取攝像頭中的實(shí)時(shí)畫(huà)面到本地,然后上傳到百度智能云的后臺(tái)進(jìn)行識(shí)別,至此就完成通過(guò)攝像頭進(jìn)行車(chē)牌識(shí)別。
三、Android APP的實(shí)現(xiàn)
Android APP 的實(shí)現(xiàn)很簡(jiǎn)單,主要功能就是將識(shí)別成功的車(chē)牌號(hào)在APP上面顯示。具體的實(shí)現(xiàn)方法是當(dāng)ELF 1開(kāi)發(fā)板成功識(shí)別車(chē)牌后,通過(guò) Socket 將車(chē)牌發(fā)送到 Android APP 上面即可。由于這部分代碼比較簡(jiǎn)單,大致如下。
1、Android 端XML代碼實(shí)現(xiàn)
XML 這部分只實(shí)現(xiàn)了兩個(gè)功能,Button 用來(lái)顯示車(chē)牌號(hào)的提示,TextView用來(lái)顯示識(shí)別的車(chē)牌號(hào)。
2、 Android端Socket實(shí)現(xiàn)
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()) { @Override public void handleMessage(Message msg)
{ super.handleMessage(msg); Bundle bundle = msg.getData(); String receivedMessage = bundle.getString("msg");
textView.setText(receivedMessage); } }; }
new Thread(new Runnable()
{ @Override public 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();
上面這段代碼就實(shí)現(xiàn)了通過(guò)Socket接收來(lái)自開(kāi)發(fā)板的車(chē)牌數(shù)據(jù)并將顯示到TextView。
3、ELF 1開(kāi)發(fā)板端實(shí)現(xiàn)
開(kāi)發(fā)板端主要就是將識(shí)別成功的車(chē)牌號(hào)碼通過(guò)Socket發(fā)送到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部分就介紹結(jié)束,具體的運(yùn)行界面效果如下圖所示:

四、總結(jié)
整個(gè)項(xiàng)目的識(shí)別過(guò)程如下圖所示,首先運(yùn)行程序,啟動(dòng)攝像頭運(yùn)行,然后會(huì)獲取攝像頭中的實(shí)時(shí)畫(huà)面進(jìn)行識(shí)別,識(shí)別成功就會(huì)將車(chē)牌的關(guān)鍵字檢索出來(lái)上傳到手機(jī)APP上面,這就是整個(gè)項(xiàng)目的關(guān)鍵運(yùn)行流程。

(上述全部?jī)?nèi)容由ElfBoard的共創(chuàng)官提供,所有分享內(nèi)容僅供學(xué)習(xí)交流使用,嚴(yán)禁任何商業(yè)用途。)
-
嵌入式
+關(guān)注
關(guān)注
5198文章
20449瀏覽量
334046 -
開(kāi)發(fā)板
+關(guān)注
關(guān)注
26文章
6291瀏覽量
118108 -
識(shí)別系統(tǒng)
+關(guān)注
關(guān)注
1文章
159瀏覽量
19458 -
嵌入式應(yīng)用
+關(guān)注
關(guān)注
0文章
64瀏覽量
18960
發(fā)布評(píng)論請(qǐng)先 登錄
基于LabVIEW的車(chē)牌識(shí)別系統(tǒng)
【TL6748 DSP申請(qǐng)】基于DSP的車(chē)牌識(shí)別系統(tǒng)
怎么用FPGA做車(chē)牌識(shí)別系統(tǒng)?
基于labview vision的機(jī)動(dòng)車(chē)車(chē)牌識(shí)別系統(tǒng)
【Rico Board申請(qǐng)】基于SoC的車(chē)牌識(shí)別系統(tǒng)
【MediaTek X20開(kāi)發(fā)板申請(qǐng)】小區(qū)車(chē)牌自動(dòng)識(shí)別系統(tǒng)
【HarmonyOS HiSpark AI Camera】車(chē)牌識(shí)別系統(tǒng)
怎么實(shí)現(xiàn)基于MATLAB的車(chē)牌識(shí)別系統(tǒng)的設(shè)計(jì)?
基于MATLAB的車(chē)牌識(shí)別系統(tǒng)的研究
車(chē)牌識(shí)別技術(shù)的發(fā)展及意義_車(chē)牌識(shí)別系統(tǒng)原理介紹
基于MATLAB的車(chē)牌識(shí)別系統(tǒng)
基于OpenCV開(kāi)源庫(kù)開(kāi)發(fā)的在OpenHarmony中實(shí)現(xiàn)車(chē)牌識(shí)別
項(xiàng)目分享|基于ELF 1開(kāi)發(fā)板的遠(yuǎn)程監(jiān)測(cè)及人臉識(shí)別項(xiàng)目
迅為RK3568開(kāi)發(fā)板模型推理測(cè)試實(shí)戰(zhàn)LPRNet?車(chē)牌識(shí)別
項(xiàng)目分享|基于ELF 1開(kāi)發(fā)板的車(chē)牌識(shí)別系統(tǒng)
評(píng)論