引言

远程在家办公的第N天,快要闲出屁了,今天突然有个小学弟加我VX说要咨询我点技术问题(终于可以装X了)。 看了他的需求描述,大概是要做一个Java web版本的人脸识别功能,然后存储人物的特征,再扫脸比对。可是我不会啊。。。

不过,作为一个宠粉的暖男,别说有困难就是没困难制造困难也要上,既然人家这么真诚的咨询,说明我还是有被需要的价值,不会那就帮着查查资料吧!没想到还有意外的收获~

看完他的境遇,忽然想起自己当年做毕设时那无助的样子,是何等的相似。每每看到有这样的咨询,能帮的我都尽自己最大努力帮,毕竟都是这么走过来的。

人脸识别SDK

人脸识别技术是很复杂的,自己用Java手撕一个识别算法有点不切实际,毕竟实力不允许我这么嚣张,还是借助三方的SDK吧!

找了一圈发现一个免费的人脸识别SDK: ArcSoft:,地址:https://ai.arcsoft.com.cn。

官网首页 -> 右上角开发者中心 -> 选择“人脸识别” -> 添加SDK,会生成APPID、SDK KEY后续会用到,根据需要选择不同的环境(本文基于windows环境),然后下载SDK是一个压缩包。

Java项目搭建

终于在我的苦苦搜寻之下终于,找到一个ArcSoft的Java版本Demo,开源真是一件美好的事情,话不多说开干!

1、下载demo项目

github地址:https://github.com/xinzhfiu/ArcSoftFaceDemo,本地搭建数据库,创建表:user_face_info。这个表主要用来存人像特征,其中主要的字段 face_feature 用二进制类型 blob 存放人脸特征。

SET NAMES utf8mb4;

SET FOREIGN_KEY_CHECKS = 0;

-- ----------------------------

-- Table structure for user_face_info

-- ----------------------------

DROP TABLE IF EXISTS `user_face_info`;

