基於RTSP視頻流的Java后台服務端虹軟人臉識別


1 概述

       人臉識別技術是隨着技術發展而產生的生物識別技術,目前已廣泛應用於安防領域,主要用於身份驗證和身份識別。視頻監控是安防系統常見的一種表現形式,需要部署各種攝像頭,包括網絡攝像頭IPC,可以通過流媒體如RTSP視頻流的方式供第三方系統集成。

       虹軟是計算機視覺行業領先的算法服務提供商及解決方案供應商,提供免費、離線的人臉識別SDK,主要包含人臉檢測、性別檢測、年齡檢測、人臉識別、圖像質量檢測、RGB活體檢測、IR活體檢測等能力。支持主流Windows、Linux、Android、iOS等平台及Java、C++等開發語言。

       本文基於虹軟免費人臉識別SDK,從IPC提供的RTSP視頻流抓幀進行人臉識別。主要技術方案是通過JavaCV定時抓取視頻幀保存為圖像,然后針對圖像通過虹軟SDK提取特征,同特征庫里面的人臉進行比較,超過設定的閾值就認為識別到。

2 項目環境

介紹項目中主要使用到的開發庫及開發工具。

1) 虹軟人臉識別SDK。提供人臉識別相關開發接口。本文使用Windows X64 Java版本,ArcSoft_ArcFace_Java_Windows_x64_V3.0。

下載地址:虹軟官網開發者中心(https://ai.arcsoft.com.cn)。

2) JavaCV。是一款基於JavaCPP調用方式(JNI的一層封裝),提供了在計算機視覺領域的封裝庫,封裝了包含FFmpeg、OpenCV、tensorflow、caffe、tesseract、libdc1394、OpenKinect、videoInput和ARToolKitPlus等在內的計算機視覺領域的常用庫和實用程序類。本文使用javacv-platform-1.5.1-bin版本。

下載地址:github(https://github.com/bytedeco/javacv)。也可以通過Maven的方式下載必要的jar包。

3) Eclipse。一個開放源代碼的、基於Java的可擴展開發平台。用於Java項目的工程化組織。本文使用Oxygen Release (4.7.0)。

下載地址:Eclipse官網(https://www.eclipse.org/downloads/

4) JDK。提供Java開發環境。本文使用jdk-8u181-windows-x64版本。

下載地址:Oracle官網(https://www.oracle.com/java/

3 整體流程

整體流程包括各種初始化,啟動RTSP視頻流監測線程,啟動人臉識別任務,如下圖所示:

 

 

 

 4 工程概況

創建一個常規的Java項目,引入必要的第三方jar包。

1)    引入虹軟人臉識別jar包。

arcsoft-sdk-face-3.0.0.0.jar

2) 引入JavaCV必要的jar包。

artoolkitplus.jar

ffmpeg.jar

ffmpeg-windows-x86_64.jar

flandmark.jar

flycapture.jar

javacpp.jar

javacv.jar

leptonica.jar

libdc1394.jar

libfreenect.jar

libfreenect2.jar

librealsense.jar

openblas.jar

opencv.jar

tesseract.jar

videoinput.jar

       3) 引入log4j相關jar包。

slf4j-api-1.7.25.jar

slf4j-log4j12-1.7.25.jar

log4j-1.2.17.jar

Java工程結構如下圖所示:

  

 

  運行的時候,需要將虹軟SDK核心DLL拷到jar包所在目錄。

5 效果展示

工程以常規java項目運行,通過日志觀察識別效果。打印識比對分值和人臉庫的文件名。如下圖所示:

 

6 核心代碼說明

6.1 配置文件

#人臉識別相關參數

config.FaceAppId = 3D9hF3f4uNxgDGRkRr9PD6P7CbuSC1GrPe5dBnxxxxx

config.FaceSdkKey = 2aSheKNE4aMokrkRmn5qJ7kvPirhZM7YpDLx

config.FaceThreshold = 0.75

#人臉庫圖片所在路徑

config.FaceLibPath = d:/facelib/

#rtsp視頻流地址

config.RtspUrl = rtsp://192.168.0.100:554/live/camera

#執行任務的線程數量

config.ThreadNum = 16

 AppId和SdkKey根據虹軟開發者中心實際應用情況配置。配置項通過ConfigMgr類加載。

 

  6.2 虹軟人臉識別接口封裝類

       主要對核心方法進行封裝,包括初始化、特征提取、特征比對,是對虹軟SDK提供的接口進行封裝。

 

       初始化引擎代碼:

