java 开发 face++ 人脸特征识别系统
首先要在 face++ 注册一个账号,并且创建一个应用,拿到 api key 和 api secret;
下载 java 接入工具,一个 jar 包:https://github.com/FacePlusPlus/facepp-java-sdk
请求返回的数据是 json 格式,需要导入 json 解析包:
commons-beanutils-1.8.3.jar
commons-lang-2.5.jar
commons-collections-3.2.2.jar
ezmorph-1.0.6.jar
json-lib-2.3-jdk15.jar
图片上传类:FileUpLoad.java
package com.krry; import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.UUID;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload; /**
* FileUpLoad
* @author krry
*
*/
@WebServlet(name="fileUp",urlPatterns={"/show"})
public class FileUpLoad extends HttpServlet{ private static final long serialVersionUID = 1L; @Override
public void service(HttpServletRequest request,HttpServletResponse response) throws IOException{
//判断是不是文件上传,根据请求包里面的内容是否为二进制提交的上传的文件 true/false
boolean isMultPart = ServletFileUpload.isMultipartContent(request);
if(isMultPart){
//创建文件上传工厂
FileOutputStream out = null;
InputStream in = null;
try {
FileItemFactory factory = new DiskFileItemFactory();
//创建容器文件类,负责处理上传的文件数据
ServletFileUpload upload = new ServletFileUpload(factory);
//解析上传文件,其实就是解析表单传过来的数据
List<FileItem> fileItems = upload.parseRequest(request);
//只需要拿一张图片
in = fileItems.get(0).getInputStream();
//获取源文件名
String Ofilename = fileItems.get(0).getName();
//拿到后缀名
String ext = Ofilename.substring(Ofilename.indexOf("."), Ofilename.length());
//拿到一个目录,绝对地址
String path =request.getSession().getServletContext().getRealPath("/");
//生成一个唯一的名字
String fileName = UUID.randomUUID().toString() + ext;
//定义上传目录
String dirPath = path+"/upload";
File dirFile = new File(dirPath);
//如果此文件夹不存在
if(!dirFile.exists()){
dirFile.mkdirs();//创建此文件夹
}
//配置文件路径
String filePath = path+"/upload/"+fileName;
//输出流
out = new FileOutputStream(filePath);
//边读取边编写 字节流
byte[] b = new byte[1024];
int length = 0;
while((length = in.read(b)) != -1){ //读到字节数组里面去
out.write(b,0,length); //从0开始写,写你读了多少
}
//放在request作用域里
request.setAttribute("imgSrc", filePath);
request.setAttribute("imgSrcPage", "upload/"+fileName);
//请求转发,转发到另一个servlet
request.getRequestDispatcher("showImage").forward(request, response);
} catch (Exception e) { e.printStackTrace();
}finally{
out.close();
in.close();
}
}
} }
人脸识别类:Analysis.java
这里返回一个 json 字符串,放到作用域,在前台获取
package com.krry; import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.TreeMap; import javax.net.ssl.SSLException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; import net.sf.json.JSONArray;
import net.sf.json.JSONObject; /**
* analysis
* @author krry
* String 转json 需要的jar包:版本不能弄错
* commons-beanutils-1.8.3.jar
commons-lang-2.5.jar
commons-collections-3.2.2.jar
ezmorph-1.0.6.jar
json-lib-2.3-jdk15.jar
*/
@WebServlet(name="analysis",urlPatterns={"/showImage"})
public class Analysis extends HttpServlet{ private static final long serialVersionUID = 1L; @Override
public void service(HttpServletRequest request,HttpServletResponse response) throws IOException{ //获取上传的图片地址
String imgPath = request.getAttribute("imgSrc").toString();
File file = new File(imgPath);
byte[] buff = getBytesFromFile(file);
String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
HashMap<String, String> map = new HashMap<String, String>();
HashMap<String, byte[]> byteMap = new HashMap<String, byte[]>();
map.put("api_key", "15N9eBF_ieE-N2nvI7oK_A9anh2meuUS");
map.put("api_secret", "cBnvsIAo8VaOj53lXCWlpuOSd0NrsFif");
map.put("return_landmark", "1");
map.put("return_attributes", "gender,age,smiling,headpose,facequality,blur,eyestatus,emotion,ethnicity,beauty,mouthstatus,eyegaze,skinstatus");
byteMap.put("image_file", buff);
try{
byte[] bacd = post(url, map, byteMap);
String str = new String(bacd); JSONObject json = JSONObject.fromObject(str);
JSONArray faces = json.getJSONArray("faces"); //解析失败
if(str.indexOf("error_message") != -1 || faces.size() == 0){
request.getSession().setAttribute("error", "解析失败,请重新选择");
//重定向到首页
response.sendRedirect("index.jsp");
}else{
//将人脸信息字符串str信息放到作用域
request.setAttribute("face", str);
//请求转发,返回到页面
request.getRequestDispatcher("showImage.jsp").forward(request, response);
}
}catch (Exception e) {
e.printStackTrace();
} } private final static int CONNECT_TIME_OUT = 30000;
private final static int READ_OUT_TIME = 50000;
private static String boundaryString = getBoundary(); protected static byte[] post(String url, HashMap<String, String> map, HashMap<String, byte[]> fileMap) throws Exception {
HttpURLConnection conne;
URL url1 = new URL(url);
conne = (HttpURLConnection) url1.openConnection();
conne.setDoOutput(true);
conne.setUseCaches(false);
conne.setRequestMethod("POST");
conne.setConnectTimeout(CONNECT_TIME_OUT);
conne.setReadTimeout(READ_OUT_TIME);
conne.setRequestProperty("accept", "*/*");
conne.setRequestProperty("Content-Type", "multipart/form-data; boundary=" + boundaryString);
conne.setRequestProperty("connection", "Keep-Alive");
conne.setRequestProperty("user-agent", "Mozilla/4.0 (compatible;MSIE 6.0;Windows NT 5.1;SV1)");
DataOutputStream obos = new DataOutputStream(conne.getOutputStream());
Iterator iter = map.entrySet().iterator();
while(iter.hasNext()){
Map.Entry<String, String> entry = (Map.Entry) iter.next();
String key = entry.getKey();
String value = entry.getValue();
obos.writeBytes("--" + boundaryString + "\r\n");
obos.writeBytes("Content-Disposition: form-data; name=\"" + key
+ "\"\r\n");
obos.writeBytes("\r\n");
obos.writeBytes(value + "\r\n");
}
if(fileMap != null && fileMap.size() > 0){
Iterator fileIter = fileMap.entrySet().iterator();
while(fileIter.hasNext()){
Map.Entry<String, byte[]> fileEntry = (Map.Entry<String, byte[]>) fileIter.next();
obos.writeBytes("--" + boundaryString + "\r\n");
obos.writeBytes("Content-Disposition: form-data; name=\"" + fileEntry.getKey()
+ "\"; filename=\"" + encode(" ") + "\"\r\n");
obos.writeBytes("\r\n");
obos.write(fileEntry.getValue());
obos.writeBytes("\r\n");
}
}
obos.writeBytes("--" + boundaryString + "--" + "\r\n");
obos.writeBytes("\r\n");
obos.flush();
obos.close();
InputStream ins = null;
int code = conne.getResponseCode();
try{
if(code == 200){
ins = conne.getInputStream();
}else{
ins = conne.getErrorStream();
}
}catch (SSLException e){
e.printStackTrace();
return new byte[0];
}
ByteArrayOutputStream baos = new ByteArrayOutputStream();
byte[] buff = new byte[4096];
int len;
while((len = ins.read(buff)) != -1){
baos.write(buff, 0, len);
}
byte[] bytes = baos.toByteArray();
ins.close();
return bytes;
}
private static String getBoundary() {
StringBuilder sb = new StringBuilder();
Random random = new Random();
for(int i = 0; i < 32; ++i) {
sb.append("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_-".charAt(random.nextInt("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_".length())));
}
return sb.toString();
}
private static String encode(String value) throws Exception{
return URLEncoder.encode(value, "UTF-8");
} public static byte[] getBytesFromFile(File f) {
if (f == null) {
return null;
}
try {
FileInputStream stream = new FileInputStream(f);
ByteArrayOutputStream out = new ByteArrayOutputStream(1000);
byte[] b = new byte[1000];
int n;
while ((n = stream.read(b)) != -1)
out.write(b, 0, n);
stream.close();
out.close();
return out.toByteArray();
} catch (IOException e) {
}
return null;
} }
解析 json 字符串,先转换成 json 格式,json 数组,一个个获取人脸属性
<%@page import="net.sf.json.JSONObject"%>
<%@page import="net.sf.json.JSONArray"%>
<%@ page language="java" import="java.io.File" pageEncoding="utf-8"%>
<%@page import="java.math.BigDecimal"%>
<%@ page import="java.util.*" %>
<% String path = request.getContextPath();
int port = request.getServerPort();
String basePath = null;
if(port==80){
basePath = request.getScheme()+"://"+request.getServerName()+path;
}else{
basePath = request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+path;
}
pageContext.setAttribute("basePath", basePath); Object str = request.getAttribute("face");
JSONObject json = JSONObject.fromObject(str);
JSONArray faces = json.getJSONArray("faces");
StringBuffer strBuff = new StringBuffer();
//识别出人脸的个数
int length = faces.size(); //识别出多少个人脸,就是循环多少次
for(int i = 0;i < length;i++){ JSONObject face = faces.getJSONObject(i); //拿到第i+1个人脸部信息
JSONObject attribute = face.getJSONObject("attributes");//拿到脸部属性 //年龄
JSONObject age = attribute.getJSONObject("age");
int ageValue = age.getInt("value"); //性别
JSONObject gender = attribute.getJSONObject("gender");
String sex = gender.getString("value");
if(sex.equals("Male")) sex = "男";
else sex = "女"; //人种
JSONObject ethnicity = attribute.getJSONObject("ethnicity");
String races = ethnicity.getString("value");
if(races.equals("Asian")) races = "亚洲人";
else if(races.equals("White")) races = "白人";
else races = "黑人"; //微笑程度
JSONObject smile = attribute.getJSONObject("smile");
String smileRange = String.format("%.2f",smile.getDouble("value")); //表情
JSONObject emotion = attribute.getJSONObject("emotion");
Map<String,Double> mapp = new TreeMap<String,Double>();
//装配表情信息到map
double sadness = emotion.getDouble("sadness");
mapp.put("伤心", sadness);
double neutral = emotion.getDouble("neutral");
mapp.put("平静", neutral);
double disgust = emotion.getDouble("disgust");
mapp.put("厌恶", disgust);
double anger = emotion.getDouble("anger");
mapp.put("愤怒", anger);
double happiness = emotion.getDouble("happiness");
mapp.put("高兴", happiness);
double surprise = emotion.getDouble("surprise");
mapp.put("惊讶", surprise);
double fear = emotion.getDouble("fear");
mapp.put("恐惧", fear); //利用list取最大值
List<Double> listmap = new ArrayList<Double>();
for(String key:mapp.keySet()){
listmap.add(mapp.get(key));
}
//取到最大值
double valueMax = Collections.max(listmap);
//根据map的value获取map的key
String emotionMax = "";
for (Map.Entry<String, Double> entry : mapp.entrySet()) {
if(valueMax == entry.getValue()){
emotionMax = entry.getKey();
}
} //颜值分数
JSONObject beauty = attribute.getJSONObject("beauty");
String beautys = "";
if(sex.equals("男")) beautys = String.format("%.2f",beauty.getDouble("male_score"));
else beautys = String.format("%.2f",beauty.getDouble("female_score")); //面部状态
JSONObject skinstatus = attribute.getJSONObject("skinstatus");
Map<String,String> mapSkin = new TreeMap<String,String>();
//装配信息到map
double health = skinstatus.getDouble("health");
mapSkin.put("健康指数", String.format("%.2f",health));
double stain = skinstatus.getDouble("stain");
mapSkin.put("色斑指数", String.format("%.2f",stain));
double acne = skinstatus.getDouble("acne");
mapSkin.put("青春痘指数", String.format("%.2f",acne));
double dark_circle = skinstatus.getDouble("dark_circle");
mapSkin.put("黑眼圈指数", String.format("%.2f",dark_circle)); strBuff.append("<br>");
strBuff.append("<span>年龄:").append(ageValue).append("岁</span>");
strBuff.append("<span>性别:").append(sex).append("</span>");
strBuff.append("<br>").append("<br>");
strBuff.append("<span>人种:").append(races+"</span>");
strBuff.append("<span>微笑程度:").append(smileRange+"%</span>");
strBuff.append("<br>").append("<br>");
strBuff.append("<span>表情:").append(emotionMax+"</span>");
strBuff.append("<span>颜值分数:").append(beautys+"</span>");
strBuff.append("<br>").append("<br>");
int counts = 0;
for(String key:mapSkin.keySet()){
counts++;
strBuff.append("<span>"+key+":").append(mapSkin.get(key)+"</span>");
if(counts % 2 == 0) strBuff.append("<br>").append("<br>");
} strBuff.append("<br>"); } %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head> <title> Java开发人脸特征识别系统 --krry</title> <meta http-equiv="pragma" content="no-cache">
<meta http-equiv="cache-control" content="no-cache">
<meta http-equiv="expires" content="0">
<meta http-equiv="keywords" content="keyword1,keyword2,keyword3">
<meta http-equiv="description" content="This is my page"> <style type="text/css">
*{padding:0px;margin:0px;}
body{background: #FFF;background:url("images/78788.jpg");background-size:cover;}
.a_btn{text-decoration:none;font-family:"幼圆";background:#fff;transition:.6s;color:#f60;cursor:pointer;width:100px;height:40px;border-radius:10px;display: inline-block;text-align:center;line-height:40px;}
.aa{position: absolute;left: 48px;top: 31px;}
.a_btn:hover{background:red;color:#fff;transition:.6s;}
.clear{clear:both;}
.title{margin-top: 25px;font-size:48px;font-family:"幼圆";color: #ff7272;text-shadow: 1px 1px 3px #ff3737;text-align:center;line-height:45px;}
.content{margin:0 auto;width:900px;}
.content .img{float:left;margin-top:30px;}
.content .img img{border-radius:10px;}
.content .describe{margin-top:30px;width:500px;color:#000;font-family:"幼圆";font-size:18px;float:right;}
.content .describe span{width: 190px;display: inline-block;}
</style> </head> <body>
<div class="aa"><a class="a_btn" href="${basePath}">返回</a></div>
<div class="title">人脸识别结果</div>
<div class="content">
<div class = "img">
<img style="float:left" width="350" src="${imgSrcPage}" />
</div>
<div style="float:right" class="describe"><%=strBuff.toString() %></div>
<div class="clear"></div>
</div>
</body>
</html>
首页:
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"%> <% Object ermsg = request.getSession().getAttribute("error");
StringBuffer strBuff = new StringBuffer();
if(ermsg != null){
//清除作用域
request.getSession().removeAttribute("error");
strBuff.append("loading('"+ermsg+"',4)");
}
%> <!doctype html>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html;charset=utf-8">
<meta name="keywords" content="关键词,关键词">
<meta name="description" content="">
<link rel="stylesheet" type="text/css" href="css/sg.css" />
<link rel="stylesheet" type="text/css" href="css/sg/css/animate.css" />
<link rel="stylesheet" type="text/css" href="css/sg/css/sg.css" /> <title> Java开发人脸特征识别系统 --krry</title>
<style type="text/css">
*{padding:0px;margin:0px;}
body{background:url("images/5.jpg");background-size:cover;font-size:18px;font-family:"微软雅黑";color:#666;}
img{border:none;}
h1{font-size:24px;}
.title{margin-top: 30px;font-size:48px;font-family:"幼圆";color: #ff7272;text-shadow: 1px 1px 3px #ff3737;text-align:center;line-height:45px;}
.box{margin:100px auto;text-align:center;}
.box .b_btn{width:100px;height:40px;background:#fff;transition:.6s;font-size:16px;font-family:"微软雅黑";display:block;margin:54px auto;text-align:center;
cursor:pointer;line-height:40px;text-decoration:none;color:#F60;border:1px;border-radius:12px}
.box .b_btn:hover{background:red;color:#fff;transition:.6s;}
.busbu{top:0;background:rgba(0, 0, 0, 0.2);display:none;width:100%;height:100%;position:absolute;z-index:1000;}
</style>
</head> <body>
<!--action 提交的路径 method:post(打包传输) get(明文传输) enctype(采用二进制)-->
<form action="show" method="post" enctype="multipart/form-data">
<div class="box">
<div class="title">人脸特征识别系统 --krry</div>
<input type="file" id="fileChoice" accept="image/jpeg,image/png" style="display:none" name="files"/>
<a class="b_btn" href="javascript:void(0);" onclick="choice()">选择照片</a>
<input type="button" value="提交解析" class="b_btn" id="but"/>
<input type="submit" class="sub_btn" style="display:none;"/>
</div>
</form>
<div class="busbu"></div>
<script src="js/jquery-1.11.3.min.js"></script>
<script src="js/sg.js"></script>
<script src="js/sgutil.js"></script>
<script type="text/javascript" src="css/sg/tz_util.js"></script>
<script type="text/javascript" src="css/sg/sg.js"></script>
<script type="text/javascript">
<%=strBuff.toString() %>
//选择照片
function choice(){
//js 弱类型 快速定位
var choose = document.getElementById("fileChoice");
choose.click();
}
$("#but").click(function(){
if($("#fileChoice").val()){//如果选择了照片
$(".sub_btn").click();
$(".busbu").show();
loading("正在解析",900);//再展示
}else{
$.tmDialog.alert({open:"top",content:"请先选择一张照片",title:"Krry温馨提醒"});
}
}); </script>
</body> </html>
需要注意的点,json 字符串的转换和解析,获取 json 中人脸属性的方法
git:https://github.com/Krryxa/face
java 开发 face++ 人脸特征识别系统的更多相关文章
- 分享:Java 开发精美艺术二维码
博客地址:https://ainyi.com/58 Java 开发精美艺术二维码 看到网络上各种各样的二维码层出不穷,好像很炫酷的样子,一时兴起,我也要制作这种炫酷二维码效果 例如: 根据以往例子 根 ...
- Java开发前期准备工作
配置Java开发环境变量 在"系统变量"中设置3项属性,JAVA_HOME, PATH, CLASSPATH. 变量设置参数如下: 变量名:JAVA_HOME 变量值:C:\Pro ...
- Win7 32位系统下Java开发环境的安装及配置
目录: Java JDK安装. Java JDK系统环境的配置. 配置常见问题的解决. Java JDK的安装 Java Jdk(Java Development Kit)Java开发不可缺少的环境, ...
- Java开发笔记(八十一)如何使用系统自带的注解
之前介绍继承的时候,提到对于子类而言,父类的普通方法可以重写也可以不重写,但是父类的抽象方法是必须重写的,如果不重写,编译器就直接在子类名称那里显示红叉报错.例如,以前演示抽象类用法之时,曾经把Chi ...
- Nodejs开发人脸识别系统-教你实现高大上的人工智能
Nodejs开发人脸识别系统-教你实现高大上的人工智能 一.缘起缘生 前段时间有个H5很火,上传个头像就可以显示自己穿军装的样子,无意中看到了一篇帖子叫 全民刷军装背后的AI技术及简单实现 ,里面 ...
- Ubuntu系统Java开发环境的搭建
操作系统:Linux x64 / Ubuntu 14.04 Java JDK版本:jdk-8u65-linux-x64.tar.gz 声明:转载请注明出处及本文链接 本文原文地址:Ubuntu系统Ja ...
- 基于java开发的在线题库系统tamguo
简介 探果网(简称tamguo)是基于java开发的在线题库系统,包括 在线访问 后台运营 会员中心 书籍中心 管理员账号:system 密码:123456 因为线上数据和测试数据没有做到隔离,作者已 ...
- Windows系统下JAVA开发环境搭建
首先我们需要下载JDK(JAVA Development Kit),JDK是整个java开发的核心,它包含了JAVA的运行环境,JAVA工具和JAVA基础的类库. 下载地址:http://www.or ...
- SSM开发基于Java EE在线图书销售系统
SSM(Spring+Spring MVC+MyBatis)开发基于Java EE在线图书销售系统 网站成功建立和运行很大部分取决于网站开发前的规划,因此为了在网站建立过程中避免一些不 ...
随机推荐
- 读《Linux Shell脚本攻略》(第2版) 总结
前段时间读完了<Linux Shell脚本攻略>(第2版)这本书,给部分想读这本书的人分享下个人感受. 说下这本书的难度吧.纯新手或者只懂少部分编程知识的人,读起来还是有很大难度的.以我为 ...
- centos/linux下的使得maven/tomcat能在普通用户是使用
以下操作#代表在root用户下使用 $表示在普通用户下使用 1.创建新用户 # useradd lonecloud 2.设置该用户的密码 # passwd lonecloud 3.因为昨天将tomca ...
- Egret学习笔记 (Egret打飞机-8.敌机和主角飞机发射子弹)
经过前面几章的准备,我们差不多已经具备了一个基本的框架,这一章我们就开始添砖加瓦了. 敌机定时发射一个子弹,子弹的方向是从上到下,但是发射子弹的代码应该放在哪儿呢? 从面向对象编程的思想来说,子弹是敌 ...
- hdu1061(2015-N1):1.快速幂;2.找规律
1.快速幂 原理:求a的b次方,将b转化为二进制数,该二进制位第i位的权是2^(i-1), 例如 11的二进制是1011 11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1 因此,我们将a¹ ...
- 计蒜客 无脑博士 bfs
题目链接无脑博士的试管们 思路:直接模拟倒水过程即可,但是需要记忆判断当前的情况是否已经处理过.dfs和bfs都ok AC代码 #include <cstdio> #include < ...
- ACdream 1031 Cut
题意:给定一棵树,删除一些边,让整棵树被分成多个节点数为偶数的联通块,且联通块尽量多. 思路:如果出现连通且节点数为偶数的立即删除这个点与它父节点之间的边,尽量删除即可,因为题目说了保证n为偶数,删了 ...
- ios开发之自定义textView
自定义textView,从理论上讲很简单,根据需求自定义,比如我在开发中的需求就是现实一个字数的限制以及根据输入的文字改变提示剩余字数,那么开始我的基本思路就是自定义一个View,而里面包含一个子控件 ...
- 后台模拟请求 HttpHelper 序列化 MD5 时间戳
使用场景 C# 服务器后台调用其他服务器并处理 场景 /// <summary> /// 获取用户信息 /// </summary> /// <param name=&q ...
- Vue第一个自定义组件:数字输入框(number-input)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- sizeof计算空间大小的总结
sizeof,看起来还真不简单,总结起来还是一大堆的东西,不过这是笔试面试中出现比较频繁的,我也是考过才觉得很重要,有些规则如果不注意,还真是拿到一道题目摸不着头脑,所有总结一下,方面忘记的时候瞄一瞄 ...