1.手势功能
由于只利用眼神很难提供太多的交互事件,因此我们增加了手势功能来提供更多的交互事件,这里利用百度已有的API来实现手势功能,详情可以看这里的API文档:
https://ai.baidu.com/docs#/Body-API/top
1.1.创建应用
首先需要创建应用,填写相关信息之后确认,就可以获得API Key和secret Key,拥有它们才可以进行下一步的操作:
1.2.获取access_token
具体方式可以参考如下地址的API文档:
http://ai.baidu.com/docs#/Auth/top
这里似乎必须从服务端来获取,在HTML页面中直接发post请求就会报跨域的错误,这里我用bash来获取需要的access_token:
curl -i -k 'https://aip.baidubce.com/oauth/2.0/token?grant_type=client_credentials&client_id=【百度云应用的AK】&client_secret=【百度云应用的SK】'
从结果中可以看到获取到了这个access_token。
1.3.实现调用代码
这里只需要向接口发送access_token和base64编码的图片即可,从返回值中就可以拿到识别结果的json,结果json示例如下:
{
"log_id": 4466502370458351471,
"result_num": 2,
"result": [{
"probability": 0.9844077229499817,
"top": 20,
"height": 156,
"classname": "Face",
"width": 116,
"left": 173
},
{
"probability": 0.4679304957389832,
"top": 157,
"height": 106,
"classname": "Heart_2",
"width": 177,
"left": 183
}]
}
这里我封装了一个js文件gesture.js用于调用手势识别,识别之后打印出识别出的手势代号以及准确率:
const access_token = [自己的access_token];
window.gesture = {
dealGesture:function(json) {
for(var i = 0; i < json.result_num; i++) {
console.log(json.result[i].classname+' '+json.result[i].probability);
}
},
getGesture:function(base64Image) {
console.log(base64Image);
var image;
if(base64Image.substr(0,4) == 'data')
image = base64Image.substr(22, base64Image.length);
else
image = base64Image;
$.ajax({
type: "POST",
url: "https://aip.baidubce.com/rest/2.0/image-classify/v1/gesture",
contentType: "application/x-www-form-urlencoded",
dataType: "json", //表示返回值类型,不必须
data: {'access_token': access_token, 'image' : image},
success: gesture.dealGesture
});
}
}
然后编写测试的HTML然后调用这个方法来获得图片中的手势代号:
从控制台中打印的结果可以看出,图片中的人物所做的手势是比心,此外在图片中识别出了人脸,两者准确率都超过了90%。
下一步就是通过对手势所对应的事件进行定义然后完成相应的功能。
2.文章选择功能
从文章列表页面需要通过视线定位具体文章标题然后进一步进入具体的文章页面:
我们预计提供两种进入方式:
- 利用手势左划或者右划来进入、退出页面
- 全视线控制的进入、退出页面
第一种实现方式目前还在调试之中,所以这里我先使用第二种实现方式来实现文章的进入:
- 当视线停留在标题块上的时候,标题块开始从红色变为绿色。
- 如果在变为绿色之前移开了视线,则标题块变回原来的白色。
- 如果在标题块最终变为了绿色,则进入到标题对应的文章页面。
- 当视线没有停留在标题块上时,什么都不做。
该功能主要利用JavaScript的计时器来实现,通过计时器来实现颜色的渐变,等时间到了再载入具体的文章HTML页面,具体实现代码如下:
window.cursor = {
left: 0,
top: 0
}
const OPEN_TIME = 3000;
var openClock; //计时器
var clockLeft; //剩余时间
var curElement; //当前元素
var oriColor; //当前元素的原始颜色
function openArticle(ele){
return function(){
// 从r转换到g
clockLeft -= 100;
if(clockLeft <= 0){ //如果午时已到
$("#content").load('article.html')
window.article_id = ele.parentNode.id.substr(2);
clearInterval(openClock);//清除计时器
}
curColorValue = parseInt(clockLeft / OPEN_TIME * 255); //计算颜色值
ele.style.background = 'rgb(' + curColorValue +', ' + (255 - curColorValue) + ', 0)';
}
}
function getPostParent(ele){
parNode = ele;
while(parNode != null && parNode.nodeName != '#document'){
if(parNode.className.indexOf('blog-post') != -1){
return parNode;
}
parNode = parNode.parentNode; //获取父节点
}
return null;
}
function moveTarget() {
// Move the model target to where we predict the user is looking to
if (itrack.currentModel == null || facetracker.currentEyeRect==null || itrack.inTraining) {
return;
}
const prediction = itrack.getPrediction();
cursor.left = prediction[0] * ($('body').width() - $('#target').outerWidth());
cursor.top = prediction[1] * ($('body').height() - $('#target').outerWidth());
var ele = document.elementFromPoint(cursor.left,cursor.top); //获取元素
ele = getPostParent(ele);
if(ele != null){ //如果元素不为空
if(curElement != ele){ //如果是标题并且没有在计时当中
clockLeft = OPEN_TIME; //设置剩余时间
if(curElement != null){ //如果有元素在计时
curElement.style.background = oriColor; //恢复原来的颜色
}
oriColor = ele.style.background; //保存原来的颜色
clearInterval(openClock); //清除历史计时器
openClock = setInterval(openArticle(ele),100); //每100ms检查一次
curElement = ele; //重新设置当前计时的标签
}
}else{
if(curElement != null){ //如果有元素在计时
curElement.style.background = oriColor; //恢复原来的颜色
curElement = null; //清空当前元素
clearInterval(openClock); //清除历史计时器
}
}
$('#target').css('left', cursor.left + 'px');
$('#target').css('top', cursor.top + 'px');
}
使用情况如下:
可见标题块正在逐渐变成绿色,当彻底变为绿色之后,会跳转到具体文章页面。
如图可见这里成功跳转到了具体文章页面。