文章目录
- 0. 需求
- 1. 前端实现
-
- 1.1 如何调用摄像头
- 1.2 如何用ajax将图片从前端传到后端
- 2. 后端实现
-
- 2.1 如何接收ajax上传的图片
- 2.2 如何调用百度人脸对比api
- 3. 后端难点
-
- 3.1 图片怎么存mysql数据库
- 3.2 图片怎么取出数据库
- 4. 细节问题
-
- 4.1 百度api访问频率限制
- 4.2 为啥改了后端代码前端没有任何改变
- 4.3 我有一个form表单负责用户输入,怎么让它始终在屏幕最底端?
- 5. end
0. 需求
在前端调用摄像头进行用户拍照,将照片传至后端,后端调用百度人脸对比api进行人相对比,如果相似度达到90%以上则进行登录。
1. 前端实现
1.1 如何调用摄像头
js代码如下:
// 启动摄像头
function activateCamera() {
document.getElementById("vedioWindow").hidden=false;
document.getElementById("canvasWindow").hidden=false;
//video捕获摄像头画面
navigator.mediaDevices.getUserMedia({
video: true,
}).then(success).catch(error)
function success(stream) {
video.src = window.webkitURL.createObjectURL(stream);
video.play();
}
function error(err) {
alert('video error: ' + err)
}
}
function shoot() {
//把当前视频帧内容渲染到画布上
context.drawImage(self.video, 0, 0, 200, 200);
}
function myUpload() {
//生成图片格式base64包括:jpg、png格式
var Data = canvas.toDataURL("image/jpeg", 1.0);
var imageDataB64 = Data.substring(22);
//这里我打算用ajax方式,所以需要使用Formdata形式
var data = new FormData();
data.append("imgData", imageDataB64);
$.ajax({
url:"/admin/faceLogin",
type: "post",
data: data,
//async: true,
contentType: false,
processData:false, // 告诉浏览器不要处理我的数据 直接发就行
success: function (res) {
setCookie('isLogin','1');
setCookie('userId',res.data.id);
setCookie('userName', res.data.username);
window.location.href = "myQuestionnaires.html";
}
});
}
第一个函数对应人脸识别按钮,点击此按钮打开摄像头;
第二个函数对应拍照按钮,点击按钮将当前摄像头的内容捕获下来并显示到canvas上。
第三个函数对应上传按钮,点击上传就可以将canvas上显示的照片上传到服务器端,进行后续操作。
1.2 如何用ajax将图片从前端传到后端
代码如下:
//生成图片格式base64包括:jpg、png格式
var Data = canvas.toDataURL("image/jpeg", 1.0);
//去掉图片首端的一些说明信息(占22位)
var imageDataB64 = Data.substring(22);
//这里我打算用ajax方式,所以需要使用Formdata形式
var data = new FormData();
data.append("imgData", imageDataB64);
$.ajax({
url:"/admin/faceLogin",
type: "post",
data: data,
//async: true,
contentType: false,
processData:false, // 告诉浏览器不要处理我的数据 直接发就行
success: function (res) { // 登陆成功的回调函数
setCookie('isLogin','1');
setCookie('userId',res.data.id);
setCookie('userName', res.data.username);
window.location.href = "myQuestionnaires.html";
}
});
前端的内容大概就是这些。
2. 后端实现
2.1 如何接收ajax上传的图片
前面我们用ajax传递了一个data过来,data中有一个字段"imgData"对应了用户的图片。因此可以在controller的参数中取到这个图片的内容。
@RequestMapping(value = "/faceLogin", method = RequestMethod.POST, headers = "Accept=application/json")
@ResponseBody
public HttpResponseEntity faceLogin(@RequestParam("imgData") String imgData, HttpServletRequest request) {
HttpResponseEntity httpResponseEntity = new HttpResponseEntity();
//这里实现你的其他操作
}
RequestPara代表传递过来的内容中必须要有"imgData",否则会出错。
String imgData就直接可以取到图片信息!!!名字一样就可以了!
需要注意前端我们取到的图片就已经是String类型的了(编码是base64),所以这里也要用String接收。
2.2 如何调用百度人脸对比api
我简单说一下要使用百度api的准备工作:
1.先去百度智能云注册登录
2.创建人脸识别应用
3.获得application key和secret key
调用百度api的大致流程:
1.先用你的application key(简称ak)和你的secret key(简称sk)发送请求获取一个access_token
2.用这个token和你要对比的两张图片发送url请求进行人脸对比
3.获取百度api的返回值,再返回值中取得相似度。
代码我不贴了,百度智能云api文档中有。
我说一个要注意的地方,那就是传递过去的数据格式。
首先,你要传递的数据格式是json,其次,你要传递的图片编码是base64。
我们在前端获取的图片非常好,本身就是base64的编码,因此我们可以直接传给百度api使用。但是如果你要使用你本机的图片jpg或者png等就需要先把文件转为base64编码的字符串才可以传过去。
现在问题又来了,你分别有了两张图片的base64编码的字符串,怎么把他们转成格式符合要求的json进行发送呢?代码如下:
List<Map<String, Object>> map = new ArrayList<>();
Map<String, Object> map1 = constructImageJson(img);
Map<String, Object> map2 = constructImageJson(imgData);
map.add(map1);
map.add(map2);
private Map<String, Object> constructImageJson(String res) {
Map<String, Object> map = new HashMap<>();
map.put("image", res);
map.put("image_type", "BASE64");
map.put("face_type", "LIVE");
map.put("quality_control", "LOW");
map.put("liveness_control", "NORMAL");
return map;
}
经过上述处理,你可以或者一个包含两个map的List,然后再把这个List转成json格式就可以传过去了。
String param = GsonUtils.toJson(map); //转List为json
//向百度api发送请求,result就是结果
// url代表百度api的url
result = HttpUtil.post(url, access_token, "application/json", param);
如果对比成功,那么在返回的json中将会有一个score字段记录了两种图片的相似度,通常来说,如果相似度达到百分之90以上就可以认为是同一个人,可以成功登录。
//解析传回的结果
JSONObject sb = JSONObject.parseObject(result);
//从结果中取得score
double score = JSONObject.parseObject(sb.getString("result")).getDouble("score");
//如果相似度大于等于90
if (score>=90) {
httpResponseEntity.setData(ue); //传递用户信息
httpResponseEntity.setCode(Constans.SUCCESS_CODE); //传递用户名
httpResponseEntity.setMessage("登陆成功!");
break;
}
return httpResponseEntity;
然后在前端进行页面的跳转和相应cookie的设置,整个登录过程就到此结束啦!
3. 后端难点
3.1 图片怎么存mysql数据库
思路如下:
1.设置数据库相应字段的类型为BLOB(或者MediumBlob等)
2.再将图片变为字节数组byte[]
3.将字节数组存入数据库即可
File转byte[]代码:
File f = new File("D:\\Temp\\anwserQuestionnaire-master\\anwserQuestionnaire-master\\src\\main\\resources\\static\\images\\zzq.png");
byte[] data = null;
try {
FileInputStream fis = new FileInputStream(f);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
int len;
byte[] buffer = new byte[1024];
while ((len = fis.read(buffer)) != -1) {
baos.write(buffer, 0, len);
}
data = baos.toByteArray();
fis.close();
baos.close();
} catch (Exception e) {
e.printStackTrace();
}
ue.setImage(data);
userService.insertUserImage(ue);
mybatis怎么写?
<update id="insertUserImage" parameterType="com.aim.questionnaire.dao.entity.UserEntity">
update user_info set image = #{image, jdbcType=BLOB} where id = #{id, jdbcType=VARCHAR}
</update>
需要注意的就是jdbcType写BLOB
3.2 图片怎么取出数据库
先看mybatis:
<resultMap type="com.aim.questionnaire.dao.entity.UserEntity" id="imgResultMap" >
<id column="id" jdbcType="VARCHAR" property="id" />
<result property="username" column="username" jdbcType="VARCHAR" />
<result property="image" column="image" jdbcType="BLOB" typeHandler="org.apache.ibatis.type.BlobTypeHandler"/>
</resultMap>
<select id="queryAllUserImage" resultMap="imgResultMap">
select id, username, image
from user_info
</select>
1.resultMap标签中,id表示主键,只有一个,result表示普通的字段。
1.property表示type中实体的一个属性(强烈建议要有一个对应的实体,不管你需不需要,都最好建立一个实体与之对应),column表示数据库的一个字段名。
3.取图片时,一定要在后方额外加一个typeHandler=“org.apache.ibatis.type.BlobTypeHandler”,否则出错。
而对于queryAllUserImage函数的返回值,写成相应实体的List就行。如:List<UserEntity>。
4. 细节问题
4.1 百度api访问频率限制
限制是qps=2,所以每请求两次就Thread.sleep(1000);睡眠一秒就行。
土豪请充钱。
4.2 为啥改了后端代码前端没有任何改变
1.首先确定你代码是不是写对了,如果对了,看2.
2.解决方法(1)删除你浏览器最近24小时的所有数据(2)进入浏览器的无痕模式,重新尝试
4.3 我有一个form表单负责用户输入,怎么让它始终在屏幕最底端?
前端我不太懂。
代码:
<form action="" style="position: fixed; bottom: 0px; margin-bottom: 20px">
...
</form>
具体参数还可以调整。其他标签也是同样使用了,要让标签在其他位置,比如最上,最右也可以这样,调一下方向就好。
当然最左最右也可以用float: right;和float: left来实现,这样也可以让两个标签位于同一行。
5. end
end