又是一年畢業季,自己轉眼間也畢業一年了!!!前段時間幫學妹指導了一個小區人臉識別門禁系統,整個的實現思路在此記錄下,感興趣的可以參考一下。
整個項目溝通後情況如下:
需求功能:
- 人臉錄入
- 人臉更新
- 人臉刪除
- 人臉搜索
- 數據備份,數據恢復
- 人臉登錄
- 登錄統計
- 管理員系統登錄
- 小區管理
所用技術:按客戶掌握的技能採用java、servlet、vue、jquery、js、ajax、boostrap、css、人臉圖像處理部分主要採用百度api。
工期:2個星期。
整個項目最終效果:
- 登錄模塊的實現思路
(一)代碼實現
1、用戶請求程序登錄入口login.html頁面;
2、採集攝像頭實時人臉數據,每個1秒鐘截取攝像頭視頻一幀畫面,將人臉圖片數據轉換成base64格式發送給後臺控制器;
3、控制器接收前臺傳入的人臉數據,調用具體的人臉搜索服務;
4、後臺拼裝參數請求百度api接口;
5、後臺獲取百度api接口響應數據;
6、後臺判斷該用戶人臉數據是否存在遠程人臉庫且相似度超過80%,則繼續查詢本地該用戶保存的社區信息和用戶基本信息並返回,同時記錄用戶登錄記錄,最後提示用戶登錄成功。反之則返回空的用戶信息用戶登錄失敗;
(二)代碼實現
//截取圖片並請求後臺隔
package com.face.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.face.opj.Face;
import com.face.opj.FaceAndGroup;
import com.face.opj.Groups;
import com.face.opj.MsgSearch;
import com.face.opj.ResultObj;
import com.face.service.FaceInfoCrud;
import com.face.service.FaceSearch;
import com.face.service.GroupsInfoCrud;
import com.face.service.LoginInfoCrud;
import com.google.gson.Gson;
import sun.misc.BASE64Decoder;
@WebServlet("/Login")
public class Login extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8;");
PrintWriter out = response.getWriter();
String b64 = request.getParameter("saveImg");
BASE64Decoder decoder = new BASE64Decoder();
byte[] b = decoder.decodeBuffer(b64);
Gson gson = new Gson();
FaceInfoCrud fc = new FaceInfoCrud();
GroupsInfoCrud gc = new GroupsInfoCrud();
LoginInfoCrud lc = new LoginInfoCrud();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ResultObj ro = new ResultObj("500", "操作失敗", null);
Map result = new HashMap<String, Object>();
result.put("groupName", "noInfo");
result.put("name", "noInfo");
result.put("tel", "noInfo");
result.put("addr", "noInfo");
//調用百度人臉接口查詢
if(b64!=null) {
MsgSearch msgs = FaceSearch.Search(b);
if(msgs.error_code == 0) {
String userId = msgs.ShowSearched().user_id;
String groupId = msgs.ShowSearched().group_id;
ArrayList<FaceAndGroup> list2 = fc.selectOne(userId);
String groupName = "";
if(list2.size() > 0) {
if(null != list2.get(0).ext3) {
ArrayList<Groups> list1 = gc.selectOne(list2.get(0).ext3);
groupName = list1.get(0).name;
}
result.put("groupName", groupName);
result.put("name", list2.get(0).name);
result.put("tel", list2.get(0).tel);
result.put("addr", list2.get(0).ext2);
result.put("role", list2.get(0).role);
ro.code = "200";
ro.msg = "操作成功";
ro.obj = result;
lc.insert(groupName,list2.get(0).name, list2.get(0).tel,sf.format(new Date()));
}else{
ro.code = "500";
ro.msg = "沒有在本地人臉庫查到數據";
ro.obj = result;
}
}else {
ro.code = "500";
ro.msg = "請求遠程人臉庫失敗";
ro.obj = result;
}
}else {
ro.code = "500";
ro.msg = "人臉參數爲空";
ro.obj = result;
}
out.print(gson.toJson(ro));
out.close();
}
}
二、小區信息管理模塊
添加小區:
1、管理員通過訪問admin.html管理頁面;
2、管理員輸入相應的小區信息,並點擊保存;
3、後臺獲取輸入的小區信息並保存到數據庫;
4、後臺返回操作成功信息;
5、前臺刷新小區信息;
刪除小區:
- 查詢該小區的所有用戶;
- 刪除小區信息;
- 刪除該小區所有用戶的本地人臉照片;
- 刪除該小區所有用戶的本地數據;
- 刪除該小區所有用戶的遠程數據;
查詢所有小區:
- 用戶輸入或者不輸入小區信息後點擊查詢按鈕;
- 後臺獲取查詢參數;
- 後臺查詢小區信息並返回;
更新小區:
- 用戶輸入小區更改後的信息;
- 後臺獲取參數並保存;
package com.face.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.face.opj.FaceAndGroup;
import com.face.opj.Groups;
import com.face.opj.Msg;
import com.face.opj.ResultObj;
import com.face.service.AddGroup;
import com.face.service.DeleteGroup;
import com.face.service.FaceInfoCrud;
import com.face.service.GroupsInfoCrud;
import com.face.utils.FileUtil;
import com.face.utils.GsonUtils;
import com.google.gson.Gson;
@WebServlet("/GroupOperation")
public class GroupOperation extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8;");
String Operation = request.getParameter("Operation");
String id = request.getParameter("id");
String name = request.getParameter("name");
Gson gson = new Gson();
SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
ResultObj ro = new ResultObj("500", "操作失敗", null);
AddGroup ag = new AddGroup();
DeleteGroup dg = new DeleteGroup();
FaceInfoCrud fc = new FaceInfoCrud();
GroupsInfoCrud gc = new GroupsInfoCrud();
if("delete".equals(Operation)) {
ArrayList<FaceAndGroup> list = fc.selectByGroupId(id);
int isSuccess = gc.delete(id);
if(isSuccess == 1) {
String path = "";
for(FaceAndGroup fg:list) {
path = request.getServletContext().getRealPath("")+fg.getUrl();
FileUtil.deletePic(path);
fc.delete(fg.getTel());
}
ro.setCode("200");
ro.setMsg("刪除小區成功!");
// 遠程用戶組在人臉搜索時有數量限制,因此用戶的小區信息只保存在本地 默認一個用戶組user
// Msg msg = GsonUtils.fromJson(dg.deleteGroup(id), Msg.class);
// if(msg.error_code == 0) {
// ro.setCode("200");
// ro.setMsg("刪除小區成功!");
// }else {
// ro.setCode("500");
// ro.setMsg("遠程刪除小區失敗!");
// }
}else {
ro.setCode("500");
ro.setMsg("本地刪除小區失敗!");
}
}else if("add".equals(Operation)) {
boolean exist = gc.exist(id);
if(exist) {
ro.setCode("500");
ro.setMsg("小區編號已存在!");
}else {
int isSuccess = gc.insert(id, name, sf.format(new Date()));
if(isSuccess == 1) {
ro.setCode("200");
ro.setMsg("小區添加成功!");
// 遠程用戶組在人臉搜索時有數量限制,因此用戶的小區信息只保存在本地 默認一個用戶組user
// Msg msg = GsonUtils.fromJson(ag.addGroup(id), Msg.class);
// if(msg.error_code == 0) {
// ro.setCode("200");
// ro.setMsg("小區添加成功!");
// }else {
// ro.setCode("500");
// ro.setMsg("遠程添加小區失敗!");
// }
}else {
ro.setCode("500");
ro.setMsg("本地添加小區失敗!");
}
}
}else if("selectAll".equals(Operation)) {
Map data = new HashMap<String, Object>();
ArrayList<Groups> list = gc.selectAll();
data.put("groups", list);
ro.setCode("200");
ro.setMsg("查詢成功!");
ro.setObj(data);
}else if("update".equals(Operation)) {
int result = gc.update(name, sf.format(new Date()), id);
ro.setCode("200");
ro.setMsg("查詢成功!");
}
PrintWriter out = response.getWriter();
out.print(gson.toJson(ro));
out.close();
}
}
三、用戶信息管理模塊
添加用戶:
- 用戶輸入註冊信息並請求後臺;
- 後臺獲取註冊信息;
- 判斷該用戶是否已存在;
- 存在着立即返回;
- 不存在則註冊人臉到百度人臉庫;
- 保存用戶照片到本地;
- 保存用戶信息到數據庫;
- 返回註冊成功信息;
刪除用戶:
- 管理員刪除指定用戶;
- 後臺刪除該用戶基本信息;
- 刪除改用戶保存的人臉照片;
- 刪除遠程人臉庫該用戶的信息;
- 返回操作成功信息;
查詢用戶:
- 管理員輸入查詢參數;
- 後臺後去查詢參數並查詢數據庫;
- 後臺返回查詢結果;
package com.face.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.face.opj.Face;
import com.face.opj.FaceAndGroup;
import com.face.opj.Msg;
import com.face.opj.ResultObj;
import com.face.service.FaceDelete;
import com.face.service.FaceInfoCrud;
import com.face.utils.FileUtil;
import com.face.utils.GsonUtils;
import com.google.gson.Gson;
@WebServlet("/UserOperation")
public class UserOperation extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8;");
String Operation = request.getParameter("Operation");
String tel = request.getParameter("tel");
String token = request.getParameter("token");
String groupId = request.getParameter("groupId");
String url = request.getParameter("url");
Gson gson = new Gson();
ResultObj ro = new ResultObj("500", "操作失敗", null);
FaceInfoCrud fc = new FaceInfoCrud();
if("delete".equals(Operation)) {
String path = request.getServletContext().getRealPath("")+url;
System.out.println(path);
int isSuccess = fc.delete(tel);
if(isSuccess == 1) {
FileUtil.deletePic(path);
Msg msg = GsonUtils.fromJson(FaceDelete.delete(tel,groupId,token), Msg.class);
if(msg.error_code == 0) {
ro.setCode("200");
ro.setMsg("刪除用戶成功!");
}else {
ro.setCode("500");
ro.setMsg("遠程刪除用戶失敗!");
}
}else {
ro.setCode("500");
ro.setMsg("本地刪除用戶失敗!");
}
}else if("selectOne".equals(Operation)) {
Map data = new HashMap<String, Object>();
ArrayList<FaceAndGroup> list = fc.selectOne(tel);
data.put("users", list);
ro.setCode("200");
ro.setMsg("查詢所有用戶成功!");
ro.setObj(data);
}else if("selectAll".equals(Operation)) {
Map data = new HashMap<String, Object>();
ArrayList<FaceAndGroup> list = fc.selectAll();
data.put("users", list);
ro.setCode("200");
ro.setMsg("查詢所有用戶成功!");
ro.setObj(data);
}
PrintWriter out = response.getWriter();
out.print(gson.toJson(ro));
out.close();
}
}
四、登錄統計模塊
折線圖的渲染:
1、前臺發送登錄統計請求;
2、後臺統計某日期的6個時間段24小時的登錄次數;
3、前臺接收後臺響應數據;
4、echarts根據響應數據渲染折線圖,實現登錄數據的可視化;
登錄日誌詳情:
- 前臺發送查詢日誌詳情請求;
- 後臺接收查詢參數;
- 後臺查詢日誌信息並返回到前臺;
package com.face.servlet;
import java.io.IOException;
import java.io.PrintWriter;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.face.opj.FaceAndGroup;
import com.face.opj.Groups;
import com.face.opj.Logs;
import com.face.opj.Msg;
import com.face.opj.ResultObj;
import com.face.service.AddGroup;
import com.face.service.DeleteGroup;
import com.face.service.FaceInfoCrud;
import com.face.service.GroupsInfoCrud;
import com.face.service.LoginInfoCrud;
import com.face.utils.FileUtil;
import com.face.utils.GsonUtils;
import com.google.gson.Gson;
@WebServlet("/LogsOperation")
public class LogsOperation extends HttpServlet {
private static final long serialVersionUID = 1L;
public void doPost(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8;");
String Operation = request.getParameter("Operation");
String date = request.getParameter("date");
String xiaoqu = request.getParameter("xiaoqu");
Gson gson = new Gson();
ResultObj ro = new ResultObj("500", "操作失敗", null);
LoginInfoCrud lc = new LoginInfoCrud();
if("tongji".equals(Operation)) {
Map m = lc.loginStatistics(date,xiaoqu);
ro.setCode("200");
ro.setMsg("統計成功!");
ro.setObj(m);
}else if("add".equals(Operation)) {
}else if("select".equals(Operation)) {
Map m = new HashMap<String, Object>();
ArrayList<Logs> list = lc.select(date,xiaoqu);
m.put("logs", list);
ro.setCode("200");
ro.setMsg("統計成功!");
ro.setObj(m);
}
PrintWriter out = response.getWriter();
out.print(gson.toJson(ro));
out.close();
}
}
五、數據備份模塊
1、前臺發送數據備份請求;
2、後臺接收請求;
3、後臺讀取所有用戶照片信息;
4、後臺讀取數據庫人臉信息;
5、後臺生成壓縮包,並寫入上述文件;
6、返回改壓縮包url地址;
package com.face.servlet;
import java.io.File;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import com.face.utils.FileToZip;
@WebServlet("/BackUps")
public class BackUps extends HttpServlet {
private static final long serialVersionUID = 1L;
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
}
protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
request.setCharacterEncoding("utf-8");
response.setContentType("text/html;charset=utf-8;");
String path = request.getServletContext().getRealPath("");
System.out.println(request.getServletContext().getRealPath(""));
Date date = new Date();
String downloadFilePath = path+"backups/"+date.getTime()+".zip";
String downoladDbPath = path+"backups/dbdata"+date.getTime()+".txt";
String downloadAllPicPath = path+"photo/";
List<File> allFile = new ArrayList<File>();
allFile = FileToZip.getPics(downloadAllPicPath);
allFile.add(FileToZip.getDbContent(downoladDbPath));
File zipFile = new File(downloadFilePath);
FileToZip.toZip(allFile, zipFile);
PrintWriter out = response.getWriter();
out.print("{\"url\":\""+"http://"+request.getHeader("host")+request.getContextPath()+"/backups/"+date.getTime()+".zip"+"\"}");
out.close();
}
}
需要完整代碼可發郵件至[email protected]