public static boolean init(String _sAppID, String _sSdkKey)

{

       m_oFaceEngine = new FaceEngine();

       // 引擎激活

       int iFaceActiveCode = m_oFaceEngine.activeOnline(_sAppID, _sSdkKey);

       if (iFaceActiveCode != ErrorInfo.MOK.getValue() &&

                     iFaceActiveCode != ErrorInfo.MERR_ASF_ALREADY_ACTIVATED.getValue())

       {

           logger.error("人臉識別引擎在線激活失敗!({})", iFaceActiveCode);

           return false;

    }

       

       // 引擎配置

       EngineConfiguration oEngineConfiguration = new EngineConfiguration();

       oEngineConfiguration.setDetectMode(DetectMode.ASF_DETECT_MODE_IMAGE);

       oEngineConfiguration.setDetectFaceOrientPriority(DetectOrient.ASF_OP_0_ONLY);

       // 功能配置

       FunctionConfiguration oFunctionConfiguration = new FunctionConfiguration();

       oFunctionConfiguration.setSupportFaceDetect(true);

       oFunctionConfiguration.setSupportFaceRecognition(true);

       oFunctionConfiguration.setSupportAge(false);

       oFunctionConfiguration.setSupportGender(false);

       oEngineConfiguration.setFunctionConfiguration(oFunctionConfiguration);

       // 初始化引擎

       int iFaceInitCode = m_oFaceEngine.init(oEngineConfiguration);

       if (iFaceInitCode != ErrorInfo.MOK.getValue())

       {

              logger.error("人臉識別引擎初始化失敗!({})", iFaceInitCode);

              return false;

    }

             

    return true;

}

       提取特征代碼:

public static FaceFeature getFaceFeature(byte[] _abyImageData)

{

       try

       {

           ImageInfo oImageInfo = ImageFactory.getRGBData(_abyImageData);

           List<FaceInfo> lstFaceInfo = new ArrayList<FaceInfo>();

           int iCode = m_oFaceEngine.detectFaces(oImageInfo.getImageData(), oImageInfo.getWidth(), oImageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, lstFaceInfo);

           if (iCode != ErrorInfo.MOK.getValue())

           {

               logger.error("檢測人臉失敗({})", iCode);

               return null;

           }

              

           if (lstFaceInfo.isEmpty())

           {

               logger.error("檢測人臉為空({})", iCode);

               return null;

           }

      

           FaceFeature oFaceFeature = new FaceFeature();

           iCode = m_oFaceEngine.extractFaceFeature(oImageInfo.getImageData(), oImageInfo.getWidth(), oImageInfo.getHeight(), ImageFormat.CP_PAF_BGR24, lstFaceInfo.get(0), oFaceFeature);

           if (iCode != ErrorInfo.MOK.getValue())

           {

                  logger.error("提取人臉特征失敗({})", iCode);

                  return null;

           }

           return oFaceFeature;

       }

       catch (Exception e)

       {

              logger.error(e.getMessage());

              return null;

       }

}

       特征比對代碼:

public static float compare(FaceFeature _oFaceFeature1, FaceFeature _oFaceFeature2)

{

       float fSimilarity = 0.0f;

             

       try

       {

           FaceSimilar oFaceSimilar = new FaceSimilar();

           int iCode = m_oFaceEngine.compareFaceFeature(_oFaceFeature1, _oFaceFeature2, oFaceSimilar);

           if (iCode != ErrorInfo.MOK.getValue())

           {

                  logger.error("人臉比對失敗({})", iCode);

                  return fSimilarity;

           }

          

           fSimilarity = oFaceSimilar.getScore();

       }

       catch (Exception e)

       {

              logger.error(e.getMessage());

       }

      

       return fSimilarity;

}

  6.3 任務調度封裝類

       主要是通過JDK提供的線程池ScheduledExecutorService對程序中任務執行進行調度。

 

       主要代碼如下:

private ScheduledExecutorService svc;

private boolean init;

   

private TaskMgr()

{

svc = null;

    init = false;

}

/**

 * 初始化

*/

public void init(int _iThreadNum)

{

svc = Executors.newScheduledThreadPool(_iThreadNum);

    init = true;

}

   

 /**

* 銷毀

 */

public void destroy()

{

if (init)

{

           svc.shutdown();

    }

}

 

/**

* 增加一個任務

* @param _task 任務對象,實現Runnable接口

*/

