1.数据收集工具
在lookie-lookie的基础上,删除了训练相关的功能,保留了以下功能:
-
Draw Heatmap 绘制标记的点
-
Clear Heatmap 清除绘制的点
-
Load Dataset 载入之前保存的数据集
-
Save Dataset 保存当前的数据集
当前的目录结构如下:
├── hint.mp3 提示音
├── index.html 主要页面
├── js
│ ├── dataset.js 与数据收集相关的文件
│ ├── facetracker.js 面部追踪的文件,包括摄像头的开启和画面截取处理
│ ├── globals.js 与启动摄像头相关的文件
│ ├── heat.js 与绘制标记点相关的文件
│ ├── main.js 主要逻辑,调用其他文件的内容
│ ├── mouse.js 与鼠标相关的文件,主要是返回转换后的标签位置
│ ├── ui.js 与UI相关的文件,包含对用户的提示
│ └── vendor
│ └── clmtrackr.js 面部追踪的API文件
├── normalize.css
└── style.css
由于我们的模型想在原来基础上加上脸部的信息,因此我增加了一个50x50的canvas来绘制部分脸部图像如下:
接下来就是对采集数据逻辑的一些修改了,这里就不细说了,说一下最终的效果:
1.注视鼠标指针然后按下空格来采集数据
采集后右上角的数字会增加,同时如果点击"draw heatmap"按钮会绘制出当前采集的屏幕坐标:
小一点的点用于训练,大一点的点用于验证。
2.保存采集的数据
采集一段时间数据之后,可以点击"save dataset"按钮来保存数据,数据会以json文件形式下载到默认的下载目录中,文件名为dataset.json:
可以在python中利用如下的方式来读取json中的内容:
import numpy as np
import json
from PIL import Image
def load_data(file,validation = 0):
with open(file,'r') as f:
dic = json.load(f)
if(validation == 0): # 如果是取训练集
data = dic['train']['x']
label =dic['train']['y']
else: # 如果是取验证集
data = dic['val']['x']
label =dic['val']['y']
eyes = np.array(data[0]) #眼部图片
face = np.array(data[1]) #脸部图片
image_info = np.array(data[2]) #眼部图片在整个画面中的位置、大小信息
label = np.array(label) #标签
eyes = eyes.reshape((-1,25,50,3))
face = face.reshape((-1,50,50,3))
image_info = image_info.reshape((-1,4))
label = label.reshape(-1,2)
return eyes,face,image_info,label
if __name__=='__main__':
data=load_data('./dataset.json',1)
print(data[0].shape)
3.读取采集的内容
可以在之前保存的采集数据的基础上继续扩充采集量,点击"load dataset"就可以选择对应的json文件然后将其读取进来:
2.前端运行框架
目前我们采集的每一帧视频用于三项功能的处理:
- 视线追踪
- 手势识别
- 情绪识别
功能 | 实时性要求 | x需要的图像 |
---|---|---|
视线追踪 | 实时0.1s | 脸部图像、眼部图像 |
手势识别 | 实时0.1s | 全部原始图像 |
情绪识别 | 5~10s | 全部原始图像 |
所以需要合理的来调用摄像头的画面。
此外,由于每次产生页面跳转都会重新向用户申请摄像头的权限(至少现在还不知道如何在页面跳转的情况下保留已经获得的权限),因此这里我在第一个html页面调用了摄像头,然后利用load语句来加载其他的html页面,然后在其他页面中写获取服务器数据的逻辑,这样虽然比较繁琐,但是可以避免页面跳转失去权限的问题。
如图,在主页面index.html中打开了摄像头,然后利用load语句载入了list.html的内容,在list.html中则是像服务器请求了文章相关的数据:
index.html中的载入语句:
$("#content").load('list.html')
list.html中的内容请求语句:
function getNextPage(lastId){
$.post('http://localhost:8080/article/list',{'lastId':lastId},putArt); //putArt为渲染的回调函数
}
这样就可以获取摄像头的内容同时从服务器获取到数据了,接下来我整合了一下我们之前没有加上脸部信息的模型来实验。
功能调用的方式如下:
首先完成功能执行时的函数,在这里是操纵一个小球来根据预测结果进行运动:
const $target = $('#target');
const targetSize = $target.outerWidth();
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();
console.log(prediction)
const left = prediction[0] * ($('body').width() - $('#target').outerWidth());
const top = prediction[1] * ($('body').height() - $('#target').outerWidth());
//console.log(left)
//console.log(right)
$('#target').css('left', left + 'px');
$('#target').css('top', top + 'px');
}
然后在index.html中加一个定时器来每100毫秒调用一次这个函数:
setInterval(moveTarget, 100);
效果如下:
眼部可以简单的操控这个圆球的运动,但由于目前的模型还不够好所以反应还不够灵敏,但改正模型的任务也在进行中。
下一步我打算等其他团队成员的情绪识别和手势识别部分完成之后来整合一下,来看一下会不会有性能上的问题。