2020/11/13·Java·人脸识别一键登录/注册

2 篇文章 0 订阅
1 篇文章 0 订阅



1.eclipse 和 tomcat 服务器的安装与使用

1.1 Eclipse 的安装

该 Eclipse 为免安装版,解压找到 eclipse.exe 双击打开即可使用
eclipse 2019/12
提取码:6vlf

1.2 Eclipse 配置 Tomcat

在 eclipse 上面导航栏点击Window——》Show View ——》Other ——》选中Server 下面的 Servers,点击 open
Tomcat 9
提取码:h73c
在控制台点击 Server 选项,右键空白处,new——》Server ——》选择 Apache ——》选择Tomcat 9, next ——》选择 Tomcat 9 的解压路径 ——》Finish,可以看到 eclipse 左边导航栏多了个 Servers。

1.3 新建 Web 项目

File ——》New ——》Other ——》输入 Web,选择 Dynamic Web Project ,next ——》填写项目名,Target Runtime 为刚刚配置的Tomcat9(一般会自动选择),next,next ——》按需勾选 web.xml ——》Finish

1.4 新建页面测试

右键 WebContent ——》创建 new HTML File,取名 ——》随便输入内容即可 ——》右键页面 ——》Run as ——》Run On Server ——》选择 Choose an existing server 和 刚刚配置的 Tomcat,next ——》添加当前项目 ——》点击Finish。即可在 eclipse 中打开刚刚的测试页面,如果想要默认打开 Google,Window——》Preferences ——》Web Browser ——》选择 use external web browser ,选择 Google ——》ApplyAndClose。



2.前沿生态–图像识别介绍

2.1 概念

2.1.1 前沿生态-图像识别技术

图像识别技术是人工智能的一个重要领域。它是指对图像进行对象识别,以识别各种不同模式的目标和对像的技术。

图像识别技术是立体视觉、运动分析、数据融合等实用技术的基础,在导航、地图与地形配准、自然资源分析、天气预报、环境监测、生理病变研究等许多领域重要的应用价值。

2.1.2 人脸 face_token

人脸(Face)在人脸识别技术中特指图像中发现的人脸,当对一张图片进行人脸检测时,会将检测到的人脸记录下来,包括人脸在图片中的位置,用一个系统标识face_token来表示。

注意:对同一张图片进行多次人脸检测,对同一个人脸会得到不同的face_token。

2.1.3 人脸集合 faceSet

人脸集合(FaceSet)是用来存储检测到人脸的存储对象。一个FaceSet内face_token是不重复的。

2.1.4 人脸搜索

计算机检测到图片中一个人脸之后,通过人脸判断人身份的过程被称为人脸搜索。

人脸搜索是指采集用户新的人脸,在多个已知身份用户的人脸集合中进行搜索,找出新的人脸属于哪一个已知身份用户。人脸搜索需要调用Search API。

3.Face++ 账号申请

常规申请方法,填写个人信息,选择个人用户,绑定邮箱,电话号码,注册成功之后根据提示创建第一个应用(免费的)。完毕

4.根据 API 接口封装的工具的使用

需要用到阿里巴巴的 fastjson 依赖包;

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;
	}

}

5.其它工具

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;
	}
}
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;
        }
    }

}

properties配置文件参数从Face++ 账号获取

API_KEY=
API_SECRET=
DISPLAY_NAME=
OUTER_ID=

6.注册/登陆功能的实现

ServletController

@WebServlet("/faceController")
public class FaceController extends HttpServlet {

	private static final long serialVersionUID = 1L;

	/**
	 * 1.接受客户端的请求 request
	 * 2.处理请求
	 * 3.返回数据给客户端 response
	 */
	@Override
	protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		
		//登陆步骤
		//1.获取用户上传的图片——上传到指定文件夹中upImg
		File file = ImageUtils.uploadImg(req, "imgData", "upImg");
		boolean res = false;
		boolean delFlag = true;
		try {
			//检查人脸信息:detect
			String faceToken = FaceUtil.detect(file);
			//如果包含人脸信息
			if(faceToken!=null) {
				//在 faceSet 中查找是否有相似度较高的人脸信息:search
				//有:登陆成功,删除图片;无:登陆失败,删除图片
				res = FaceUtil.search(faceToken);
				//判断用户请求类型
				String type = req.getParameter("type");
				//如果是注册
				if("register".equals(type)) {
					//如果 faceSet 中有匹配的人脸
					if(res) {
						res=false;
					}else {//如果 faceSet 中没有匹配
						res=FaceUtil.addFace(faceToken);
						delFlag=false;
					}
				}
				
			}else {//不包含人脸信息,登陆失败,删除图片
				
			}
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} finally {
			//删除图片
			if(delFlag) {
				file.delete();
			}
			//返回数据给客户端 response
			PrintWriter pw = resp.getWriter();
			String msg = "{\"success\":"+res+"}";
			pw.write(msg);
		}
	}

	@Override
	protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		// TODO Auto-generated method stub
		this.doGet(req, resp);
	}

}

