你们都嫌公司之前使用的刷卡门禁太麻烦,正好借这个机会开发一我的脸识别的门禁系统,采用的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