本文基于虹软免费人脸识别SDK,从IPC提供的RTSP视频流抓帧进行人脸识别。主要技术方案是通过JavaCV定时抓取视频帧保存为图像,然后针对图像通过虹软SDK提取特征,同特征库里面的人脸进行比较,超过设定的阈值就认为识别到。
人脸识别技术是随着技术发展而产生的生物识别技术,目前已广泛应用于安防领域,主要用于身份验证和身份识别。视频监控是安防系统常见的一种表现形式,需要部署各种摄像头,包括网络摄像头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包。
#人脸识别相关参数
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
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
;
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;
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;
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
);
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());
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();
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
)
grabber.stop();
catch
(
FrameGrabber
.
Exception
ex)
logger
.error("grabber stop exception: " + ex.getMessage());
finally
grabber =
null
;
Thread
.
sleep
(100);
catch
(
InterruptedException
e)
logger
.error(e.getMessage());
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());
logger
.error("Init Face error");
RtspFrameGrabberThread
thread =
new
RtspFrameGrabberThread
(
ConfigMgr
.
getInstance
().getRtspUrl());
thread.start();
7
结论
本文所介绍的方法,只是提供可行性验证,说明可以通过抓取RTSP视频帧调用虹软SDK进行人脸识别。可以作为商业项目的参考。在实际项目中,可以通过对相关参数的调整达到更好的性能。
8
源码下载
源码包含了完整的第三方库,所以比较大,上传到百度网盘提供下载。