你們都嫌公司之前使用的刷卡門禁太麻煩,正好借這個機會開發一我的臉識別的門禁系統,採用的SDK是虹軟公司開發的,接口調用比較簡單。多線程
1、虹軟SDK接口性能性能
在配置爲i5-7400 、16G內存的PC上測試性能以下:測試
1.FT 單次3ms左右優化
2.FD 單次10ms左右線程
3.FR 單次170ms左右 2、業務層須要解決的問題code
1.FT和FR單次性能相差較大,速度不匹配視頻
2.FT支持多人臉,單次檢測人臉較多,而FR只支持單人臉blog
3.視頻幀單次處理可能會超過幀間隔時間接口
3、優化方案內存
人臉識別過程包括三個步驟,檢測人臉、人臉特徵提取、特徵匹配,以人臉識別的門禁系統爲例,主要步驟獲取視頻幀、檢
測視頻幀人臉、提取特徵、特徵匹配,門禁系統對於實時性要求比較高。
流程圖大概以下:
下面說下開發過程當中多線程方面的優化點。
攝像頭視頻的幀率正常在25~30幀左右,而且通常的視頻幀的分辨率爲1280x720,固然有的攝像頭能夠達到更大的分辨率,
可是通過測試多款攝像頭,發現分辨率設置過大會致使獲取視頻幀的過程當中卡頓。而且分辨率適中,會提高後面的FT的速度。獲取視頻幀的操做是在主線程進行的。
lock_guard<std::mutex> locker(g_CameraMutex); if (m_camera->getFrame(m_curFrame)) { return; } ftProcessor->faceDetect(m_curFrame, m_resizeImage);
採用了獲取視頻幀和FT串行的方式,須要保證從獲取視頻幀一直處處理完成,必須在幀間隔時間內(幀率爲25時,在40ms左右),不然可能會出現卡幀的狀況。經測試,獲取視頻幀和FT串行的單次時間在幀間隔時間內,所以採用串行的方式。 FT支持多人臉檢測,我將檢測最大人臉數設置爲5,因此在極限狀態下,人數較多的話,待識別的人數可能一直維持在5人,這就須要提升FR的有效識別率。
FR使用了一個自定義threadsafe_queue簡化多線程數據同步操做,在FT中將須要進行FR的人臉框以及對應的視頻幀和人臉框的trackid push_back到threadsafe_queue中,FR線程從中取人臉框信息和視頻幀,作提取特徵和特徵匹配處理。
我從如下幾個點優化人臉識別效率:
a.增長FR線程數量。 對於我來講,開線程池的方式可行性並不過高。首先機器的內核數限制的線程數,動態增長線程數聽起來不錯,可是門禁使用的一體機畢竟跟開發機器不同,性能限制太多,而且線程切換和數據同步都會更加複雜。可是爲了提升FR的識別速度,我最終開了兩個FR線程,經測試,在i5-7400T 8G內存 配置的機器上,CPU大概處於40%左右。
b.提升FR識別效率 優化FR識別效率要求FR作到每次識別都是有效的,也就是說FR不作垃圾幀的處理。
1)每次在獲取到人臉後,判斷是否與前一幀檢測到的人臉結果屬於同一我的(經過trackid斷定,這一部分留到後面的文章說明,敬請期待)。若是某我的臉框首次出現,或者若是某個trackid對應的人臉框仍未識別成功,都須要作FR操做。
case FTSucceed: case FRFailed: { newFaceInfo.faceStatus = FRWaiting; FRParam frParam = { 0 }; frParam.curImageInfo = m_curImageInfo; frParam.faceInfo.faceOrient = newFaceInfo.faceOrient; frParam.faceInfo.faceRect = { newFaceInfo.faceRect.wleft, newFaceInfo.faceRect.wtop, newFaceInfo.faceRect.wright, newFaceInfo.faceRect.wbottom }; frParam.trackid = newFaceInfo.trackid; m_frParamsQueue.push(frParam); }
當某個trackid對應的人臉已經在等待或者在作FR的時候,在後面檢測到的該trackid對應人臉將再也不作FR,一直到FR檢測結果出來之後,再作處理。
case FRProcessing: case FRWaiting: { //default color } break;
2)識別成功後,一樣將該trackid所對應的人臉都設置爲識別到的人,這樣下次就不須要再次作FR,不會浪費FR的時間片。 3)每次在從threadsafe_queue獲取的待處理的人臉框、trackid和視頻幀時,都檢測該trackid是否已消失,若是消失,就不作FR,由於拿到的結果毫無用處,直接丟棄。
std::lock_guard<std::mutex> locker(m_faceInfoListMutex); //找到對應的trackid 對應的人臉,設置爲FRProcessing auto iter = find_if(m_prevFacesRes.begin(), m_prevFacesRes.end(), [=](const FaceInfo& lhs) { return lhs.trackid == frParam.trackid; }); if (iter != m_prevFacesRes.end()) { iter->faceStatus = FRProcessing; } else { //找不到 就不用作FR了 continue; }
好了,此次就說到這,你們有什麼問題的話,能夠留言,謝謝。 參考連接: 1.trackid 介紹:https://www.jianshu.com/p/4ae90634a79e