最近领导让做一个人脸识别项目,在网上找了一个虹软的人脸识别demo,留意了一下,然后再将人脸识别搞完之后,重新下了一个人脸识别服务端完整demo,配置好app_id和sdk_key之后,(没有虹软app_id和不会配置的同学请点击),项目正常运行,demo原有的功能如下:
提示:今天我主要的目的是说一下开启本地摄像头进行人脸识别,有兴趣的同学自己试一下上面的功能。
(注意视频流识别可能需要在手机或者电脑上旋转保存再播放、或者在代码读到某一帧图片的时候,进行旋转,才能识别出来,因为目前只能识别正脸)
项目源码在文章最下方。
保存图片比较简单,在images文件夹下保存自己的照片,再在FaceController的 如下代码下加入自己的数据就可以了,比如我是小明,我就加一个我的图片,在重启一下项目,照片就加载到内存缓存中了。
fileMap.put(“xiaoming”, “小明”);
/**
* 打开摄像头进行人脸识别/保存人脸图片/保存人脸视频
* @param response
* @throws Exception
*/
@GetMapping(value = "/streamCamera")
public void streamCamera(HttpServletResponse response) throws Exception {
videoPlayerService.servletStreamPlayer(response);
}
public void servletStreamPlayer(HttpServletResponse response) throws Exception {
//启动人脸处理引擎
FacePreview faceProcessEngine = new FacePreview(appId, sdkKey);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);//新建opencv抓取器,一般的电脑和移动端设备中摄像头默认序号是0,不排除其他情况
grabber.setImageWidth(600);
grabber.setImageHeight(400);
grabber.start();//开始获取摄像头数据
int i = 1;
for (; ; ) {
Frame frame = grabber.grab();
if (frame == null) {
continue;
}
IplImage iplImage = converter.convert(frame);//抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
if (iplImage != null) {
// 一帧图片插入人脸图框
faceProcessEngine.preview(iplImage);
frame = converter.convert(iplImage);
}
// ======================================保存为图片(开始)============================================
File imgFile = new File("想要保存的路径\\picture\\" + i + ".jpg");
//判断保存的文件的文件夹是否存在,不存在创建。
if (!imgFile.getParentFile().exists()) {
System.out.println("保存文件的文件夹不存在,创建。");
imgFile.getParentFile().mkdirs();
}
RenderedImage renderedImage = VideoProcessing.frameToBufferedImage(frame);
ImageIO.write(renderedImage, "jpg", imgFile);
// ======================================保存为图片(结束)============================================
// 添加i++就是按照休眠时间保存图片,注释掉就只保存最后一帧图片,转换一下思路,假设休眠200ms, 那一秒保存五次图片,那么打开这张图片,过滤掉加载的白屏,就是5帧的视频
// i++;
if (outputStream.size() > 0) {
byte[] bytes = outputStream.toByteArray();
response.getOutputStream().write(bytes);
outputStream.reset();
}
Thread.sleep(200);
System.out.println("休眠200ms!!!");
}
}
public void servletStreamPlayer(HttpServletResponse response) throws Exception {
//启动人脸处理引擎
FacePreview faceProcessEngine = new FacePreview(appId, sdkKey);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);//新建opencv抓取器,一般的电脑和移动端设备中摄像头默认序号是0,不排除其他情况
grabber.setImageWidth(600);
grabber.setImageHeight(400);
grabber.start();//开始获取摄像头数据
// ======================================保存为视频(开始)============================================
// 流媒体输出地址,分辨率(长,高),是否录制音频(0:不录制/1:录制) ?overrun_nonfatal=1&fifo_size=50000000
//这里udp地址增加参数扩大udp缓存
FFmpegFrameRecorder recorder = new FFmpegFrameRecorder("想要保存的路径\\picture\\" + new SimpleDateFormat("yyyyMMddHHmmss").format(new Date()) + ".flv", grabber.getImageWidth(), grabber.getImageHeight(), 0);
// 直播流格式
// 转码
recorder.setFormat("flv");
recorder.setInterleaved(false);
recorder.setVideoOption("tune", "zerolatency");
recorder.setVideoOption("preset", "ultrafast");
recorder.setVideoOption("crf", "26");
recorder.setVideoOption("threads", "1");
double frameRate = grabber.getFrameRate();
recorder.setFrameRate(frameRate);// 设置帧率
recorder.setGopSize(25);// 设置gop,关键帧
int videoBitrate = grabber.getVideoBitrate();
recorder.setVideoBitrate(videoBitrate);// 设置码率500kb/s,画质
recorder.setVideoCodec(avcodec.AV_CODEC_ID_H264);
recorder.setPixelFormat(avutil.AV_PIX_FMT_YUV420P);
recorder.setAudioCodec(avcodec.AV_CODEC_ID_AAC);
recorder.setTrellis(1);
recorder.setMaxDelay(0);// 设置延迟
recorder.setAudioChannels(grabber.getAudioChannels());
recorder.start();
// ======================================保存为视频(开始)============================================
long startTime = 0;
long videoTS = 0;
for (; ; ) {
Frame frame = grabber.grab();
if (frame == null) {
continue;
}
IplImage iplImage = converter.convert(frame);//抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
if (iplImage != null) {
// 一帧图片插入人脸图框
faceProcessEngine.preview(iplImage);
frame = converter.convert(iplImage);
}
if (startTime == 0) {
startTime = System.currentTimeMillis();
}
videoTS = 1000 * (System.currentTimeMillis() - startTime);
// 判断时间偏移
if (videoTS > recorder.getTimestamp()) {
recorder.setTimestamp((videoTS));
}
recorder.record(frame);
if (outputStream.size() > 0) {
byte[] bytes = outputStream.toByteArray();
response.getOutputStream().write(bytes);
outputStream.reset();
}
Thread.sleep(100);
System.out.println("休眠100ms!!!");
}
}
首先介绍一下四个参数的作用
DO_NOTHING_ON_CLOSE,(在你点击关闭按钮的时候,不会被关闭,)不执行任何操作。
HIDE_ON_CLOSE,(当你点击关闭按钮的时候,不会释放内存,只是隐藏该界面,没有真正的关闭,还占有资源)只隐藏界面,setVisible(false)。
DISPOSE_ON_CLOSE,点击关闭按钮的时候,隐藏并释放窗体,dispose(),当最后一个窗口被释放后,则程序也随之运行结束。
EXIT_ON_CLOSE,直接关闭应用程序,System.exit(0)。一个main函数对应一整个程序。**
CanvasFrame canvas = new CanvasFrame(“摄像头预览”);//新建一个预览窗口
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
public void servletStreamPlayer(HttpServletResponse response) throws Exception {
//启动人脸处理引擎
FacePreview faceProcessEngine = new FacePreview(appId, sdkKey);
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
OpenCVFrameConverter.ToIplImage converter = new OpenCVFrameConverter.ToIplImage();
OpenCVFrameGrabber grabber = new OpenCVFrameGrabber(0);//新建opencv抓取器,一般的电脑和移动端设备中摄像头默认序号是0,不排除其他情况
grabber.setImageWidth(600);
grabber.setImageHeight(400);
grabber.start();//开始获取摄像头数据
CanvasFrame canvas = new CanvasFrame("摄像头预览");//新建一个预览窗口
canvas.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
canvas.setVisible(true);
canvas.setFocusable(true);
// 窗口置顶
if (canvas.isAlwaysOnTopSupported()) {
canvas.setAlwaysOnTop(true);
}
for (; ; ) {
Frame frame = grabber.grab();
if (frame == null) {
continue;
}
IplImage iplImage = converter.convert(frame);//抓取一帧视频并将其转换为图像,至于用这个图像用来做什么?加水印,人脸识别等等自行添加
if (iplImage != null) {
// 一帧图片插入人脸图框
faceProcessEngine.preview(iplImage);
frame = converter.convert(iplImage);
}
// 获取摄像头图像并放到窗口上显示,frame是一帧图像
canvas.showImage(frame);
if (outputStream.size() > 0) {
byte[] bytes = outputStream.toByteArray();
response.getOutputStream().write(bytes);
outputStream.reset();
}
Thread.sleep(100);
System.out.println("休眠100ms!!!");
}
}
其中主要是这一步:把在2.1得到的每一帧图片按照设定的休眠时间放在打开的窗口上展示,展示出来的就是一个视频
// 获取摄像头图像并放到窗口上显示,frame是一帧图像
canvas.showImage(frame);
经历了CV的捶打,结果终于出来了,人脸识别成功之后下节做人脸识别登录。
本项目git地址:https://gitee.com/table-tennis-king/faceForCamera.git