張若萱,董 晨(通信作者),彭業(yè)誠,韓宇陽,張?zhí)@婷,張 照,李鑫磊,吳小剛,朱秀美
(天津理工大學計算機科學與工程學院 天津 300384)
近年,疲勞駕駛已成為交通重大安全隱患之一。駕駛?cè)藛T在疲勞狀態(tài)時,對周圍環(huán)境的感知力、判斷力以及車輛的操控力都有不同程度的下降,容易發(fā)生交通事故。統(tǒng)計數(shù)據(jù)表明,每年約有9 000 人死于疲勞駕駛,截止到2021 年底,每年因為疲勞駕駛的車禍死亡率甚至達到21%。因此,高性能的疲勞駕駛狀態(tài)實時監(jiān)測及預警系統(tǒng),對改善我國交通安全現(xiàn)狀具有重大的意義。開發(fā)初期,團隊對大量駕駛?cè)藛T和相關(guān)疲勞駕駛檢測產(chǎn)品進行了社會調(diào)研,結(jié)果顯示,應用市場中部分疲勞檢測系統(tǒng)存在功能單一、實用性低或價格昂貴等問題。針對市場應用需求和現(xiàn)有技術(shù)的調(diào)查[1-6],面向個人及企業(yè)駕駛用戶,本項目開發(fā)一種新型的疲勞檢測系統(tǒng),改進了傳統(tǒng)疲勞檢測系統(tǒng)固化的攝像儀模式和高成本的特點,增強了檢測的移動和普適性。通過安卓APP 端使用手機攝像頭采集駕駛?cè)藛T的面部視頻,基于PFLD(Practical Facial Landmark Detector)[7-9]人臉檢測點算法對面部特征實時檢測,在安卓端進行相關(guān)調(diào)用,調(diào)用之后對面部檢測得到的數(shù)據(jù)進行高速Webrtc 傳輸,由后臺算法模型進行相關(guān)閾值二分推演,推演后判斷疲勞結(jié)果,采用Socket 傳回給安卓端APP 頁面展示,并且發(fā)出蜂鳴預警,若多次預警無效,對用戶設置的緊急聯(lián)系人進行短信通知。此外,在云服務器端記錄疲勞狀態(tài)歷史信息以及相關(guān)地址信息,生成可視化圖表,在個人中心可進行回查,對下次駕駛疲勞狀態(tài)進行預測和警醒。
系統(tǒng)采用阿里云服務器+Android APP 客戶端模式,主要實現(xiàn)疲勞檢測、疲勞提醒、可視化蜂鳴預警、疲勞歷史回查、疲勞報表生成、緊急聯(lián)系人、行車導航和個人中心等功能。
在疲勞檢測功能中,系統(tǒng)利用安卓手機攝像頭和PFLD人臉識別算法定位人臉特征點,采取融合左右眼開合度的方式增強算法的魯棒性,輔以計算駕駛?cè)藛T眨眼次數(shù)和打哈欠次數(shù)實現(xiàn)疲勞駕駛檢測,當系統(tǒng)發(fā)現(xiàn)駕駛者疲勞,實時蜂鳴報警提醒,引起駕駛者注意,在一定程度上保證駕駛的安全性。同時,設置緊急聯(lián)系人機制,在多次預警無效的狀況下,聯(lián)系緊急聯(lián)系人。在疲勞報表生成功能中,系統(tǒng)同步記錄各個時間段駕駛?cè)藛T的疲勞駕駛情況,對歷史特征數(shù)據(jù)進行分析和可視化,駕駛?cè)藛T可以通過查看歷史疲勞數(shù)據(jù),實現(xiàn)疲勞預警和干預;在行車導航功能中,當駕駛?cè)藛T輸入目的地后,自動規(guī)劃最優(yōu)的行車路線,實現(xiàn)智能輔助駕駛功能。
(1)后端服務器:實現(xiàn)數(shù)據(jù)交互,為保證高內(nèi)聚低耦合,進行模塊化開發(fā),系統(tǒng)間功能相互獨立單一又交叉配合。使用Springboot 作為基礎框架,使用Mybatis 作為持久層框架。
(2)流服務器:通過網(wǎng)絡播放流媒體文件,節(jié)省大量的磁盤空間開銷,提高系統(tǒng)運行效率,使用nginx+nginx-rtmp-module+ffmpeg 搭建流媒體服務器。
(3)數(shù)據(jù)庫:使用MySQL 作為后臺數(shù)據(jù)庫,Redis 作為緩存,持久化存儲用戶信息。
(4)算法服務器:執(zhí)行算法并用Websocket 向安卓端APP 推送執(zhí)行結(jié)果。算法服務器采用django+Django REST framework+dwebsocket 技術(shù)實現(xiàn)。
客戶端通過RTMP(Real Time Messaging Protocol,實時消息傳輸協(xié)議)上傳視頻流到nginx 服務器,經(jīng)過nginx-rtmp-module 處理,算法服務器端使用RTMP 拉流獲得m3u8 視頻流,進行算法預測。向后端Springboot 服務器發(fā)送帶有預測結(jié)果的http 請求,后端服務器對token進行驗證,并把結(jié)果通過Websocket 推送給客戶端。為了增強部署的可移植性、降低硬件要求和應用環(huán)境之間耦合度,利用Docker 進行后端應用容器化部署。
1.2.1 Android 客戶端框架
基于Android 6.0,使用Kotlin 語言和JVM 引擎,采用MVC 架構(gòu)進行開發(fā)。對于Android 客戶端,采用統(tǒng)一接口設計,由于后端返回一個封裝過的JSON 對象,故進行一層解封,加入異步機制Promise 來控制事件。
1.2.2 通信交互
使用WebSocket 協(xié)議實時接收后端提供的檢測結(jié)果并顯示給用戶?;贏ndroid Webview JSBridge 接口,使用開源庫DSBridge 完成Android 與Vue 間通信。
1.2.3 圖像數(shù)據(jù)采集推流
為將延遲盡量降低,判斷及時有效,通過手機攝像頭采集視頻,刷新至GLSurfaceView 提供預覽,將其傳至native 層進行編碼,保證預覽流暢性?;贘ava JNI 接口與Android NDK,使用C 語言視頻編碼庫,執(zhí)行RTMP 視頻流硬件編碼,保證視頻編碼流暢性。
駕駛疲勞狀態(tài)檢測流程如下圖1 所示,在通過手機攝像頭獲取人臉圖片后,得到臉部模型定位特征點,根據(jù)其中的嘴部和眼部特征點計算一定時間內(nèi)眨眼和打哈欠的次數(shù),并對這個次數(shù)設置一定的閾值進行疲勞狀況判別。疲勞檢測算法流程見圖1。
為了提取面部特征,系統(tǒng)使用了人臉關(guān)鍵點檢測,自動定位一組預定義的人臉基準點,但人臉經(jīng)常是出現(xiàn)在控制不足甚至沒有約束的環(huán)境中。在不同的照明條件下,臉部呈現(xiàn)各種各樣的姿勢、表情和形狀,有時還有部分遮擋。為了使面部檢測更準確,采用PFLD 算法,PFLD 是一個實用的人臉關(guān)鍵點檢測算法,PFLD 算法在復雜情況下也可以保持高精度。針對全局變化,PFLD 采用輔助網(wǎng)絡來估計人臉樣本的集合信息。針對數(shù)據(jù)不平衡,設計新的損失函數(shù),加大對難樣本的懲罰力度,很適合用于疲勞駕駛的人臉檢測部分。
首先,使用PFLD 算法在安卓端采集面部特征點,該算法將對駕駛?cè)藛T面部輪廓、眉毛、鼻子關(guān)鍵點進行檢測,在本系統(tǒng)中,主要使用嘴部和眼部的關(guān)鍵點。
2.1.1 眼部修正優(yōu)化
在使用PFLD 算法后,可以得到嘴部和眼部的關(guān)鍵點和相關(guān)數(shù)據(jù),由于人眼部的疲勞特征一般可以采用眼睛的開合度和時長占比來表示,利用Soukupová 提出的眼睛長寬比(eye aspect ration,EAR)[10]判斷駕駛?cè)说钠跔顟B(tài),當駕駛?cè)藳]有疲勞時,人的眼睛處于正常睜開狀態(tài),此時 EAR 值基本固定不變,在某個值上下波動;當駕駛?cè)似跁r,人的眼睛處于閉合狀態(tài),此時EAR 迅速變小,接近于零,EAR 的計算如下:
但公式(1)只用到了左眼的開合度信息,一般情況下,若駕駛?cè)藛T發(fā)生疲勞,會產(chǎn)生左右眼同步的情況,為了提高算法的魯棒性,嘗試采取融合左右眼開合度的方式計算:
公式(2)融合了駕駛者的左右眼信息,使檢測更加精確。
2.1.2 眨眼和打哈欠次數(shù)計算
在獲取駕駛者的眼睛長寬比后,模型將計算眨眼和打哈欠次數(shù)。在本實驗中,使用PERCLOS(眨眼閾值標準)和打哈欠持續(xù)時間這兩個特征,其中PERCLOS 以P70 作為判斷標準(即一段時間內(nèi)“閉眼”時間占據(jù)總時間的70%以上,即可認定被駕駛?cè)藛T處于疲勞狀態(tài))。打哈欠持續(xù)時間取最大持續(xù)時間。當檢測結(jié)束時間到達時,若還有動作正在進行,檢測時間則會延長,直到?jīng)]有正在進行中的動作為止。其中,使用參數(shù)標準為:
PERCLOS(P70 標準):0.7(閉眼時間占比高于此值判定為疲勞)
閉眼EAR 閾值(單眼):0.25(閉眼時間占比低于此值檢測為閉眼)
打哈欠EAR 閾值:0.40(打哈欠時間高于此值檢測為打哈欠)
打哈欠持續(xù)幀數(shù)閾值:50(打哈欠時間高于此值為疲勞狀態(tài))
在計算完左右眼開合度、眨眼次數(shù)和打哈欠次數(shù)后,使用SVM(support vector machines,SVM)支持向量機進行判定。SVM 支持向量機是一種二分類模型,是定義在特征空間上的間隔最大的線性分類器,能夠正確劃分訓練數(shù)據(jù)集,并且獲得幾何間隔最大的分離超平面,根據(jù)劃分的平面來完成分類。根據(jù)SVM 支持向量機原理,可以用來對駕駛?cè)藛T的疲勞狀態(tài)做判別,具體過程見圖3。
在本次實驗中,支持向量機算法選擇Linear 線性核函數(shù)。由SVM 模型給出一個二分推理:0 為正常狀態(tài),1為疲勞狀態(tài)。在對 SVM 支持向量機進行訓練時,設定損失函數(shù)閾值為0.05,當損失函數(shù)值低于0.05 時結(jié)束訓練。
在模型搭建好后,需要用數(shù)據(jù)集訓練模型,本次實驗使用了YawDD 數(shù)據(jù)集。YawDD 數(shù)據(jù)集是駕駛狀態(tài)數(shù)據(jù)集,由Abtahi 等研究整理,包含了多種不同面部行為,但不能直接用于疲勞檢測算法驗證,通過對疲勞狀態(tài)標簽篩選,得到優(yōu)化后的數(shù)據(jù)集用于疲勞算法處理,主要包括以下步驟:(1)視頻采集:從手機攝像頭獲取駕駛者面部特征視頻;(2)圖片獲?。阂?0 幀/s 左右速率對視頻數(shù)據(jù)集采樣;(3)標記篩選:對圖片中駕駛行為進行標記篩選;(4)人臉檢測:以2 s 為最小量化時間,對每個量化時間里每一幀圖片進行檢測,得到相應特征值及推理結(jié)果。
在數(shù)據(jù)集獲取完畢后,將優(yōu)化后的數(shù)據(jù)集放入模型中進行訓練。
為了驗證疲勞駕駛檢測方案能否達到預期效果,進行了左右眼狀態(tài)識別測試以及嘴部哈欠測試實驗,測試結(jié)果顯示眼部以及嘴部疲勞準確率均可達90%。
為了驗證眼部優(yōu)化是否提高了識別疲勞狀態(tài)的準確率,進行了對比實驗。通過采集現(xiàn)實生活中駕駛狀態(tài)視頻,大約500 條,將視頻經(jīng)過圖片采樣后,使用眼部修正優(yōu)化算法和未使用眼部修正優(yōu)化算法進行計算,并進行算法識別準確度對比,得到如圖4 所示的對比測試結(jié)果。
根據(jù)以上算法準確度對比圖可知,眼部修正優(yōu)化有助于模型準確率提升。本模型主要使用PFLD 算法和SVM算法,通過PFLD 算法檢測人臉關(guān)鍵點,計算眼睛開合度并對其進行了修正優(yōu)化,計算駕駛者眨眼和打哈欠次數(shù),使用SVM 對上面計算結(jié)果進行分類,判斷駕駛者是否疲勞。模型創(chuàng)新點主要如下:(1)在模型中,人臉檢測部分選擇使用了PFLD 算法,該算法在復雜情況下也可以保持高精度,算法所占內(nèi)存較小,計算量小,運行速度快。(2)在模型中,對關(guān)鍵點使用了眼部數(shù)據(jù)的修正優(yōu)化,融合了左右眼開合度計算的數(shù)據(jù),使得結(jié)果更加準確,模型更加魯棒。(3)整體模型運行速度快,占內(nèi)存小,適合駕駛者在移動端使用。
該系統(tǒng)將主要運行在手機安卓端,使用手機RGB 攝像頭捕捉駕駛者視頻和圖像,再調(diào)用經(jīng)過訓練的模型進行判別,主要使用Java 語言實現(xiàn)。
為方便程序調(diào)用安卓手機攝像頭,通過request Permission 方法向Android 系統(tǒng)申請相機和存儲權(quán)限。為了使算法模型運行更快,先將模型文件拷貝到手機存儲中。啟動Android 相機,獲取機型所支持的相機分辨率列表,選擇與手機屏幕尺寸比例最接近的圖像寬度和圖像高度,便于預覽畫面。設置輸出格式為NV21,并設置onPreviewFrame 回調(diào)以得到相機數(shù)據(jù)。申請一塊大小為圖像寬度×圖像高度×2 的數(shù)據(jù)暫存區(qū)供模型計算,在每次相機回調(diào)時將得到的圖像數(shù)據(jù)拷貝到暫存區(qū),調(diào)用方法觸發(fā)底層模型計算。計算部分由C++編寫并以SO 庫形式封裝,在程序加載時裝入內(nèi)存。
計算部分讀取暫存區(qū)中的圖像數(shù)據(jù)和手機存儲中的模型文件進行運算,得到面部106 特征點的橫坐標與縱坐標。特征點坐標存儲于一個106×2 大小的數(shù)組中,當計算完成后,以回調(diào)形式傳遞特征點坐標數(shù)組至Kotlin 應用層,并封裝為Face 類以供后續(xù)特征值計算使用。在計算特征值時,定義特征點模型的40 次捕捉為一次量化,在每次量化結(jié)束時計算該次量化的特征值以減少誤差。疲勞模型使用的特征值共有兩個,分別是P70 和maxMouth,其中P70 表示一次量化內(nèi)閉眼次數(shù),maxMouth 表示一次量化內(nèi)最大張嘴次數(shù)。當一次量化結(jié)束時,若特征點描述判斷仍在張嘴狀態(tài),則繼續(xù)進行捕捉直到張嘴狀態(tài)結(jié)束再進行計算。
3.2.1 使用SurfaceView 渲染相機回傳的預覽數(shù)據(jù)
SurfaceView 開啟一個子線程來對畫面進行刷新,對SurfaceView 的繪制并不會影響到主線程的運行。在底層代碼中實現(xiàn)了雙緩沖機制,適用于顯示復雜 UI 或頻繁刷新的圖像的情況。SurfaceView 直接渲染相機回傳的預覽數(shù)據(jù),數(shù)據(jù)拷貝次數(shù)較少,渲染效率高。
3.2.2 使用NV21 格式編碼圖像數(shù)據(jù)作為特征點模型的輸入
NV21 是一種YUV 像素排列方式。“Y”表示灰度值,明亮程度;而“U”和“V”表示色彩信息代表了顏色的色調(diào)Cr(V)和飽和度Cb(U)。傳統(tǒng)YUV444 采樣中,每一個Y 對應一組UV 分量8+8+8=24 bits(3 個字節(jié))。而NV21采用YUV420 采樣,每4 個Y 共用1 組UV 分量,1 個YUV占8+2+2=12 bits 1.5 個字節(jié),減少對內(nèi)存的消耗,提高圖像數(shù)據(jù)處理速度,由于灰度值不共享,這種采樣方式不會造成太大的精度損失。同時,NV21 是一種two-plane 模式,即Y 和UV 分為兩個Plane,但是UV(CbCr)為交錯存儲,而不是分為3 個plane,保證了模型可以實時分析數(shù)據(jù),提高計算效率。
3.2.3 使用native 層進行模型計算
圖像數(shù)據(jù)處理是典型的CPU 密集型任務,Android應用程序以字節(jié)碼的形式運行于JVM 之上,這就導致了JVM 中指令的執(zhí)行效率遠不如機器碼的執(zhí)行效率。由于Android 基于Linux Kernel,也繼承了Linux 中所有SO相關(guān)的設計,為了保證圖像數(shù)據(jù)處理任務快速完成,將面部106 特征點計算程序以C++編寫并封裝為SO 庫。SO 是與平臺相關(guān)的二進制機器碼,沒有解釋編譯的開銷,執(zhí)行速度較快。
3.2.4 使用JSBridge 實現(xiàn)與H5 端的混合開發(fā)
由于應用中存在一些經(jīng)常更新的頁面,如個人中心、緊急聯(lián)系人設置等,在制作這些頁面時,比起編寫Android 代碼,使用H5 編寫效率更高。這時Android原生為H5 提供宿主環(huán)境,H5 提供上層顯示。兩者使用JSBridge 進行交互:JavaScript 調(diào)用Native 的方法是通過WebView 提供的接口,向JavaScript 的 Context(window)中注入對象或者方法,讓JavaScript 調(diào)用時,直接執(zhí)行相應的 Native 代碼邏輯;Native 調(diào)用JavaScript 執(zhí)行拼接JavaScript 字符串,從外部調(diào)用JavaScript 中的方法。
3.2.5 組件化架構(gòu)
由于APP 含有多個模塊(檢測、導航、報表等),各個模塊之間耦合較輕。為了提高APP 開發(fā)效率,在開發(fā)過程中進行了組件化解耦。實現(xiàn)了加快編譯速度,提高了協(xié)作效率,實現(xiàn)了基礎組件重用的優(yōu)化。
本項目提出了一種基于PFLD 人臉識別的多特征疲勞駕駛檢測系統(tǒng),通過修正PFLD 人臉識別算法優(yōu)化雙眼校正,高效精準實現(xiàn)疲勞判定。系統(tǒng)功能完備,通過手機端APP實現(xiàn)交互,使用便捷成本低,具有一定的市場應用前景。下一步,引入心率檢測光感,通過LFP/HFP(高低心率比)計算駕駛?cè)藛T疲勞度,輔以頭部超聲波測距設備,提高疲勞檢測準確率。