文章和項(xiàng)目源碼已經(jīng)歸檔至【Github倉庫:https://github.com/timerring/face-recognition-door 】或者【AIShareLab】回復(fù) 人臉識(shí)別門禁 也可獲取艳汽。
1.通信系統(tǒng)制作方案概述
項(xiàng)目演示視頻: 基于YOLOv2和傳感器的多功能門禁系統(tǒng)
1.1系統(tǒng)設(shè)計(jì)的立意
此處略伪煤。
1.2系統(tǒng)的主要組成
設(shè)計(jì)基于 YOLOv 2 的人臉識(shí)別門禁系統(tǒng)富寿,主要由成品模塊組成。具體包含:K210 Maix Bit迁筛、配套24PIN DVP 攝像頭及 LCD 屏、SG90舵機(jī)伤极、HC-SR501人體紅外感應(yīng)模塊鲫咽、MFRC-522射頻模塊肚豺、HC-05藍(lán)牙模塊溃斋、有源蜂鳴器、32G SD 內(nèi)存卡及讀卡器吸申、4位獨(dú)立按鍵梗劫。
1.3系統(tǒng)的制作方案
1.3.1制作方案框圖
[圖片上傳失敗...(image-af15ad-1694761640999)]
1.3.2制作方案原理描述
初步設(shè)立門禁系統(tǒng)三大模式,等待截碴、門禁及錄入模式梳侨。
等待模式無人時(shí)顯示屏全黑只顯示 waiting......;門禁模式打開攝像頭鎖定人臉顯示比對精度(百分制)與識(shí)別框日丹,此時(shí) RFID 數(shù)據(jù)通道打開走哺,并在左上角標(biāo)注所處模式;
錄入模式打開攝像頭鎖定人臉顯示采樣進(jìn)度與識(shí)別框哲虾,此時(shí)藍(lán)牙通道打開丙躏,并在左上角標(biāo)注所處模式,默認(rèn)等待模式束凑。使用 K210 MAIXBIT 做主控晒旅,當(dāng)紅外感知模塊檢測到人時(shí),屏幕亮起汪诉,可識(shí)別人臉但無反應(yīng)(紅外感知模塊可調(diào)節(jié)靈敏度與延時(shí)废恋,但過于靈敏會(huì)導(dǎo)致畫面卡頓,反之則檢測效果不理想)扒寄。使用獨(dú)立按鍵切換到錄入或門禁模式鱼鼓,30s 未檢測到人臉自動(dòng)進(jìn)入等待黑屏模式。
錄入模式時(shí)该编,使用移動(dòng)端 app 調(diào)試全能王連接藍(lán)牙模塊并發(fā)送指令:
- 輸入“
register****
”(****
代表錄入人臉編號(hào))后按照 yolo v 2 算法采集 196 維人臉數(shù)據(jù)(3 輪 18 次采樣)迄本,并儲(chǔ)存在 SD 卡文件中,且屏幕顯示采樣進(jìn)度上渴,錄入完成屏幕顯示“successful”岸梨,蜂鳴器發(fā)低聲。 - 輸入“
delete****
”則刪除對應(yīng)用戶儲(chǔ)存在 SD 卡的特征值稠氮,蜂鳴器發(fā)高聲曹阔。 - 輸入“
erase
”則刪除 SD 卡內(nèi)所有用戶人臉特征值,蜂鳴器發(fā)高聲隔披。 - 輸入“
open
”則無條件控制舵機(jī)旋轉(zhuǎn)赃份。
門禁模式時(shí),設(shè)定比對閾值,高于則蜂鳴器發(fā)低聲且舵機(jī)旋轉(zhuǎn)抓韩,低于則蜂鳴器發(fā)高聲舵機(jī)無反應(yīng)纠永。此外 RFID 數(shù)據(jù)通道開通,我們已給兩張 S50標(biāo)準(zhǔn)卡與異形卡相同扇區(qū)注入不同信息谒拴,分別會(huì)有舵機(jī)與蜂鳴器的不同響應(yīng)情形尝江,當(dāng)其他 RFID 卡靠近則默認(rèn)發(fā)生系統(tǒng)錯(cuò)誤并發(fā)出獨(dú)有蜂鳴器聲音(可以修改)。
1.4系統(tǒng)方案的可行性論證
技術(shù)可行性分析:
深度學(xué)習(xí)算法和神經(jīng)網(wǎng)絡(luò)理論已有較成熟應(yīng)用,圖像識(shí)別英上、人臉識(shí)別等領(lǐng)域有較多成功案例,技術(shù)上實(shí)現(xiàn)人臉識(shí)別門禁系統(tǒng)是可行的炭序。傳感器技術(shù)也比較成熟,可以采集人臉圖像和相關(guān)生物特征,作為識(shí)別的輸入。系統(tǒng)集成方面,人臉識(shí)別算法苍日、傳感器技術(shù)和門禁系統(tǒng)的結(jié)合也是現(xiàn)有技術(shù)可以實(shí)現(xiàn)的惭聂。經(jīng)濟(jì)可行性分析:
相關(guān)硬件成本在可接受范圍內(nèi),如高清攝像頭等。軟件實(shí)現(xiàn)可以采用開源算法和框架,開發(fā)成本不高相恃。人臉識(shí)別門禁系統(tǒng)可以降低人工成本,尤其適用于人流較大場景,具有較好的經(jīng)濟(jì)效益辜纲。操作可行性分析:
人臉識(shí)別門禁系統(tǒng)操作簡單,易于推廣使用,無需復(fù)雜訓(xùn)練,符合大多數(shù)人的接受習(xí)慣。該系統(tǒng)也便于維護(hù)和管理,可靠性較高拦耐。
綜上,從技術(shù)耕腾、經(jīng)濟(jì)和操作等多方面考慮,基于深度學(xué)習(xí)的人臉識(shí)別門禁系統(tǒng)是一種可行的智能門禁方案。但是,數(shù)據(jù)安全和隱私保護(hù)也需要重點(diǎn)考慮,總體而言該方案是值得研究和探索的揩魂。
2.具體模塊分布圖及集成原理圖
[圖片上傳失敗...(image-d80bfd-1694761641000)]
圖2-1 人臉識(shí)別系統(tǒng)實(shí)操圖
[圖片上傳失敗...(image-ae645b-1694761641000)]
圖2-2 通信系統(tǒng)原理圖
3.各個(gè)模塊硬件調(diào)試中遇見難題及解決方案
3.1藍(lán)牙
HC-05藍(lán)牙模塊是一種基于藍(lán)牙協(xié)議的簡單無線通信設(shè)備幽邓。該模塊基于 BC417單芯片藍(lán)牙 IC,符合藍(lán)牙 v2.0標(biāo)準(zhǔn)火脉,支持 UART 和 USB 接口牵舵。
具有兩種工作模式:命令響應(yīng)工作模式和自動(dòng)連接工作模式。
當(dāng)模塊處于命令響應(yīng)工作模式(或者AT模式)時(shí)能才能執(zhí)行 AT 命令倦挂,用戶可向模塊發(fā)送各種 AT指令畸颅,為模塊設(shè)定控制參數(shù)或發(fā)布控制命令。(AT指令就是我們PC與一些終端設(shè)備(例如藍(lán)牙方援,WiFi模塊)之間進(jìn)行通信的没炒,配置這些終端設(shè)備參數(shù)的一套指令。)在自動(dòng)連接工作模式下模塊又可分為主(Master)犯戏、從(Slave)和回環(huán)(Loopback)三種工作角色送火。當(dāng)模塊處于自動(dòng)連接工作模式時(shí),將自動(dòng)根據(jù)事先設(shè)定的方式連接的數(shù)據(jù)傳輸先匪。主模式:該模塊可以主動(dòng)搜索并連接其它藍(lán)牙模塊并接收發(fā)送數(shù)據(jù)种吸。從模式:只能被搜索被其它藍(lán)牙模塊連接進(jìn)行接收發(fā)送數(shù)據(jù)⊙椒牵回環(huán):藍(lán)牙模塊就是將接收的數(shù)據(jù)原樣返回給遠(yuǎn)程的主設(shè)備坚俗。
初次使用模塊由于不知道藍(lán)牙模塊密碼镜盯,故需要再使用 TTL 轉(zhuǎn)串口模塊,使用 AT 指令查詢和修改藍(lán)牙名稱與密碼猖败。
[圖片上傳失敗...(image-d384f5-1694761641000)]
圖3-1正點(diǎn)原子XCOM串口調(diào)試助手圖
3.2蜂鳴器
蜂鳴器主要用于功能實(shí)現(xiàn)的提示音速缆,一開始使用了低電平的蜂鳴器,導(dǎo)致一直響以為是代碼不當(dāng)導(dǎo)致的功能卡頓恩闻,多次檢查后發(fā)現(xiàn)和代碼無關(guān)艺糜,后來選取了高電平觸發(fā)的蜂鳴器得以成功得到提示音。
3.3紅外感知模塊
紅外模塊用來感知是否有人在使用判呕,從而開啟或者關(guān)閉識(shí)別元件倦踢,紅外檢測器件的使用難點(diǎn)在于靈敏性調(diào)整送滞,需要仔細(xì)修改侠草,否則就會(huì)導(dǎo)致過快或者不進(jìn)入休眠模式,從而影響使用犁嗅。除此之外边涕,不準(zhǔn)確的紅外檢測還會(huì)導(dǎo)致器件反應(yīng)過慢等等的問題,所以在紅外器件的修改上下了很多時(shí)間才得到比較準(zhǔn)確的識(shí)別數(shù)據(jù)褂微。
3.4矩陣鍵盤
用于模式轉(zhuǎn)換功蜓,錄入人臉模式和正常使用模式,安裝需要注意連接線宠蚂。
3.5 RFID
RFID模塊:標(biāo)簽進(jìn)入磁場后式撼,接收解讀器發(fā)出的射頻信號(hào),憑借感應(yīng)電流所獲得的能量發(fā)送出存儲(chǔ)在芯片中的產(chǎn)品信息(Passive Tag求厕,無源標(biāo)簽或被動(dòng)標(biāo)簽)著隆,或者由標(biāo)簽主動(dòng)發(fā)送某一頻率的信號(hào)(Active Tag,有源標(biāo)簽或主動(dòng)標(biāo)簽)呀癣,解讀器讀取信息并解碼后美浦,再進(jìn)行有關(guān)數(shù)據(jù)處理。在RFID模塊的設(shè)計(jì)中项栏,為了方便地將標(biāo)簽的信息進(jìn)行區(qū)分浦辨,首先設(shè)計(jì)了不同權(quán)限卡之間的對應(yīng)規(guī)則,分別設(shè)計(jì)了存儲(chǔ)信息中Y開頭的萬能通用卡沼沈,N開頭的帶有序號(hào)的普通用戶權(quán)限卡流酬,以及未規(guī)定的其他RFID卡,然后按照設(shè)定寫了讀卡器的寫入程序列另,將對應(yīng)的規(guī)則寫入測試卡片芽腾,并且對卡片進(jìn)行了測試。具體要將RFID驗(yàn)證模塊加入到哪個(gè)環(huán)節(jié)之中访递,我們也對應(yīng)地做了測試晦嵌,所有流程都會(huì)回到普通模式,因此最開始是將RFID是加入在普通模式下,但是經(jīng)過實(shí)際地測試與檢驗(yàn)后惭载,發(fā)現(xiàn)普通模式并不適合加入RFID模塊旱函,應(yīng)該在檢測到有人存在時(shí)再啟動(dòng)RFID。 其一描滔,當(dāng)門禁系統(tǒng)不被使用時(shí)票编,啟動(dòng)RFID模塊會(huì)浪費(fèi)大量的能源。通過檢測到有人存在再啟動(dòng)RFID模塊尿招,可以最大程度地節(jié)省能源畔规,降低系統(tǒng)的運(yùn)行成本。其二拘泞,在門禁系統(tǒng)中纷纫,啟動(dòng)RFID模塊是為了實(shí)現(xiàn)對進(jìn)出人員的身份識(shí)別和控制。通過檢測到有人存在后再啟動(dòng)RFID模塊陪腌,可以確保門禁系統(tǒng)只對授權(quán)人員開放辱魁,提高門禁系統(tǒng)的安全性。最后綜合考慮诗鸭,將RFID模塊放置在門禁模式之下染簇。
3.6人臉識(shí)別模塊
由k210芯片,攝像頭和LED顯示屏組成强岸,用于識(shí)別用戶臉部數(shù)據(jù)決定是否開啟舵機(jī)锻弓。原理是YOLO 人臉識(shí)別,是一種基于深度學(xué)習(xí)的目標(biāo)檢測算法蝌箍,它可以在一張圖像中同時(shí)檢測出多個(gè)目標(biāo)青灼,并且實(shí)時(shí)性能非常好。YOLO 模型的識(shí)別原理是通過將圖像分成名個(gè)網(wǎng)格十绑,然后對每個(gè)網(wǎng)格進(jìn)行預(yù)測聚至,最終將所有網(wǎng)格的預(yù)測結(jié)果合并起來得到最終的檢迎結(jié)果。YOLO 模型的輸入是一張圖像本橙,輸出是每個(gè)目標(biāo)的類別扳躬、位置和置信度。在訓(xùn)練階段甚亭,YOLO 模型會(huì)學(xué)習(xí)如何將圖像分成多個(gè)網(wǎng)格贷币,并且對每個(gè)網(wǎng)格進(jìn)行預(yù)測。每個(gè)網(wǎng)格的大小可以根據(jù)圖像的大小 或者目標(biāo)的大小進(jìn)行調(diào)整亏狰。對于每個(gè)網(wǎng)格役纹,YOLO 模型會(huì)預(yù)測出多個(gè)邊界框,每個(gè)邊界框包含了一個(gè)日標(biāo)的位置和大小信息暇唾。同時(shí)促脉,YOLO模型還會(huì)預(yù)測出每個(gè)邊界框?qū)?yīng)的目標(biāo)的類別和置信度辰斋。除了寫入訓(xùn)練的數(shù)學(xué)模型外,還需要設(shè)置識(shí)別的準(zhǔn)確數(shù)據(jù)分?jǐn)?shù)瘸味,超過標(biāo)準(zhǔn)才可以運(yùn)行下一步功能宫仗。還需協(xié)調(diào)模型的數(shù)據(jù)存儲(chǔ)和循環(huán)量,以免占用過多的數(shù)據(jù)空間旁仿,造成大量數(shù)據(jù)冗余藕夫,導(dǎo)致死機(jī)。
3.7舵機(jī)
SG 90舵機(jī)需要使用正確的通信協(xié)議與門禁系統(tǒng)的其他部件進(jìn)行通信枯冈。在門禁系統(tǒng)中使用SG 90舵機(jī)時(shí)毅贮,應(yīng)該選擇適當(dāng)?shù)耐ㄐ艆f(xié)議,例如PWM或者串口通信尘奏,并確保通信協(xié)議的準(zhǔn)確性和穩(wěn)定性滩褥。
4.開發(fā)平臺(tái)介紹及代碼思路簡介
4.1 yolo v2算法介紹
[圖片上傳失敗...(image-e69c99-1694761641000)]
圖4-1 YOLOv2原理圖
- 輸入圖片被分成 S x S 個(gè)網(wǎng)格(cell),每個(gè)網(wǎng)格負(fù)責(zé)檢測該網(wǎng)格內(nèi)是否存在目標(biāo)物體罪既。
- 對于每個(gè)網(wǎng)格铸题,預(yù)測出 B 個(gè)邊界框(bounding box),每個(gè)邊界框包括(x, y, w, h, confidence)五個(gè)元素琢感,其中(x, y)是邊界框中心的坐標(biāo),w 和 h 是邊界框的寬和高探熔,confidence 表示該邊界框中包含目標(biāo)物體的置信度驹针。
- 對于每個(gè)邊界框,計(jì)算它與 ground truth(真實(shí)標(biāo)注的物體位置)的 IoU(交并比)诀艰,并選取 IoU 最大的邊界框作為該物體的預(yù)測框柬甥。
- 使用非極大值抑制(NMS)方法來剔除重疊的預(yù)測框,最終輸出預(yù)測結(jié)果其垄。
關(guān)于IoU:
IoU 是交并比(Intersection over Union)的縮寫苛蒲,是一種用于衡量目標(biāo)檢測算法檢測準(zhǔn)確性的指標(biāo)。它是通過計(jì)算預(yù)測框和 ground truth(真實(shí)標(biāo)注的物體位置)之間的重疊程度來得出的绿满。具體來說臂外,IoU 是預(yù)測框和 ground truth 的交集面積除以它們的并集面積,即:
IoU = Intersection over Union = Intersection / Union
其中喇颁,Intersection表示預(yù)測框和ground truth的交集面積漏健,Union表示它們的并集面積。IoU的取值范圍在0到1之間橘霎,取值越大表示檢測準(zhǔn)確性越高蔫浆。一般來說,當(dāng)IoU大于某個(gè)閾值時(shí)姐叁,我們就認(rèn)為預(yù)測框和ground truth匹配成功瓦盛,可以將其作為檢測結(jié)果洗显;反之則認(rèn)為匹配失敗。
在目標(biāo)檢測算法中原环,通常會(huì)使用IoU作為評價(jià)指標(biāo)來衡量算法的準(zhǔn)確性墙懂。比如,在YOLOv2算法中扮念,會(huì)使用IoU來選取每個(gè)邊界框中與ground truth匹配的框损搬。在訓(xùn)練過程中,如果預(yù)測框與ground truth之間的IoU大于某個(gè)閾值柜与,我們就認(rèn)為這個(gè)預(yù)測框是正確的巧勤,并計(jì)算它的損失函數(shù);反之則認(rèn)為它是錯(cuò)誤的弄匕,不參與損失函數(shù)的計(jì)算颅悉。通過不斷地調(diào)整模型參數(shù),最終可以得到一個(gè)準(zhǔn)確性較高的目標(biāo)檢測算法迁匠。
關(guān)于NMS:
非極大值抑制(Non-Maximum Suppression剩瓶,NMS)是一種用于目標(biāo)檢測算法中的后處理方法,主要用于剔除重疊的預(yù)測框城丧,保留最準(zhǔn)確的預(yù)測結(jié)果延曙。在目標(biāo)檢測算法中,一些目標(biāo)可能會(huì)被多個(gè)預(yù)測框所檢測到亡哄,這些預(yù)測框之間可能存在重疊枝缔。在這種情況下,我們需要對這些預(yù)測框進(jìn)行篩選蚊惯,保留最準(zhǔn)確的預(yù)測結(jié)果愿卸。NMS方法就是用來完成這個(gè)任務(wù)的。NMS的基本原理如下:
- 對所有預(yù)測框按照其置信度(confidence)進(jìn)行排序截型,從置信度最高的預(yù)測框開始遍歷趴荸。
- 對于當(dāng)前遍歷到的預(yù)測框,計(jì)算它與之前已經(jīng)選中的預(yù)測框的 IoU(交并比)宦焦,如果 IoU 大于某個(gè)閾值(如0.5)发钝,則將該預(yù)測框剔除,否則保留該預(yù)測框赶诊。
- 重復(fù)步驟2和3笼平,直到遍歷完所有的預(yù)測框。
通過這個(gè)過程舔痪,NMS方法可以將多個(gè)重疊的預(yù)測框剔除寓调,保留最準(zhǔn)確的預(yù)測結(jié)果。NMS方法可以有效地解決目標(biāo)檢測算法中的多框問題锄码,提高檢測準(zhǔn)確性夺英。需要注意的是晌涕,NMS方法的效果受到閾值的影響。如果閾值較高痛悯,那么將會(huì)保留更少的預(yù)測框余黎,可能會(huì)漏檢一些目標(biāo);如果閾值較低载萌,那么將會(huì)保留更多的預(yù)測框惧财,可能會(huì)增加誤檢的概率。
同時(shí)扭仁,為了提高準(zhǔn)確性和速度垮衷,YOLOv2采用了一些技巧:
- Darknet-19網(wǎng)絡(luò):YOLOv2使用了一個(gè)19層的卷積神經(jīng)網(wǎng)絡(luò) Darknet-19來提取特征。該網(wǎng)絡(luò)比 VGG16等經(jīng)典網(wǎng)絡(luò)更輕量乖坠,同時(shí)具有更好的準(zhǔn)確性搀突。
- Anchor Boxes:YOLOv2在每個(gè)網(wǎng)格上預(yù)測 B 個(gè)邊界框,而不是像 YOLOv1一樣只預(yù)測一個(gè)熊泵。此外仰迁,YOLOv2使用了 Anchor Boxes,即預(yù)定義的邊界框顽分,來提高檢測準(zhǔn)確性徐许。在訓(xùn)練過程中,YOLOv2通過調(diào)整 Anchor Boxes 和預(yù)測框的位置和大小來進(jìn)行目標(biāo)檢測怯邪。
- Batch Normalization:在 Darknet-19網(wǎng)絡(luò)中使用 Batch Normalization 來加速收斂和提高準(zhǔn)確性绊寻。
- High Resolution Classifier:YOLOv2使用了一個(gè)高分辨率的分類器來提高檢測準(zhǔn)確性。具體來說悬秉,在訓(xùn)練時(shí),YOLOv2將輸入圖片的分辨率提高到608x608冰蘑,而在測試時(shí)和泌,將其縮小到416x416,以加快處理速度祠肥。
- Convolutional With Anchor Boxes (CWA):YOLOv2引入了一種新的卷積層武氓,稱為 Convolutional With Anchor Boxes (CWA)。該層同時(shí)計(jì)算多個(gè) Anchor Boxes 的位置和置信度仇箱,以提高檢測準(zhǔn)確性和速度县恕。
總的來說,YOLOv2是一個(gè)快速且準(zhǔn)確的目標(biāo)檢測算法剂桥,它的核心思想是將目標(biāo)檢測問題轉(zhuǎn)化為一個(gè)回歸問題忠烛,并使用神經(jīng)網(wǎng)絡(luò)來解決。通過使用Anchor Boxes权逗、Batch Normalization美尸、High Resolution Classifier和Convolutional With Anchor Boxes等技巧冤议,YOLOv2在準(zhǔn)確性和速度方面都有所提高。
4.2 開發(fā)平臺(tái)
開發(fā)環(huán)境:MaixPy IDE
[圖片上傳失敗...(image-64c4b6-1694761641000)]
MaixPy IDE 是一款基于 Python 語言的集成開發(fā)環(huán)境(IDE)师坎,主要用于開發(fā)和調(diào)試 MaixPy(開源的嵌入式人工智能框架)項(xiàng)目恕酸。MaixPy IDE 提供了一系列功能,包括代碼編輯胯陋、調(diào)試蕊温、編譯、下載遏乔、串口調(diào)試义矛、固件升級(jí)等,方便用戶對 MaixPy 進(jìn)行開發(fā)和調(diào)試按灶。
燒錄環(huán)境:kflash_gui
[圖片上傳失敗...(image-8199-1694761641000)]
kflash_gui是一款開源的圖形化固件燒錄工具症革,用于將固件燒錄到Kendryte K210芯片上。K210是一款基于RISC-V架構(gòu)的高性能鸯旁、低功耗的嵌入式處理器噪矛,廣泛應(yīng)用于物聯(lián)網(wǎng)、人工智能等領(lǐng)域铺罢。kflash_gui是Kendryte K210的官方固件燒錄工具艇挨,提供了一系列功能,包括固件下載韭赘、擦除缩滨、燒錄、調(diào)試等泉瞻。kflash_gui基于Python語言和PyQt庫開發(fā)脉漏,支持命令行和GUI兩種模式。用戶可以通過命令行模式進(jìn)行批量燒錄等高級(jí)操作袖牙,也可以通過GUI模式進(jìn)行簡單易用的固件燒錄侧巨。kflash_gui還提供了一些高級(jí)功能,如自動(dòng)檢測串口鞭达、自動(dòng)切換燒錄模式司忱、支持多種燒錄設(shè)備等,方便用戶進(jìn)行高效的固件燒錄畴蹭。
串口調(diào)試環(huán)境:XCOM
[圖片上傳失敗...(image-45aab8-1694761641000)]
- 支持多個(gè)常用波特率坦仍,支持自定義波特率
- 支持5/6/7/8位數(shù)據(jù),支持1/1.5/2個(gè)停止位
- 支持奇/偶/無校驗(yàn)
- 支持16禁止發(fā)送/接收顯示叨襟,支持DTR/RTS控制
- 支持窗口保存繁扎,并可以設(shè)置編碼格式
- 支持延時(shí)設(shè)置,支持時(shí)間戳功能
- 支持定時(shí)發(fā)送芹啥,支持文件發(fā)送锻离,支持發(fā)送新行
- 支持多條發(fā)送铺峭,并關(guān)聯(lián)數(shù)字鍵盤,支持循環(huán)發(fā)送
- 支持無限制擴(kuò)展條數(shù)汽纠,可自行增刪
- 支持發(fā)送條目導(dǎo)出/導(dǎo)入(excel格式)
- 支持協(xié)議傳輸(類modbus)
- 支持發(fā)送/接收區(qū)字體大小卫键、顏色和背景色設(shè)置
- 支持簡體中文、繁體中文虱朵、英文三種語言
- 支持原子軟件倉庫
4.3代碼解析
[圖片上傳失敗...(image-41efb6-1694761641000)]
圖4-3 代碼流程圖
從左到右依次將代碼模塊化為三個(gè)模塊莉炉,分別是人臉數(shù)據(jù)采集模塊,人臉信息錄入模塊碴犬,人臉?biāo){牙RFID綜合驗(yàn)證模塊絮宁。下面依次對三個(gè)模塊的思路進(jìn)行解析:
首先是人臉數(shù)據(jù)采集模塊,這段代碼是一個(gè)人臉識(shí)別的應(yīng)用程序服协,主要分為以下幾個(gè)步驟:首先設(shè)置各種標(biāo)志位和參數(shù)绍昂,包括是否檢測到人、是否錄入偿荷、查找模式窘游、人臉對比置信度等。
然后執(zhí)行以下操作:
a. 調(diào)用 check_key()函數(shù)跳纳,可能用于檢測設(shè)備是否已經(jīng)授權(quán)使用相關(guān)的模型忍饰。
b. 調(diào)用sensor.snapshot()函數(shù)獲取一張圖像。
c. 使用kpu.run_yolo2()函數(shù)對輸入的圖像進(jìn)行人臉檢測寺庄,返回一個(gè)包含檢測結(jié)果的列表code艾蓝。
d. 如果檢測到人臉,程序會(huì)遍歷code中的每個(gè)檢測結(jié)果斗塘,計(jì)算人臉框的面積赢织,并選擇面積最大的人臉進(jìn)行處理。
e. 使用 img.draw_rectangle()函數(shù)在原圖像上繪制人臉框馍盟,然后使用 img.cut()函數(shù)對原圖像進(jìn)行裁剪敌厘,得到人臉圖像。
f. 對人臉圖像進(jìn)行特征點(diǎn)檢測朽合,得到人臉的五個(gè)關(guān)鍵點(diǎn)坐標(biāo),使用img.draw_circle()函數(shù)在原圖像上繪制出這些關(guān)鍵點(diǎn)的位置饱狂。
g. 使用這些關(guān)鍵點(diǎn)的坐標(biāo)計(jì)算人臉的仿射變換矩陣曹步,并使用image.get_affine_transform()函數(shù)計(jì)算變換矩陣,將人臉圖像進(jìn)行對齊休讳,得到標(biāo)準(zhǔn)的人臉圖像讲婚。
h. 使用kpu.forward()函數(shù)對對齊后的人臉圖像進(jìn)行特征提取,再使用kpu.face_encode()函數(shù)將特征向量進(jìn)行編碼俊柔。
i. 遍歷預(yù)先錄入的人臉特征列表筹麸,使用kpu.face_compare()函數(shù)計(jì)算當(dāng)前人臉特征向量與列表中每個(gè)特征向量的相似度得分活合,并選擇得分最高的特征向量,返回其在列表中的索引物赶,用于識(shí)別當(dāng)前人臉是否為已知人臉白指。
j. 根據(jù)人臉識(shí)別結(jié)果,可以執(zhí)行不同的操作酵紫,如錄入新人臉特征告嘲、查找已知人臉特征,或者進(jìn)行相應(yīng)的提示和處理奖地。
代碼詳細(xì)注釋如下:
# 設(shè)置各種flag
no_people = 0 # 是否無人
no_flag = 0
delline = []
check_num = 0
shibie_num = 0
uart.read()
# 設(shè)置人臉對比置信度
ACCURACY = 75
# 錄入模式flag
luru_flag = 0
# 查找模式flag
find_flag = 0
feature = ''
max_score = 0
index = 0
while (1):
# 程序首先調(diào)用了check_key()函數(shù)橄唬,該函數(shù)可能用于檢測設(shè)備是否已經(jīng)授權(quán)使用相關(guān)的模型。
check_key()
# 調(diào)用了sensor.snapshot()函數(shù)獲取一張圖像参歹。
img = sensor.snapshot()
# 使用kpu.run_yolo2()函數(shù)對輸入的圖像進(jìn)行人臉檢測仰楚,返回一個(gè)包含檢測結(jié)果的列表code。
code = kpu.run_yolo2(task_fd, img)
max_score = 0
# 如果code不為空犬庇,即檢測到人臉僧界,程序會(huì)遍歷code中的每個(gè)檢測結(jié)果,計(jì)算人臉框的面積械筛,并選擇面積最大的人臉進(jìn)行處理捎泻。
if code:
t = 0
max_face = 0
totalRes = len(code)
area = []
# 如果檢測到的人臉數(shù)大于1,則只處理面積最大的人臉埋哟。
if totalRes > 1: #多張人臉時(shí)笆豁,挑選面積最大的,一般即最前面的
for i in code: # 迭代坐標(biāo)框 多張人臉
area.append(i.w()*i.h())
for j in range(len(area)):
if max_face < area[j]:
max_face = area[j]
t = j #保存最大臉面積下標(biāo)
totalRes = 1
del area
if totalRes == 1: #只有一張臉
i = code[t]
# 首先使用img.draw_rectangle()函數(shù)在原圖像上繪制人臉框
# Cut face and resize to 128x128
a = img.draw_rectangle(i.rect())
# 然后使用img.cut()函數(shù)對原圖像進(jìn)行裁剪赤赊,得到人臉圖像闯狱。
face_cut = img.cut(i.x(), i.y(), i.w(), i.h())
# 使用img.resize()函數(shù)將人臉圖像縮放為128x128大小
face_cut_128 = face_cut.resize(128, 128)
# 使用img.pix_to_ai()函數(shù)將圖像轉(zhuǎn)換為KPU能夠處理的格式。
a = face_cut_128.pix_to_ai()
# a = img.draw_image(face_cut_128, (0,0))
# Landmark for face 5 points
# 程序使用kpu.forward()函數(shù)對人臉圖像進(jìn)行特征點(diǎn)檢測抛计,得到人臉的五個(gè)關(guān)鍵點(diǎn)坐標(biāo)哄孤。
fmap = kpu.forward(task_ld, face_cut_128)
plist = fmap[:]
le = (i.x() + int(plist[0] * i.w() - 10), i.y() + int(plist[1] * i.h()))
re = (i.x() + int(plist[2] * i.w()), i.y() + int(plist[3] * i.h()))
nose = (i.x() + int(plist[4] * i.w()), i.y() + int(plist[5] * i.h()))
lm = (i.x() + int(plist[6] * i.w()), i.y() + int(plist[7] * i.h()))
rm = (i.x() + int(plist[8] * i.w()), i.y() + int(plist[9] * i.h()))
# 使用img.draw_circle()函數(shù)在原圖像上繪制出這些關(guān)鍵點(diǎn)的位置。
a = img.draw_circle(le[0], le[1], 4)
a = img.draw_circle(re[0], re[1], 4)
a = img.draw_circle(nose[0], nose[1], 4)
a = img.draw_circle(lm[0], lm[1], 4)
a = img.draw_circle(rm[0], rm[1], 4)
# align face to standard position
src_point = [le, re, nose, lm, rm]
# 程序使用這些關(guān)鍵點(diǎn)的坐標(biāo)計(jì)算人臉的仿射變換矩陣吹截,并使用image.get_affine_transform()函數(shù)計(jì)算變換矩陣瘦陈。
T = image.get_affine_transform(src_point, dst_point)
# 使用image.warp_affine_ai()函數(shù)將人臉圖像進(jìn)行對齊,得到標(biāo)準(zhǔn)的人臉圖像波俄。
a = image.warp_affine_ai(img, img_face, T)
# 然后晨逝,程序使用img.ai_to_pix()函數(shù)將對齊后的圖像轉(zhuǎn)換為原圖像能夠顯示的格式。
a = img_face.ai_to_pix()
# a = img.draw_image(img_face, (128,0))
del (face_cut_128)
# calculate face feature vector
# 程序使用kpu.forward()函數(shù)對對齊后的人臉圖像進(jìn)行特征提取
fmap = kpu.forward(task_fe, img_face)
# 使用kpu.face_encode()函數(shù)將特征向量進(jìn)行編碼
feature = kpu.face_encode(fmap[:])
reg_flag = False
scores = []
# 程序遍歷預(yù)先錄入的人臉特征列表
for j in range(len(record_ftrs)):
# 使用kpu.face_compare()函數(shù)計(jì)算當(dāng)前人臉特征向量與列表中每個(gè)特征向量的相似度得分懦铺。
score = kpu.face_compare(record_ftrs[j], feature)
scores.append(score)
max_score = 0
index = 0
# 最終捉貌,程序選擇得分最高的特征向量,并返回其在列表中的索引。這個(gè)索引可以用于識(shí)別當(dāng)前人臉是否為已知人臉趁窃。
for k in range(len(scores)):
if max_score < scores[k]:
max_score = scores[k]
index = k
其次是人臉信息錄入模塊牧挣,主要分為以下幾個(gè)步驟:
- 如果檢測到當(dāng)前畫面中存在人臉,且識(shí)別率超過預(yù)設(shè)值醒陆,程序會(huì)在屏幕上顯示提示信息“Face Exist”瀑构,然后繼續(xù)循環(huán),等待下一張圖像的檢測和處理统求。
- 如果檢測到人臉特征检碗,程序會(huì)記錄當(dāng)前采集的人臉數(shù)量,每檢測到一次人臉就加 1码邻,并在屏幕上顯示當(dāng)前采樣進(jìn)度折剃。程序會(huì)間隔錄入,每采集 6 次人臉特征就將當(dāng)前特征加入到臨時(shí)特征值列表中像屋。
- 如果已采集到 18 次人臉特征怕犁,表示錄入結(jié)束,程序會(huì)將當(dāng)前特征添加到已知特征列表中己莺,并將編號(hào)添加到 names 列表中奏甫。然后程序會(huì)嘗試打開 SD 卡上的 faceinfo. Txt 文件,并以追加模式寫入數(shù)據(jù)凌受。寫入完成后阵子,程序會(huì)將當(dāng)前特征添加到已知特征列表中,并將編號(hào)添加到 names 列表中胜蛉。同時(shí)清空臨時(shí)特征值列表和采集次數(shù)挠进,顯示錄入成功或失敗的提示信息,并進(jìn)行蜂鳴器聲音提示誊册。最后退出錄入任務(wù)并回到正常模式领突。
- 如果保存到 SD 卡失敗,則按鍵次數(shù)清零案怯,check_num 清零君旦,編號(hào)清空,并顯示錄入失敗的提示信息嘲碱。
- 最后金砍,程序會(huì)刪除code變量,釋放內(nèi)存空間麦锯。
代碼詳細(xì)注釋如下:
# 執(zhí)行錄入任務(wù)
if luru_flag == 1:
# 如果檢測到當(dāng)前畫面中存在人臉捞魁,且識(shí)別率超過預(yù)設(shè)值
if max_score > ACCURACY:
# 人臉采集次數(shù)清零
check_num = 0
# 在屏幕上顯示提示信息“Face Exist”
a = img.draw_string(200,0, b'Face Exist', color=(255,0,0),scale=1.6,mono_space=1) #提示人臉已存在
# 在屏幕上顯示圖像
a = lcd.display(img)
# 繼續(xù)循環(huán),等待下一張圖像的檢測和處理
continue
# 如果檢測到人臉特征
if code:
# 記錄當(dāng)前采集的人臉數(shù)量离咐,每檢測到一次人臉就加1
check_num = check_num + 1 #檢測到一次人臉則加 1
# 在屏幕上顯示當(dāng)前采樣進(jìn)度
a = img.draw_string(5,40, b'%d'%check_num, color=(0,255,0),scale=1.4,mono_space=1) #顯示采樣進(jìn)度
# 間隔錄入,每采集6次人臉特征就將當(dāng)前特征加入到臨時(shí)特征值列表中
if check_num % 6 == 0 and check_num != 0:
record_ftrtemp.append(feature) #加入當(dāng)前人臉特征
# 如果已采集到18次人臉特征,表示錄入結(jié)束
if check_num == 18:
# 錄入成功標(biāo)志位設(shè)為1
save_success = 1
try:
# 嘗試打開SD卡上的faceinfo.txt文件宵蛀,并以追加模式寫入數(shù)據(jù)
with open("/sd/faceinfo.txt", "a") as f:
for i in range(len(record_ftrtemp)): #循環(huán)遍歷臨時(shí)特征值列表昆著,寫入SD卡
f.write(stu_num+'#'+str(record_ftrtemp[i]))
# 每個(gè)特征值占一行
f.write("\n")
# 關(guān)閉文件
f.close()
except Exception:
save_success = 0 #表示保存到SD卡失敗了
pass
# 如果保存到SD卡成功,則將當(dāng)前特征添加到已知特征列表中术陶,并將學(xué)號(hào)添加到names列表中凑懂;同時(shí)清空臨時(shí)特征值列表和采集次數(shù),顯示錄入成功的提示信息梧宫,并進(jìn)行蜂鳴器聲音提示接谨;最后退出錄入任務(wù)并回到正常模式。
if save_success == 1:
#將當(dāng)前特征添加到已知特征列表塘匣,學(xué)號(hào)添加到names
for i in record_ftrtemp:
record_ftrs.append(i)
names.append(stu_num)
record_ftrtemp.clear() #清空臨時(shí)特征值列表
# 在屏幕上顯示錄入成功的提示信息
a = img.draw_string(0,5, b'Success!', color=(255,0,0),scale=1.4,mono_space=1) #錄入成功
# 在屏幕上顯示圖像
a = lcd.display(img)
#蜂鳴器聲音提示
beep.enable()
beep.freq(1000)
time.sleep(2)
beep.disable()
luru_flag = 0 # 退出錄入任務(wù)
# 回到正常模式
LuRu_mode = False # 錄入模式
Door_mode = False # 門禁模式
Normal_mode = True # 正常模式
#如果保存到SD卡失敗脓豪,則按鍵次數(shù)清零,check_num清零忌卤,學(xué)號(hào)清空
else:
a = img.draw_string(0,5, b'Fail!', color=(255,0,0),scale=1.4,mono_space=1) #錄入失敗
#蜂鳴器聲音提示
beep.enable()
beep.freq(600)
time.sleep(2)
beep.disable()
luru_flag = 0 # 退出錄入任務(wù)
# 回到正常模式
LuRu_mode = False # 錄入模式
Door_mode = False # 門禁模式
Normal_mode = True # 正常模式
# 刪除code變量扫夜,釋放內(nèi)存空間。
del code
最后是人臉?biāo){牙RFID綜合驗(yàn)證模塊驰徊,這個(gè)模塊相較于前面兩個(gè)模塊笤闯,邏輯設(shè)計(jì)較為復(fù)雜,首先判斷是否檢測到人:程序首先會(huì)檢測人是否出現(xiàn)在門禁的監(jiān)控區(qū)域棍厂,如果有人颗味,則將 no_flag 置為1。同時(shí)進(jìn)行垃圾回收牺弹,程序會(huì)定期進(jìn)行垃圾回收浦马,以釋放不再使用的內(nèi)存空間。再接收藍(lán)牙數(shù)據(jù):程序會(huì)讀取藍(lán)牙模塊發(fā)送的數(shù)據(jù)例驹,如果讀取到了數(shù)據(jù)且長度大于等于2捐韩,則進(jìn)行后續(xù)的處理。
a. 如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'open'鹃锈,則程序會(huì)將舵機(jī)旋轉(zhuǎn)以打開門禁荤胁,以實(shí)現(xiàn)臨時(shí)門禁的功能。
b. 如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'erase'屎债,執(zhí)行刪除全部用戶的操作仅政。具體來說,代碼實(shí)現(xiàn)了以下功能:
- 如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'erase'盆驹,則執(zhí)行內(nèi)部代碼塊圆丹。
- 清空名稱列表、特征值列表和人臉信息文件躯喇。
- 打開人臉信息文件辫封,并將其內(nèi)容清空硝枉。清空圖像緩存。
- 繪制矩形和字符串倦微,并在 LCD 屏幕上顯示圖像妻味。
- 發(fā)出蜂鳴器聲音提示。
c. 如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'delete' 欣福,執(zhí)行刪除指定用戶的操作责球。具體來說,代碼實(shí)現(xiàn)了以下功能:
- 如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'delete'拓劝,則執(zhí)行內(nèi)部代碼塊雏逾。截取出要?jiǎng)h除的編號(hào),并打印輸出郑临。
- 逐行讀取人臉信息文件栖博,查找要?jiǎng)h除的編號(hào),并記錄要?jiǎng)h除的行數(shù)牧抵。
- 如果找到了要?jiǎng)h除的行笛匙,則打開人臉信息文件,刪除指定行犀变,并重新寫入文件妹孙。
- 從名稱列表和特征值列表中刪除指定的用戶。
- 繪制矩形和字符串获枝,并在 LCD 屏幕上顯示圖像蠢正。發(fā)出蜂鳴器聲音提示。
- 將程序回到正常模式省店。
d. 如果當(dāng)前處于錄入模式嚣崭,則在 LCD 屏幕上顯示“Register Mode”字樣。如果讀取到的藍(lán)牙數(shù)據(jù)中包含 'register'懦傍,則執(zhí)行人臉注冊操作雹舀。
- 截取出要注冊的編號(hào),并打印輸出粗俱。判斷該編號(hào)是否已經(jīng)被錄入说榆,如果已經(jīng)被錄入,則在 LCD 屏幕上顯示“ID Exist!”字樣寸认,并在屏幕上顯示紅色矩形區(qū)域签财,發(fā)出蜂鳴器聲音提示,并回到正常模式偏塞;否則唱蒸,設(shè)置錄入標(biāo)志位為 1。
- 如果錄入標(biāo)志位為 1灸叼,則進(jìn)行人臉錄入操作神汹。
- 檢測到人臉后庆捺,提取人臉特征,并將其添加到特征值列表 record_ftrs 中慎冤。將編號(hào)和姓名組合成一個(gè)字符串疼燥,并添加到名稱列表 names 中。發(fā)出蜂鳴器聲音提示蚁堤。將錄入標(biāo)志位設(shè)置為 0。
- 將程序回到正常模式但狭。
e. 如果當(dāng)前處于門禁模式披诗,腳本初始化 RFID 模塊并嘗試從中讀取數(shù)據(jù)。如果檢測到有效的 RFID 卡片立磁,代碼將讀取卡片數(shù)據(jù)并根據(jù)不同卡片內(nèi)容執(zhí)行相應(yīng)的操作呈队。如果卡片包含預(yù)期數(shù)據(jù),則觸發(fā)一個(gè)綠色 LED 和一個(gè)舵機(jī)來打開門鎖唱歧。如果卡片包含無效數(shù)據(jù)宪摧,則觸發(fā)一個(gè)紅色 LED 和一個(gè)蜂鳴器來警告用戶。此外颅崩,為了更加豐富使用場景几于,這里還預(yù)留了一個(gè)萬能卡的對應(yīng)信息,保證管理員可以在特殊情況下進(jìn)行無限制開門沿后。
除了 RFID 部分沿彭,“門禁模式”還同時(shí)運(yùn)行人臉識(shí)別算法。如果檢測到人臉尖滚,比較當(dāng)前人臉與存儲(chǔ)人臉相似的置信度喉刘,如果識(shí)別的置信度高于設(shè)定的閾值打毛,則觸發(fā)與有效 RFID 卡片相同的操作源内,控制舵機(jī)打開門禁并且顯示綠燈铆帽。如果人臉識(shí)別分?jǐn)?shù)低于設(shè)定的閾值绵患,顯示分?jǐn)?shù)瞻颂,并計(jì)數(shù)梅尤,如果計(jì)數(shù)超過3次則表示人臉識(shí)別失敗埂淮,開啟紅燈并發(fā)出蜂鳴器聲音
f. 如果當(dāng)前處于正常模式议泵,設(shè)置錄入標(biāo)志和檢查數(shù)字為 0券坞,使用 LCD 顯示屏顯示“等待......”,并將標(biāo)志位 no_people 設(shè)置為 0鬓催。如果當(dāng)前沒有人在操作,程序會(huì)將 LCD 清空并顯示“休眠中......”,并將標(biāo)志位 no_people 設(shè)置為 1恨锚。程序會(huì)在適當(dāng)?shù)臅r(shí)候調(diào)用 del img 和 gc.collect() 來回收內(nèi)存宇驾。其中,del img 用于刪除 img 對象占用的內(nèi)存猴伶,而 gc.collect() 用于回收未被使用的內(nèi)存课舍。
代碼詳細(xì)注釋如下:
# 有人的時(shí)候LCD顯示攝像頭的拍攝畫面
if people_find.value() == 1:
no_flag = 1
# 接收藍(lán)牙數(shù)據(jù)
# 垃圾回收
gc.collect()
# 讀取藍(lán)牙數(shù)據(jù)
text = uart.read()
if text != None and len(text) >= 2: #如果讀取到了數(shù)據(jù)塌西,且大于等于2
# 臨時(shí)開門禁
# 如果藍(lán)牙數(shù)據(jù)中包含 'open'
if 'open' in text:
print("--------藍(lán)牙開門--------")
# 舵機(jī)旋轉(zhuǎn)
Servo(SS,90)
time.sleep(2)
Servo(SS,0)
# 刪除全部用戶命令
# 如果藍(lán)牙數(shù)據(jù)中包含 'erase'
if 'erase' in text:
print("--------刪除全部用戶--------")
# 清空名稱列表、特征值列表和人臉信息文件
names.clear()
record_ftrs.clear()
# 打開文件
file_new = open('/sd/faceinfo.txt', 'w')
# 寫入空字符串
file_new.write(''.join(''))
# 關(guān)閉文件
file_new.close()
# 清除圖像
img.clear()
# 繪制矩形
img.draw_rectangle((90, 85, 140, 70), fill=True, color=(0, 0, 255))
# 繪制字符串
img.draw_string(110, 112, "delete all", color=(255, 255, 255), scale=1.5, mono_space=0)
# 在LCD屏幕上顯示圖像
lcd.display(img)
#蜂鳴器聲音提示
beep.enable()
beep.freq(1000)
time.sleep(2)
beep.disable()
a = img.clear()
# 刪除用戶命令
# 如果藍(lán)牙數(shù)據(jù)中包含 'delete'
if 'del' in text:
print("--------刪除用戶--------")
delnum = text[3:].decode('utf-8') #截取出刪除的學(xué)號(hào)
print('刪除的學(xué)號(hào): ', delnum)
print(delnum)
del text
k=-1
# 打開人臉信息文件
with open('/sd/faceinfo.txt', 'r') as f:
while(1):
# 逐行讀取文件內(nèi)容
thisline=f.readline()
if not thisline:
# 如果文件已讀完
break
# 計(jì)數(shù)器加1
k=k+1
# 判斷是否找到要?jiǎng)h除的學(xué)號(hào)
result = delnum in thisline
# 如果找到了第一個(gè)匹配項(xiàng)
if result==True and find_flag == 0:
# 標(biāo)記為找到
find_flag=1
print('ok')
# 如果找到了多個(gè)匹配項(xiàng)
if result==True and find_flag == 1:
# 記錄要?jiǎng)h除的行數(shù)
delline.append(k)
# 如果匹配項(xiàng)已結(jié)束
if result==False and find_flag == 1:
# 標(biāo)記為未找到
find_flag = 0
break
# 關(guān)閉文件
f.close()
# 如果SD卡中有此人筝尾,那么就刪除捡需,
if delline:
# 按行讀入,刪除最后一行
# 打開文件
file_old = open('/sd/faceinfo.txt', 'r')
# 逐行讀取文件內(nèi)容
lines = [i for i in file_old]
# 刪除指定行數(shù)
del lines[int(delline[0]):int(delline[-1])+1]
# 關(guān)閉文件
file_old.close()
del file_old
# 清空要?jiǎng)h除的行數(shù)列表
delline.clear()
# 再覆蓋寫入
# 打開文件
file_new = open('/sd/faceinfo.txt', 'w')
# 將修改后的內(nèi)容寫入文件
file_new.write(''.join(lines))
# 關(guān)閉文件
file_new.close()
del lines
##刪除姓名列表和特征值列表中的數(shù)據(jù)
#print('之前',names)
i = 0
# 清空名稱列表
temp_num = ''
names = []
# 清空特征值列表
record_ftrs = []
# 垃圾回收
gc.collect()
try:
# 打開人臉信息文件
with open("/sd/faceinfo.txt", "r") as f:
while(1):
# 垃圾回收
gc.collect()
# 逐行讀取文件內(nèi)容
lin = f.readline()
# 如果文件已讀完
if not lin:
break
stunum = lin[0:lin.index('#')] #獲取學(xué)號(hào)
lin = lin[lin.index('#')+1:] #截取除了學(xué)號(hào)以外的字符串
stu_name = lin[0:lin.index('#')] #獲取姓名
names.append(stunum+'#'+stu_name) #追加到姓名列表
lin = lin[lin.index('#')+1:] #截取人臉特征
record_ftrs.append(eval(lin)) #向人臉特征列表中添加已存特征
except:
pass
# 垃圾回收
gc.collect()
# 清除圖像
img.clear()
# 繪制矩形
img.draw_rectangle((90, 85, 140, 70), fill=True, color=(0, 0, 255))
# 繪制字符串
img.draw_string(110, 112, "delete %s"%delnum, color=(255, 255, 255), scale=1.5, mono_space=0)
# 在LCD屏幕上顯示圖像
lcd.display(img)
#蜂鳴器聲音提示
beep.enable()
beep.freq(1000)
time.sleep(2)
beep.disable()
a = img.clear()
# 回到正常模式
LuRu_mode = False # 錄入模式
Door_mode = False # 門禁模式
Normal_mode = True # 正常模式
else:
a = img.clear()
# 繪制矩形
a = img.draw_rectangle((90, 85, 140, 70), fill=True, color=(0, 0, 255))
# 繪制字符串
a = img.draw_string(118, 112, "No people!", color=(255, 255, 255), scale=1.5, mono_space=0)
# 在LCD屏幕上顯示圖像
a = lcd.display(img)
#蜂鳴器聲音提示
beep.enable()
beep.freq(600)
time.sleep(2)
beep.disable()
a = img.clear()
# 回到正常模式
LuRu_mode = False # 錄入模式
Door_mode = False # 門禁模式
Normal_mode = True # 正常模式
# 檢測按鍵
# 錄入模式按鍵
if LuRu_mode:
try:
# 在屏幕上顯示“錄入模式”字樣
a = img.draw_string(0,0, b'Register Mode', color=(0,255,0),scale=1.6,mono_space=1)
except:
pass
# 判斷藍(lán)牙數(shù)據(jù)是否讀取到并且長度大于等于2
if text != None and len(text) >= 2: #如果讀取到了數(shù)據(jù)筹淫,且大于等于2
# 判斷是否收到“register”命令站辉,如果是則進(jìn)行人臉注冊
if 'register' in text:
print("--------人臉注冊--------")
stu_num = text[2:].decode('utf-8') # 截取出學(xué)號(hào)
print('學(xué)號(hào): ', stu_num)
# 判斷該學(xué)號(hào)是否已被錄入
# 如果該學(xué)號(hào)已經(jīng)被錄入,顯示“ID Exist!”字樣损姜,并在屏幕上顯示紅色矩形區(qū)域
if stu_num in names:
a = img.clear()
a = img.draw_rectangle((90, 85, 140, 70), fill=True, color=(0, 0, 255))
a = img.draw_string(118, 112, "ID Exist!", color=(255, 255, 255), scale=1.5, mono_space=0)
a = lcd.display(img)
#蜂鳴器聲音提示
beep.enable()
beep.freq(600)
time.sleep(2)
beep.disable()
# 回到正常模式
LuRu_mode = False # 錄入模式
Door_mode = False # 門禁模式
Normal_mode = True # 正常模式
# 如果學(xué)號(hào)沒有被錄入饰剥,進(jìn)行下一步錄入
else:
# 設(shè)置錄入標(biāo)志位為1
luru_flag = 1
# 門禁模式按鍵
if Door_mode:
# 錄入標(biāo)志位設(shè)置為0
luru_flag = 0
# 校驗(yàn)次數(shù)設(shè)置為0
check_num = 0
# 在屏幕上顯示“門禁模式”字樣
a = img.draw_string(0,0, b'Entrance Mode', color=(0,255,0),scale=1.6,mono_space=1)
# ================================== RFID ================================
# time.sleep(2)
# from micropython import const
#############################################
#continue_reading = True
# 20: CS_NUM;
fm.register(CS_NUM, fm.fpioa.GPIOHS20, force=True)
# set gpiohs work mode to output mode
cs = GPIO(GPIO.GPIOHS20, GPIO.OUT)
spi1 = SPI(SPI.SPI_SOFT, mode=SPI.MODE_MASTER, baudrate=SPI_FREQ_KHZ * 1000,
polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=SPI_SCK, mosi=SPI_MOSI, miso=SPI_MISO)
# Create an object of the class MFRC522
MIFAREReader = MFRC522(spi1, cs)
# time.sleep_ms(300)
# Scan for cards
(status, ataq) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQALL)
# If a card is found
if status == MIFAREReader.MI_OK:
# 如果卡片被找到,打印卡片類型和UID
print("Card detected type: ",hex(ataq[0]<<8|ataq[1]))
# Get the UID of the card
(status, uid) = MIFAREReader.MFRC522_Anticoll()
# If we have the UID, continue
if status == MIFAREReader.MI_OK:
# Print UID
print("Card read UID: " +
str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3]))
# This is the default key of M1(S50) for authentication
# M1卡片的默認(rèn)密鑰
key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
# Select the scanned tag
# 選擇掃描到的標(biāo)簽
MIFAREReader.MFRC522_SelectTag(uid)
# Authenticate
# 驗(yàn)證卡片密鑰
status = MIFAREReader.MFRC522_Auth(
MIFAREReader.PICC_AUTHENT1A, 0x12, key, uid)
# Check if authenticated
# 檢查是否驗(yàn)證成功
#if status == MIFAREReader.MI_OK:
# 示例:定義一個(gè)包含16個(gè)元素的列表摧阅,并將第一個(gè)元素設(shè)為'Y'
##data = ['Y',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
##data = ['N',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
## Fill the data with 0~16
#for x in range(0, 16):
#data.append(x)
## Write the data
# 向扇區(qū)0x12寫入數(shù)據(jù)
#print("Sector 11 will now be filled with 1~16:")
# 使用MFRC522_Write方法將data列表寫入扇區(qū)0x12
#status = MIFAREReader.MFRC522_Write(0x12, data)
# 如果驗(yàn)證成功汰蓉,讀取RFID模塊中的數(shù)據(jù)
try:
if status == MIFAREReader.MI_OK:
print("start to read")
# read the data
# MIFAREReader.MFRC522_Read(0x12)
datas = MIFAREReader.MFRC522_Read(0x12)
#讀出卡中的id號(hào)
strnum = ' '
strnum = chr(datas[0])+str(datas[1])+str(datas[2])+str(datas[3])+str(datas[4])
#如果第一個(gè)字符不是B則說明卡錯(cuò)誤
if chr(datas[0]) == 'Y':
led_g.value(0) # 綠燈亮
Servo(SS,90)
time.sleep(2)
Servo(SS,0)
led_g.value(1) # 綠燈滅
if chr(datas[0]) == 'N':
#蜂鳴器聲音提示
beep.enable()
beep.freq(300)
time.sleep(2)
beep.disable()
##讀出卡中的姓名
#if datas[11]==0: #名字兩個(gè)字
#strname = "b'"+hex(datas[5])+hex(datas[6])+hex(datas[7])+hex(datas[8])+hex(datas[9])+hex(datas[10])+"'"
#else : #名字三個(gè)字
#strname = "b'"+hex(datas[5])+hex(datas[6])+hex(datas[7])+hex(datas[8])+hex(datas[9])+hex(datas[10])+hex(datas[11])+hex(datas[12])+hex(datas[13])+"'"
#strname = eval(strname.replace('0','\\')).decode('utf8')
# Stop
MIFAREReader.MFRC522_StopCrypto1()
#else:
#print("Authentication error")
except Exception as e:
beep.enable()
beep.freq(1000)
time.sleep(2)
beep.disable()
try:
# 如果人臉識(shí)別分?jǐn)?shù)高于設(shè)定的閾值,顯示學(xué)號(hào)與分?jǐn)?shù)棒卷,并開啟綠燈
if max_score > ACCURACY:
a = img.draw_string(i.x()+4,i.y()-20, ("%s: %2.1f" % (names[index], max_score)), color=(0,255,0),scale=2) # 顯示學(xué)號(hào)與分?jǐn)?shù)
a = lcd.display(img)
print("--------人臉識(shí)別成功--------")
led_g.value(0) # 綠燈亮
Servo(SS,90)
time.sleep(2)
Servo(SS,0)
led_g.value(1) # 綠燈滅
shibie_num = 0
elif code:
# 如果人臉識(shí)別分?jǐn)?shù)低于設(shè)定的閾值顾孽,顯示分?jǐn)?shù),并計(jì)數(shù)比规,如果計(jì)數(shù)超過3次則表示人臉識(shí)別失敗若厚,開啟紅燈并發(fā)出蜂鳴器聲音
img.draw_string(i.x()+4,i.y()-20, ("%s: %2.1f" % ("No",max_score)), color=(0,255,0),scale=2) # 顯示分?jǐn)?shù)
a = lcd.display(img)
shibie_num = shibie_num + 1
if shibie_num > 3:
shibie_num = 0
print("--------人臉識(shí)別失敗--------")
led_r.value(0) # 紅燈亮
beep.enable()
beep.freq(600)
time.sleep(2)
beep.disable()
led_r.value(1) # 紅燈滅
except:
pass
# 刪除變量code,釋放內(nèi)存空間
del code
# 正常模式按鍵
# 設(shè)置錄入標(biāo)志和檢查數(shù)字為0苞俘,使用LCD顯示屏顯示“等待……”
if Normal_mode:
luru_flag = 0
check_num = 0
a = img.draw_string(0,0, b'Waiting......', color=(0,255,0),scale=1.6,mono_space=1)
## ================================== RFID ================================
## time.sleep(2)
## from micropython import const
#################### config ###################
#CS_NUM = const(18)
#SPI_FREQ_KHZ = const(600)
#SPI_SCK = const(19)
#SPI_MOSI = const(8)
#SPI_MISO = const(15)
##############################################
##continue_reading = True
## 20: CS_NUM;
#fm.register(CS_NUM, fm.fpioa.GPIOHS20, force=True)
## set gpiohs work mode to output mode
#cs = GPIO(GPIO.GPIOHS20, GPIO.OUT)
#spi1 = SPI(SPI.SPI_SOFT, mode=SPI.MODE_MASTER, baudrate=SPI_FREQ_KHZ * 1000,
#polarity=0, phase=0, bits=8, firstbit=SPI.MSB, sck=SPI_SCK, mosi=SPI_MOSI, miso=SPI_MISO)
## Create an object of the class MFRC522
#MIFAREReader = MFRC522(spi1, cs)
## time.sleep_ms(300)
## Scan for cards
#(status, ataq) = MIFAREReader.MFRC522_Request(MIFAREReader.PICC_REQALL)
## If a card is found
#if status == MIFAREReader.MI_OK:
#print("Card detected type: ",hex(ataq[0]<<8|ataq[1]))
## Get the UID of the card
#(status, uid) = MIFAREReader.MFRC522_Anticoll()
## If we have the UID, continue
#if status == MIFAREReader.MI_OK:
## Print UID
#print("Card read UID: " +
#str(uid[0])+","+str(uid[1])+","+str(uid[2])+","+str(uid[3]))
## This is the default key of M1(S50) for authentication
#key = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]
## Select the scanned tag
#MIFAREReader.MFRC522_SelectTag(uid)
## Authenticate
#status = MIFAREReader.MFRC522_Auth(
#MIFAREReader.PICC_AUTHENT1A, 0x12, key, uid)
## Check if authenticated
##if status == MIFAREReader.MI_OK:
###data = ['Y',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
###data = ['N',0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
### Fill the data with 0~16
##for x in range(0, 16):
##data.append(x)
### Write the data
##print("Sector 11 will now be filled with 1~16:")
##status = MIFAREReader.MFRC522_Write(0x12, data)
#try:
#if status == MIFAREReader.MI_OK:
#print("start to read")
## read the data
## MIFAREReader.MFRC522_Read(0x12)
#datas = MIFAREReader.MFRC522_Read(0x12)
##讀出卡中的id號(hào)
#strnum = ' '
#strnum = chr(datas[0])+str(datas[1])+str(datas[2])+str(datas[3])+str(datas[4])
##如果第一個(gè)字符不是B則說明卡錯(cuò)誤
#if chr(datas[0]) == 'Y':
#led_g.value(0) # 綠燈亮
#Servo(SS,90)
#time.sleep(2)
#Servo(SS,0)
#led_g.value(1) # 綠燈滅
#if chr(datas[0]) == 'N':
##蜂鳴器聲音提示
#beep.enable()
#beep.freq(300)
#time.sleep(2)
#beep.disable()
###讀出卡中的姓名
##if datas[11]==0: #名字兩個(gè)字
##strname = "b'"+hex(datas[5])+hex(datas[6])+hex(datas[7])+hex(datas[8])+hex(datas[9])+hex(datas[10])+"'"
##else : #名字三個(gè)字
##strname = "b'"+hex(datas[5])+hex(datas[6])+hex(datas[7])+hex(datas[8])+hex(datas[9])+hex(datas[10])+hex(datas[11])+hex(datas[12])+hex(datas[13])+"'"
##strname = eval(strname.replace('0','\\')).decode('utf8')
## Stop
#MIFAREReader.MFRC522_StopCrypto1()
##else:
##print("Authentication error")
#except Exception as e:
#beep.enable()
#beep.freq(1000)
#time.sleep(2)
#beep.disable()
a = lcd.display(img)
# 無人的時(shí)候LCD黑屏盹沈,休眠狀態(tài)(錄入的時(shí)候不能進(jìn)入休眠狀態(tài))
# 如果沒有人在操作,將LCD清空并顯示“休眠中……”吃谣,并將標(biāo)志位no_people設(shè)置為1乞封。
elif luru_flag == 0:
no_people = 1
# 如果有人在操作,則將標(biāo)志位no_people和no_flag都置為0岗憋,表示有人正在操作肃晚,不進(jìn)行休眠。
if no_people == 1 and no_flag == 1:
no_people = 0
no_flag = 0
a = img.clear() # 清空一次LCD
# 最后仔戈,將img對象在LCD上顯示出來关串,并回收內(nèi)存。
a = img.draw_string(40,110, b'Suspending......', color=(0,255,0),scale=2,mono_space=1)
a = lcd.display(img)
# del img用于刪除img對象占用的內(nèi)存
del img
# gc.collect()用于回收未被使用的內(nèi)存监徘。
gc.collect()
5.各模塊實(shí)操結(jié)果展示和實(shí)現(xiàn)指標(biāo)
[圖片上傳失敗...(image-4bccf4-1694761641000)]
圖5-1人臉錄入成功
輸入“register****
”(****
代表錄入人臉編號(hào))后按照yolo v2算法采集196維人臉數(shù)據(jù)(3輪18次采樣)晋修,并儲(chǔ)存在SD卡文件中,且屏幕顯示采樣進(jìn)度凰盔,錄入完成屏幕顯示“successful”墓卦,蜂鳴器發(fā)低聲。
[圖片上傳失敗...(image-a621b1-1694761641000)]
圖5-2人臉識(shí)別成功
[圖片上傳失敗...(image-61aacd-1694761641000)]
圖5-3人臉識(shí)別比對失敗
門禁模式時(shí)户敬,人臉識(shí)別框上會(huì)顯示序列號(hào)和相似度落剪,設(shè)定比對閾值睁本,此處設(shè)置75,高于則蜂鳴器發(fā)低聲且舵機(jī)旋轉(zhuǎn)忠怖,低于則蜂鳴器發(fā)高聲舵機(jī)無反應(yīng)呢堰。
[圖片上傳失敗...(image-13fa29-1694761641000)]
圖5-4 人臉數(shù)據(jù)刪除成功
輸入“delete****
”則刪除對應(yīng)用戶儲(chǔ)存在SD卡的特征值,蜂鳴器發(fā)高聲凡泣。且屏幕顯示ok枉疼,輸入“erase”則刪除SD卡內(nèi)所有用戶人臉特征值,蜂鳴器發(fā)高聲且屏幕顯示delete all鞋拟。輸入“open”則無條件控制舵機(jī)旋轉(zhuǎn)往衷,用作臨時(shí)開關(guān)門禁。
[圖片上傳失敗...(image-a39837-1694761641000)]
圖5-5藍(lán)牙app操作
[圖片上傳失敗...(image-90a718-1694761641000)]
圖5-6刪除所有人臉數(shù)據(jù)
6.可改進(jìn)之處及拓展方向
6.1 不足及改進(jìn)之處
此部分略严卖。
6.2 系統(tǒng)方案可拓展方向
此部分略。
7.參考資料
1布轿、RFID 學(xué)習(xí)資料
https://blog.csdn.net/HuangChen666/article/details/114024767?spm=1001.2014.3001.5506
2哮笆、K210學(xué)習(xí)系列
https://blog.csdn.net/Thousand_drive/article/details/123796878?spm=1001.2014.3001.5506
3、人臉識(shí)別學(xué)習(xí)資料
4汰扭、固件燒錄稠肘、信息儲(chǔ)存學(xué)習(xí)資料
5、藍(lán)牙模塊學(xué)習(xí)資料
[1] Zhu, X., Lei, Z., Liu, X., Shi, H., & Li, S. Z. (2018). Face recognition: From traditional to deep learning methods. Advances in Computers, 113, 1-69.
[2] AlBdairi, A.J.A.; Xiao, Z.; Alkhayyat, A.; Humaidi, A.J.; Fadhel, M.A.; Taher, B.H.; Alzubaidi, L.; Santamaría, J.; Al-Shamma, O. Face Recognition Based on Deep Learning and FPGA for Ethnicity Identification. Appl. Sci. 2022, 12, 2605. https://doi.org/10.3390/app12052605
[3] Chen, J., Liao, S., & Liu, Y. (2021). Intelligent access control system based on deep learning and IoT. Journal of Physics: Conference Series, 1821(1), 012074.
[4] Derbel, A., Vivet, D. and Emile, B. (2015), Access control based on gait analysis and face recognition. Electron. Lett., 51: 751-752. https://doi.org/10.1049/el.2015.0767
[5] A. Nag, J. N. Nikhilendra and M. Kalmath, "IOT Based Door Access Control Using Face Recognition," 2018 3rd International Conference for Convergence in Technology (I2CT), Pune, India, 2018, pp. 1-3, doi: 10.1109/I2CT.2018.8529749.
[6] Radzi S A, Alif M K M F, Athirah Y N, et al. IoT based facial recognition door access control home security system using raspberry pi[J]. International Journal of Power Electronics and Drive Systems, 2020, 11(1): 417.