前端js摄像头拍照,后端java调用百度api进行人脸识别登录

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 keysecret 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

  • 9
    点赞
  • 60
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值