7.前端页面

页面
此处显示部分前端代码

<body class="no-skin">

<div class="main-container ace-save-state" id="main-container">

    <div class="main-content">
        <div class="main-content-inner">

            <div class="page-content">

                <div style="padding: 10px;">
                	<table>
	                    <tr>
	                        <td colspan="2">
	                            <button class="btn btn-sm btn-default" onclick="openMedia()">开启摄像头</button>
	                            <button class="btn btn-sm btn-default" onclick="closeMedia()">关闭摄像头</button>
	                            <button class="btn btn-sm btn-default" onclick="takePhoto('login')">登录</button>
	                            <button class="btn btn-sm btn-default" onclick="takePhoto('register')">注册</button>
	                        </td>
	                    </tr>
                    </table>
                    <table>
                        <tr>
                            <td>
                                <video id="video" width="500px" height="500px" autoplay="autoplay"></video>
                                <canvas id="canvas" width="500px" height="500px" style="display: none"></canvas>
                            </td>
                            <!-- <td>
                                <img id="imgTag" src="" alt="..." width="500px" height="500px"><br>
                            </td> -->
                        </tr>
                    </table>

                    <script>
                        let mediaStreamTrack=null; // 视频对象(全局)
                        let video ;
                        function openMedia() {
                            let constraints = {
                                video: { width: 500, height: 500 },
                                audio: false
                            };
                            //获得video摄像头
                            video = document.getElementById('video');
                            let promise = navigator.mediaDevices.getUserMedia(constraints);
                            promise.then((mediaStream) => {
                                // mediaStreamTrack = typeof mediaStream.stop === 'function' ? mediaStream : mediaStream.getTracks()[1];
                                mediaStreamTrack=mediaStream.getVideoTracks()
                                video.srcObject = mediaStream;
                                video.play();
                            });
                        }

                        // 拍照
                        function takePhoto(str) {
                            //获得Canvas对象
                            let video = document.getElementById('video');
                            let canvas = document.getElementById('canvas');
                            let ctx = canvas.getContext('2d');
                            ctx.drawImage(video, 0, 0, 500, 500);


                            // toDataURL  ---  可传入'image/png'---默认, 'image/jpeg'
                            let img = document.getElementById('canvas').toDataURL();
                            // 这里的img就是得到的图片
                            console.log('img-----', img);
                            //document.getElementById('imgTag').src=img;
                            //alert(img);
                           // alert(str);
                            //上传
                            var flagStr="登录";
                            if(str=="register"){
                            	flagStr="注册";
                            }
                            $.ajax({
                                url:"faceController",
                                type:"POST",
                                data:{"imgData":img,"type":str},
                                dataType: "json",
                                success:function(data){
                                    var flag = data.success;
                                    if (flag) {
                                        alert(flagStr+"成功");
                                    } else {
                                        alert(flagStr+"失败!");
                                    }
                                }
                                ,error:function(){
                                    alert("服务器内部错误!"+flagStr+"失败")
                                }
                            });

                        }

                        // 关闭摄像头
                        function closeMedia() {
                            let stream = document.getElementById('video').srcObject;
                            let tracks = stream.getTracks();

                            tracks.forEach(function(track) {
                                track.stop();
                            });

                            document.getElementById('video').srcObject = null;
                        }
                    </script>
                </div>

            </div><!-- /.page-content -->
        </div>
    </div><!-- /.main-content -->

</div><!-- /.main-container -->

</body>

8.一文一哲理

用眼看世界,难免一叶障眼


最后麻烦朋友们的小手手点点赞,你们的点赞是我创作最好的动力

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值