前段时间有幸得到了一个人脸识别的Java课程,开始以为是什么高大上的课程,后来才知道原来十分简单
整体都是调用接口,具体怎么实现呢
项目整体都是利用别人企业的工具实现的
首先我们需要注册一个账号,账号的网址如下,注册账号的时候好想要选择身份,我们选择个人就可以:
https://console.faceplusplus.com.cn/dashboard
接下来需要获取一个key和sercret
创建完毕之后,我们就会得到一个key和secret
相关的API文档都可以在官网进行查看,里面有参数的说明和使用方法
接下来废话不多说,上项目:
项目背景:cxk同学被主管叫过去说要提升公司的登录逼格,要将原有的账号密码登录改为人脸识别登录,还好xk同学很高兴,因为之前主管总是说一个很菜的人“你真是徐坤开门,菜到家了”,这次xk同学想发挥自己刚刚学习过的技术。
首先我们创建一个java项目,因为我们只需要实现后端功能,所以需要的jar包很少,只需要导入一个fastjson就可以了,所以根据个人爱好, 创建maven项目也不会麻烦的
项目结构如下
FaceUtil.java
package org.Util;
import java.io.File;
import java.util.HashMap;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
public class FaceUtil {
/**
* 根据传入图片进行人脸检测
* @param file 传入的人脸照片
* @return 返回人脸照片的facetoken,如果为空说明图片不符合要求
* @throws Exception
*/
public static String detect(File file) throws Exception {
byte[] buff = HTTPUtil.getBytesFromFile(file);
String url = "https://api-cn.faceplusplus.com/facepp/v3/detect";
HashMap<String, byte[]> byteMap = new HashMap<>();
byteMap.put("image_file", buff);
byte[] bacd = HTTPUtil.post(url, HTTPUtil.map, byteMap);
String str = new String(bacd);
if(str.indexOf("error_message")!=-1) {
return null;
}
JSONObject obj = JSONObject.parseObject(str);
int faceNum=obj.getIntValue("face_num");
if(faceNum==1) {
//获取facetoken
JSONObject face=(JSONObject) ((JSONArray)obj.get("faces")).get(0);
String faceToken=face.getString("face_token");
return faceToken;
}
return null;
}
/**
* 查询指定的照片是否在人脸集合faceset中存在
* @param faceToken
* @return
* @throws Exception
*/
public static boolean search(String faceToken) throws Exception {
String url = "https://api-cn.faceplusplus.com/facepp/v3/search";
HTTPUtil.map.put("face_token", faceToken);
byte[] bacd = HTTPUtil.post(url, HTTPUtil.map, null);
String str = new String(bacd);
if(str.indexOf("error_message")==-1) {//请求没有错误
JSONObject json = JSONObject.parseObject(str);
JSONObject thresholds=(JSONObject) json.get("thresholds");
Double le5=thresholds.getDouble("1e-5");
JSONArray results=(JSONArray) json.get("results");
if(results!=null && results.size()>=1) {
Double confidence=((JSONObject)results.get(0)).getDouble("confidence");
if(confidence>le5) {
return true;
}
}
}
return false;
}
/**
* 添加人脸到faceset中
* @param face_tokens 要添加的人脸
* @return
* @throws Exception
*/
public static boolean addFace(String face_tokens) throws Exception {
if(!getDetail()) {//先获取人脸集合,没有集合就创建一个
System.out.println("没有获取到指定人脸集合");
boolean res=createFaceSet();
if(!res) {
System.out.println("创建人脸集合出问题了!");
return false;
}
System.out.println("创建人脸集合成功!");
}
String url = "https://api-cn.faceplusplus.com/facepp/v3/faceset/addface";
HTTPUtil.map.put("face_tokens", face_tokens);
byte[] bacd = HTTPUtil.post(url, HTTPUtil.map, null);
String str = new String(bacd);
if(str.indexOf("error_message")!=-1) {
return false;
}
return true;
}
/**
* 创建一个人脸的集合 FaceSet,用于存储人脸标识 face_token。
* @return
* @throws Exception
*/
public static boolean createFaceSet() throws Exception {
String url = "https://api-cn.faceplusplus.com/facepp/v3/faceset/create";
byte[] bacd = HTTPUtil.post(url, HTTPUtil.map, null);
String str = new String(bacd);
System.out.println(str);
if(str.indexOf("error_message")!=-1) {
return false;
}
System.out.println("创建人脸集合:"+str);
return true;
}
/**
* 获取一个faceset
* @return
* @throws Exception
*/
public static boolean getDetail() throws Exception {
String url = "https://api-cn.faceplusplus.com/facepp/v3/faceset/getdetail";
byte[] bacd = HTTPUtil.post(url, HTTPUtil.map, null);
String str = new String(bacd);
if(str.indexOf("error_message")!=-1) {
return false;
}
return true;
}
}
HTTPUtil.java
package org.Util;
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.HashMap;
import java.util.Iterator;
import java.util.Map;
import java.util.Properties;
import java.util.Random;
import javax.net.ssl.SSLException;
public class HTTPUtil {
private final static int CONNECT_TIME_OUT = 30000;
private final static int READ_OUT_TIME = 50000;
private static String boundaryString = getBoundary();
public static HashMap<String, String> map = new HashMap<>();
static {
Properties pro=new Properties();
InputStream in=FaceUtil.class.getResourceAsStream("/api.properties");
try {
pro.load(in);
} catch (IOException e) {
e.printStackTrace();
System.out.println("配置文件加载错误!");
}
map.put("api_key", pro.getProperty("API_KEY"));
map.put("api_secret", pro.getProperty("API_SECRET"));
map.put("display_name", pro.getProperty("DISPLAY_NAME"));
map.put("outer_id", pro.getProperty("OUTER_ID"));
}
public 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;
}
}
ImageUtils.java
package org.Util;
import java.util.Base64;
import java.util.UUID;
import java.util.Base64.Decoder;
import javax.servlet.http.HttpServletRequest;
import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
public class ImageUtils {
/**
* 上传图片到指定位置
* @param request
* @param picName 客户端文件的name
* @param picPath 文件上传的路径
* @return
*/
public static File uploadImg(HttpServletRequest request,String picName,String picPath) {
String imgData = request.getParameter(picName);//获取客户端传输到服务器的图片
String path = request.getServletContext().getRealPath("/"+picPath+"/");//获取指定的图片上传到服务器的路径
String fileName = UUID.randomUUID().toString().replace("-", "")+".png";//给图片一个随机名称
boolean flag=generateImage(imgData.substring(22), path, fileName);//上传图片
System.out.println("图片上传:"+flag+",地址:"+path);
return new File(path+"/"+fileName);
}
private static boolean generateImage(String imgStr, String filePath, String fileName) {
try {
if (imgStr == null) {
return false;
}
Decoder decoder = Base64.getDecoder();
byte[] b = decoder.decode(imgStr);
File file = new File(filePath);
if (!file.exists()) {
file.mkdirs();
}
OutputStream out = new FileOutputStream(filePath+fileName);
out.write(b);
out.flush();
out.close();
return true;
} catch (Exception e) {
return false;
}
}
}
test.java
package org.yc;
import org.Util.FaceUtil;
import java.io.File;
public class test {
public static void main(String[] args){
File file=new File("D:\\my bug\\ideal\\test\\web\\static\\cxk.png");
try {
String str=FaceUtil.detect( file ); //人脸健测
System.out.println("face_token:"+str);
boolean res=FaceUtil.search( str ); //搜索结果
System.out.println("人脸搜索的结果:"+res);
//获取人脸集合
res=FaceUtil.getDetail();
if(!res){
FaceUtil.createFaceSet();
System.out.println("如果没有指定的outer_id,则创建一个人脸集合");
}
System.out.println("outer_id为ycFaceSet的人脸集合:"+res);
System.out.println("添加face_token到人脸集合中");
FaceUtil.addFace( str );
res=FaceUtil.search( str );
System.out.println("再次检测outer_id中的是否有这个face_token:"+res);
} catch (Exception e) {
e.printStackTrace();
}
}
}
api.properties
API_KEY=账号的key
API_SECRET=账号的secret
DISPLAY_NAME=ycFaceSet
OUTER_ID=ycFaceSet
接下来献上我的主角:
我们通过代码可以发现即使换了人脸,试别的结果也是true。