CREATE TABLE `user_face_info` (

`id` int(11) NOT NULL AUTO_INCREMENT COMMENT '主键',

`group_id` int(11) DEFAULT NULL COMMENT '分组id',

`face_id` varchar(31) DEFAULT NULL COMMENT '人脸唯一Id',

`name` varchar(63) DEFAULT NULL COMMENT '名字',

`age` int(3) DEFAULT NULL COMMENT '年纪',

`email` varchar(255) DEFAULT NULL COMMENT '邮箱地址',

`gender` smallint(1) DEFAULT NULL COMMENT '性别,1=男,2=女',

`phone_number` varchar(11) DEFAULT NULL COMMENT '电话号码',

`face_feature` blob COMMENT '人脸特征',

`create_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP COMMENT '创建时间',

`update_time` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP COMMENT '更新时间',

`fpath` varchar(255) COMMENT '照片路径',

PRIMARY KEY (`id`) USING BTREE,

KEY `GROUP_ID` (`group_id`) USING BTREE

) ENGINE=InnoDB AUTO_INCREMENT=1 DEFAULT CHARSET=utf8mb4 ROW_FORMAT=DYNAMIC;

SET FOREIGN_KEY_CHECKS = 1;

2、修改application.properties文件

整个项目还是比较完整的,只需改一些配置即可启动,但有几点注意的地方,后边会重点说明。

config.arcface-sdk.sdk-lib-path: 存放SDK压缩包中的三个.dll文件的路径

config.arcface-sdk.app-id : 开发者中心的APPID

config.arcface-sdk.sdk-key :开发者中心的SDK Key

config.arcface-sdk.sdk-lib-path=d:/arcsoft_lib

config.arcface-sdk.app-id=8XMHMu71Dmb5UtAEBpPTB1E9ZPNTw2nrvQ5bXxBobUA8

config.arcface-sdk.sdk-key=BA8TLA9vVwK7G6btJh2A2FCa8ZrC6VWZLNbBBFctCz5R

# druid 本地的数据库地址

spring.datasource.druid.url=jdbc:mysql://127.0.0.1:3306/xin-master?useUnicode=true&characterEncoding=utf-8&useSSL=false&serverTimezone=UTC

spring.datasource.druid.username=junkang

spring.datasource.druid.password=junkang

3、根目录创建lib文件夹

在项目根目录创建文件夹 lib,将下载的SDK压缩包中的arcsoft-sdk-face-2.2.0.1.jar放入项目根目录

4、引入arcsoft依赖包

com.arcsoft.face

arcsoft-sdk-face

2.2.0.1

system

${basedir}/lib/arcsoft-sdk-face-2.2.0.1.jar

pom.xml文件要配置includeSystemScope属性,否则可能会导致arcsoft-sdk-face-2.2.0.1.jar引用不到

org.springframework.boot

spring-boot-maven-plugin

true

true

5、启动项目

到此为止配置完成,run Application文件启动

测试一下:http://127.0.0.1:8089/demo,如下页面即启动成功

操作

1、录入人脸图像

页面输入名称,点击摄像头注册调起本地摄像头,提交后将当前图像传入后台,识别提取当前人脸体征,保存至数据库。

2、人脸对比

录入完人脸图像后测试一下能否识别成功,提交当前的图像,发现识别成功相似度92%。但是作为程序员对什么事情都要持怀疑的态度,这结果不是老铁在页面写死的吧?

为了进一步验证,这回把脸挡住再试一下,发现提示“人脸不匹配”,证明真的有进行比对。

源码分析

简单看了一下项目源码,分析一下实现的过程:

页面和JS一看就是后端程序员写的,不要问我问为什么?懂的自然懂,哈哈哈 ~ ,

1、JS调起本地摄像头拍照,上传图片文件字符串

function getMedia() {

$("#mainDiv").empty();

let videoComp = " ";

$("#mainDiv").append(videoComp);

let constraints = {

video: {width: 500, height: 500},

audio: true

};

//获得video摄像头区域

let video = document.getElementById("video");

//这里介绍新的方法,返回一个 Promise对象

// 这个Promise对象返回成功后的回调函数带一个 MediaStream 对象作为其参数

// then()是Promise对象里的方法

// then()方法是异步执行,当then()前的方法执行完后再执行then()内部的程序

// 避免数据没有获取到

let promise = navigator.mediaDevices.getUserMedia(constraints);

promise.then(function (MediaStream) {

video.srcObject = MediaStream;

video.play();

});

// var t1 = window.setTimeout(function() {

// takePhoto();

// },2000)

}

//拍照事件

function takePhoto() {

let mainComp = $("#mainDiv");

if(mainComp.has('video').length)

{

let userNameInput = $("#userName").val();

if(userNameInput == "")

{

alert("姓名不能为空!");

return false;

}

//获得Canvas对象

let video = document.getElementById("video");

let canvas = document.getElementById("canvas");

let ctx = canvas.getContext('2d');

ctx.drawImage(video, 0, 0, 500, 500);

var formData = new FormData();

var base64File = canvas.toDataURL();

var userName = $("#userName").val();

formData.append("file", base64File);

formData.append("name", userName);

formData.append("groupId", "101");

$.ajax({

type: "post",

url: "/faceAdd",

data: formData,

contentType: false,

processData: false,

async: false,

success: function (text) {

var res = JSON.stringify(text)

if (text.code == 0) {

alert("注册成功")

} else {

alert(text.message)

}

},

error: function (error) {

alert(JSON.stringify(error))

}

});

}

else{

var formData = new FormData();

let userName = $("#userName").val();

formData.append("groupId", "101");

var file = $("#file0")[0].files[0];

var reader = new FileReader();

reader.readAsDataURL(file);

reader.onload = function () {

var base64 = reader.result;

formData.append("file", base64);

formData.append("name",userName);

$.ajax({

type: "post",

url: "/faceAdd",

data: formData,

contentType: false,

processData: false,

async: false,

success: function (text) {

var res = JSON.stringify(text)

if (text.code == 0) {

alert("注册成功")

} else {

alert(text.message)

}

},

error: function (error) {

alert(JSON.stringify(error))

}

});

location.reload();

}

}

}

2、后台解析图片,提取人像特征

后台解析前端传过来的图片,提取人像特征存入数据库,人像特征的提取主要是靠FaceEngine引擎,顺着源码一路看下去,自己才疏学浅实在是没懂具体是个什么样的算法。

/*

人脸添加

*/

@RequestMapping(value = "/faceAdd", method = RequestMethod.POST)

@ResponseBody

public Result faceAdd(@RequestParam("file") String file, @RequestParam("groupId") Integer groupId, @RequestParam("name") String name) {

try {

//解析图片

byte[] decode = Base64.decode(base64Process(file));

ImageInfo imageInfo = ImageFactory.getRGBData(decode);

//人脸特征获取

byte[] bytes = faceEngineService.extractFaceFeature(imageInfo);

if (bytes == null) {

return Results.newFailedResult(ErrorCodeEnum.NO_FACE_DETECTED);

}

UserFaceInfo userFaceInfo = new UserFaceInfo();

userFaceInfo.setName(name);

userFaceInfo.setGroupId(groupId);

userFaceInfo.setFaceFeature(bytes);

userFaceInfo.setFaceId(RandomUtil.randomString(10));

//人脸特征插入到数据库

userFaceInfoService.insertSelective(userFaceInfo);

logger.info("faceAdd:" + name);

return Results.newSuccessResult("");

} catch (Exception e) {

logger.error("", e);

}

return Results.newFailedResult(ErrorCodeEnum.UNKNOWN);

}

3、人像特征对比

人脸识别:将前端传入的图像经过人像特征提取后,和库中已存在的人像信息对比分析

/*

人脸识别

*/

@RequestMapping(value = "/faceSearch", method = RequestMethod.POST)

@ResponseBody

public Result faceSearch(String file, Integer groupId) throws Exception {

byte[] decode = Base64.decode(base64Process(file));

BufferedImage bufImage = ImageIO.read(new ByteArrayInputStream(decode));

ImageInfo imageInfo = ImageFactory.bufferedImage2ImageInfo(bufImage);

//人脸特征获取

byte[] bytes = faceEngineService.extractFaceFeature(imageInfo);

if (bytes == null) {

return Results.newFailedResult(ErrorCodeEnum.NO_FACE_DETECTED);

}

//人脸比对,获取比对结果

List userFaceInfoList = faceEngineService.compareFaceFeature(bytes, groupId);

if (CollectionUtil.isNotEmpty(userFaceInfoList)) {

FaceUserInfo faceUserInfo = userFaceInfoList.get(0);

FaceSearchResDto faceSearchResDto = new FaceSearchResDto();

BeanUtil.copyProperties(faceUserInfo, faceSearchResDto);

List processInfoList = faceEngineService.process(imageInfo);

if (CollectionUtil.isNotEmpty(processInfoList)) {

//人脸检测

List faceInfoList = faceEngineService.detectFaces(imageInfo);

int left = faceInfoList.get(0).getRect().getLeft();

int top = faceInfoList.get(0).getRect().getTop();

int width = faceInfoList.get(0).getRect().getRight() - left;

int height = faceInfoList.get(0).getRect().getBottom() - top;

Graphics2D graphics2D = bufImage.createGraphics();

graphics2D.setColor(Color.RED);//红色

BasicStroke stroke = new BasicStroke(5f);

graphics2D.setStroke(stroke);

graphics2D.drawRect(left, top, width, height);

ByteArrayOutputStream outputStream = new ByteArrayOutputStream();

ImageIO.write(bufImage, "jpg", outputStream);

byte[] bytes1 = outputStream.toByteArray();

faceSearchResDto.setImage("data:image/jpeg;base64," + Base64Utils.encodeToString(bytes1));

faceSearchResDto.setAge(processInfoList.get(0).getAge());

faceSearchResDto.setGender(processInfoList.get(0).getGender().equals(1) ? "女" : "男");

}

return Results.newSuccessResult(faceSearchResDto);

}

return Results.newFailedResult(ErrorCodeEnum.FACE_DOES_NOT_MATCH);

}

整个人脸识别功能的大致流程图如下:

总结

整个项目的设计思路比较清晰,难点在于人脸识别引擎 和 前端JS部分代码,其他的功能比较平常。

人脸识别 java_基于Java实现人脸识别功能(附源码)相关推荐

  1. 基于Java的学籍管理系统(附 源码 论文 课件)

    项目背景: 随着计算机产业的迅速发展,电子计算机已广泛的应用于信息管理.文字处理.辅助设计.辅助教学及人们的日常生活中.基于WEB的学生学籍管理系统主要是针对高校中涉及高校学生学籍管理的一系列相关工作 ...

  2. 名片识别 java_基于JAVA的名片识别接口调用代码实例

    [java]代码库import java.io.BufferedReader; import java.io.DataOutputStream; import java.io.IOException; ...

  3. springboot+mysql+基于java的邮件收发管理系统 毕业设计-附源码101025

    springboot邮件收发管理系统 摘 要 科技进步的飞速发展引起人们日常生活的巨大变化,电子信息技术的飞速发展使得电子信息技术的各个领域的应用水平得到普及和应用.信息时代的到来已成为不可阻挡的时尚 ...

  4. 基于Java毕业设计校园网络维修系统源码+系统+mysql+lw文档+部署软件

    基于Java毕业设计校园网络维修系统源码+系统+mysql+lw文档+部署软件 基于Java毕业设计校园网络维修系统源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开 ...

  5. 基于Java毕业设计员工婚恋交友平台源码+系统+mysql+lw文档+部署软件

    基于Java毕业设计员工婚恋交友平台源码+系统+mysql+lw文档+部署软件 基于Java毕业设计员工婚恋交友平台源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开 ...

  6. 基于JAVA休闲网络宾馆管理计算机毕业设计源码+系统+数据库+lw文档+部署

    基于JAVA休闲网络宾馆管理计算机毕业设计源码+系统+数据库+lw文档+部署 基于JAVA休闲网络宾馆管理计算机毕业设计源码+系统+数据库+lw文档+部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

  7. 基于Java毕业设计写手管理平台源码+系统+mysql+lw文档+部署软件

    基于Java毕业设计写手管理平台源码+系统+mysql+lw文档+部署软件 基于Java毕业设计写手管理平台源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开发语言: ...

  8. 基于JAVA糖果销售管理系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA糖果销售管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA糖果销售管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语 ...

  9. 基于Java毕业设计缘梦书屋网站源码+系统+mysql+lw文档+部署软件

    基于Java毕业设计缘梦书屋网站源码+系统+mysql+lw文档+部署软件 基于Java毕业设计缘梦书屋网站源码+系统+mysql+lw文档+部署软件 本源码技术栈: 项目架构:B/S架构 开发语言: ...

  10. 基于JAVA的工资管理系统计算机毕业设计源码+数据库+lw文档+系统+部署

    基于JAVA的工资管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 基于JAVA的工资管理系统计算机毕业设计源码+数据库+lw文档+系统+部署 本源码技术栈: 项目架构:B/S架构 开发语言: ...

最新文章

  1. 2022-2028年中国操作系统行业深度调研及投资前景预测报告
  2. ES shard unassigned的解决方法汇总
  3. tinyhttpd-0.1.0_hacking
  4. HTML5 开发APP
  5. git 客户端查看不同分支的文件
  6. fckeditor编辑器自定义加按钮菜单
  7. Linux-破解rhel7-root密码
  8. linux安装python27_linux下安装python27 nginx 和uwsgi
  9. jsf ajax循环调用,每次JSF ajax回发后执行JavaScript
  10. 2019 互联网月饼大赏!阿里开动物园,腾讯秀表情包,网易游戏最会玩!
  11. c语言中static 用法
  12. mysql.sock介绍
  13. MPFC++ wrapper by Pavel
  14. swagger 源代码_我们如何使用swagger代码生成器从Angular 4更新到Angular 5
  15. Scrum立会报告+燃尽图(Final阶段第七次)
  16. 快排两种实现及五种优化
  17. 工程师必读书籍_最佳软件工程师必读书籍
  18. Neuron segmentation using 3D wavelet integratedencoder–decoder network
  19. 虚拟机安装mysql步骤
  20. 你以为我在玩游戏,其实我在学编程,这一波我在大气层

热门文章

  1. Python官方文档入门小教程
  2. Linux制作ISO镜像文件
  3. Alibaba内部713页Java程序性能优化实战手册首次开放,大受好评
  4. Matlab程序接口应用总结
  5. svn之删除文件并释放空间
  6. 分享112个留言聊天PHP源码,总有一款适合你
  7. VB6源代码收藏页面
  8. adb工具下载及安装
  9. SAP固定资产业务场景及方案
  10. 计算机网络安全基础-网络监听基本概念