public void pushTask(Runnable _task)

{

svc.schedule(_task, 0, TimeUnit.MILLISECONDS);

}

  6.4 人臉庫管理封裝類

       加載指定目錄下的圖片,提取特征保存到內存中形成人臉庫,供1:N識別時進行遍歷。

 

       初始化代碼:

public void init(String _faceLibPath)

{

File fileDir = new File(_faceLibPath);

if (fileDir.exists() && fileDir.isDirectory())

{

      String[] children = fileDir.list();

      for (int i = 0; i < children.length; i++)

{

File fileImage = new File(fileDir, children[i]);

FaceFeature faceFeature = ArcfaceApi.getFaceFeature(fileImage);

      if (faceFeature != null)

{

myFaceFeatureList.add(new MyFaceFeature(children[i], faceFeature));

}

}

  }

  

logger.info("face lib size:{}", myFaceFeatureList.size());

}

  6.5 RTSP視頻流抓幀線程類

       該線程啟動時一直運行,通過JavaCV定時抓幀,得到的圖片啟動一個任務提交到線程池,調用人臉庫管理封裝類進行識別。

 

  創建幀抓取器

private void createGrabber()

{

       try

       {

              grabber = FFmpegFrameGrabber.createDefault(rtspUrl);

              grabber.setFrameRate(frameRate);

              grabber.setVideoBitrate(bitRate);

              grabber.setImageWidth(frameWidth);

              grabber.setImageHeight(frameHeight);

              grabber.start();

       }

       catch  (Exception e)

       {

              logger.error(e.getMessage());

       }

}

定時抓幀保存為圖片格式

private void startGrabber()

{

       Java2DFrameConverter java2DFrameConverter = new Java2DFrameConverter();

 

       while (true)

       {

              if (grabber == null)

              {

                     logger.info("連接rtsp:" + rtspUrl + ",開始創建grabber");

                     createGrabber();

              }

 

              try

              {

                     Frame frame = grabber.grabImage();

                     if (frame != null)

                     {

                            BufferedImage bi = java2DFrameConverter.getBufferedImage(frame);

                            byte[] bytes = imageToBytes(bi, "jpg");

                            if (bytes != null && bytes.length > 0)

                            {

                                   // 人臉檢測

                                   TaskMgr.getInstance().pushTask(new FrameHandleTask(bytes));

                            }

                     }

              }

              catch (Exception e)

              {

                     logger.error(e.getMessage());

                           

                     if (grabber != null)

                     {

                            try

                            {

                                   grabber.stop();

                            }

                            catch (FrameGrabber.Exception ex)

                            {

                                   logger.error("grabber stop exception: " + ex.getMessage());

                            }

                            finally

                            {

                                   grabber = null;

                            }

                     }

              }

                    

              try

              {

                     Thread.sleep(100);

              }

              catch (InterruptedException e)

              {

                     logger.error(e.getMessage());

              }

       }

}

6.6 工程啟動

       在Main方法中進行初始化,並啟動線程。

public class ArcfaceRtspDemo

{

private final static Logger logger = LoggerFactory.getLogger(ArcfaceRtspDemo.class);

      

       public static void main(String[] args)

       {

       // 加載配置文件

       ConfigMgr.getInstance().init();

       // 任務初始化

       TaskMgr.getInstance().init(ConfigMgr.getInstance().getThreadNum());

       // 人臉初始化

       boolean bRet = ArcfaceApi.init(ConfigMgr.getInstance().getFaceAppId(), ConfigMgr.getInstance().getFaceSdkKey());

       if (bRet)

       {

         logger.info("Init Face success");

        MyFaceMgr.getInstance().init(ConfigMgr.getInstance().getFaceLibPath());

       }

       else

       {

              logger.error("Init Face error");

       }

             

       RtspFrameGrabberThread thread = new RtspFrameGrabberThread(ConfigMgr.getInstance().getRtspUrl());

       thread.start();

}

 

結論

       本文所介紹的方法,只是提供可行性驗證,說明可以通過抓取RTSP視頻幀調用虹軟SDK進行人臉識別。可以作為商業項目的參考。在實際項目中,可以通過對相關參數的調整達到更好的性能。

源碼下載

       源碼包含了完整的第三方庫,所以比較大,上傳到百度網盤提供下載。

鏈接:https://pan.baidu.com/s/1f3crf1x_2jq8uMm9DqVcZg

提取碼:78jd


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM