faceapi
This commit is contained in:
@@ -18,7 +18,7 @@
|
||||
<script src="js/codemirror.min.js"></script>
|
||||
<script src="js/jquery.min.js"></script>
|
||||
<script src="js/tf.min.js"></script>
|
||||
<script src="js/blazeFace.js"></script>
|
||||
<script src="js/faceapi.min.js"></script>
|
||||
<script src="js/lang.js?v=5"></script>
|
||||
<script src="js/lang2.js?v=5"></script>
|
||||
<script src="js/farbtastic.js"></script>
|
||||
|
||||
File diff suppressed because one or more lines are too long
1
js/faceapi.min.js
vendored
Normal file
1
js/faceapi.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/age_gender_model-shard1
Normal file
BIN
js/models/age_gender_model-shard1
Normal file
Binary file not shown.
1
js/models/age_gender_model-weights_manifest.json
Normal file
1
js/models/age_gender_model-weights_manifest.json
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/face_expression_model-shard1
Normal file
BIN
js/models/face_expression_model-shard1
Normal file
Binary file not shown.
1
js/models/face_expression_model-weights_manifest.json
Normal file
1
js/models/face_expression_model-weights_manifest.json
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/face_landmark_68_model-shard1
Normal file
BIN
js/models/face_landmark_68_model-shard1
Normal file
Binary file not shown.
1
js/models/face_landmark_68_model-weights_manifest.json
Normal file
1
js/models/face_landmark_68_model-weights_manifest.json
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/face_landmark_68_tiny_model-shard1
Normal file
BIN
js/models/face_landmark_68_tiny_model-shard1
Normal file
Binary file not shown.
@@ -0,0 +1 @@
|
||||
[{"weights":[{"name":"dense0/conv0/filters","shape":[3,3,3,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008194216092427571,"min":-0.9423348506291708}},{"name":"dense0/conv0/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006839508168837603,"min":-0.8412595047670252}},{"name":"dense0/conv1/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009194007106855804,"min":-1.2779669878529567}},{"name":"dense0/conv1/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0036026100317637128,"min":-0.3170296827952067}},{"name":"dense0/conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.000740380117706224,"min":-0.06367269012273527}},{"name":"dense0/conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":1,"min":0}},{"name":"dense0/conv2/pointwise_filter","shape":[1,1,32,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":1,"min":0}},{"name":"dense0/conv2/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0037702228508743585,"min":-0.6220867703942692}},{"name":"dense1/conv0/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0033707996209462483,"min":-0.421349952618281}},{"name":"dense1/conv0/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014611541991140328,"min":-1.8556658328748217}},{"name":"dense1/conv0/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002832523046755323,"min":-0.30307996600281956}},{"name":"dense1/conv1/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006593170586754294,"min":-0.6329443763284123}},{"name":"dense1/conv1/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.012215249211180444,"min":-1.6001976466646382}},{"name":"dense1/conv1/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002384825547536214,"min":-0.3028728445370992}},{"name":"dense1/conv2/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005859645441466687,"min":-0.7617539073906693}},{"name":"dense1/conv2/pointwise_filter","shape":[1,1,64,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013121426806730382,"min":-1.7845140457153321}},{"name":"dense1/conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0032247188044529336,"min":-0.46435950784122243}},{"name":"dense2/conv0/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002659512618008782,"min":-0.32977956463308894}},{"name":"dense2/conv0/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015499923743453681,"min":-1.9839902391620712}},{"name":"dense2/conv0/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0032450980999890497,"min":-0.522460794098237}},{"name":"dense2/conv1/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005911862382701799,"min":-0.792189559282041}},{"name":"dense2/conv1/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021025861478319356,"min":-2.2077154552235325}},{"name":"dense2/conv1/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.00349616945958605,"min":-0.46149436866535865}},{"name":"dense2/conv2/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008104994250278847,"min":-1.013124281284856}},{"name":"dense2/conv2/pointwise_filter","shape":[1,1,128,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.029337059282789044,"min":-3.5791212325002633}},{"name":"dense2/conv2/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0038808938334969913,"min":-0.4230174278511721}},{"name":"fc/weights","shape":[128,136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.014016061670639936,"min":-1.8921683255363912}},{"name":"fc/bias","shape":[136],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0029505149698724935,"min":0.088760145008564}}],"paths":["face_landmark_68_tiny_model-shard1"]}]
|
||||
BIN
js/models/face_recognition_model-shard1
Normal file
BIN
js/models/face_recognition_model-shard1
Normal file
Binary file not shown.
6
js/models/face_recognition_model-shard2
Normal file
6
js/models/face_recognition_model-shard2
Normal file
File diff suppressed because one or more lines are too long
1
js/models/face_recognition_model-weights_manifest.json
Normal file
1
js/models/face_recognition_model-weights_manifest.json
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/mtcnn_model-shard1
Normal file
BIN
js/models/mtcnn_model-shard1
Normal file
Binary file not shown.
1
js/models/mtcnn_model-weights_manifest.json
Normal file
1
js/models/mtcnn_model-weights_manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"paths":["mtcnn_model-shard1"],"weights":[{"dtype":"float32","name":"pnet/conv1/weights","shape":[3,3,3,10]},{"dtype":"float32","name":"pnet/conv1/bias","shape":[10]},{"dtype":"float32","name":"pnet/prelu1_alpha","shape":[10]},{"dtype":"float32","name":"pnet/conv2/weights","shape":[3,3,10,16]},{"dtype":"float32","name":"pnet/conv2/bias","shape":[16]},{"dtype":"float32","name":"pnet/prelu2_alpha","shape":[16]},{"dtype":"float32","name":"pnet/conv3/weights","shape":[3,3,16,32]},{"dtype":"float32","name":"pnet/conv3/bias","shape":[32]},{"dtype":"float32","name":"pnet/prelu3_alpha","shape":[32]},{"dtype":"float32","name":"pnet/conv4_1/weights","shape":[1,1,32,2]},{"dtype":"float32","name":"pnet/conv4_1/bias","shape":[2]},{"dtype":"float32","name":"pnet/conv4_2/weights","shape":[1,1,32,4]},{"dtype":"float32","name":"pnet/conv4_2/bias","shape":[4]},{"dtype":"float32","name":"rnet/conv1/weights","shape":[3,3,3,28]},{"dtype":"float32","name":"rnet/conv1/bias","shape":[28]},{"dtype":"float32","name":"rnet/prelu1_alpha","shape":[28]},{"dtype":"float32","name":"rnet/conv2/weights","shape":[3,3,28,48]},{"dtype":"float32","name":"rnet/conv2/bias","shape":[48]},{"dtype":"float32","name":"rnet/prelu2_alpha","shape":[48]},{"dtype":"float32","name":"rnet/conv3/weights","shape":[2,2,48,64]},{"dtype":"float32","name":"rnet/conv3/bias","shape":[64]},{"dtype":"float32","name":"rnet/prelu3_alpha","shape":[64]},{"dtype":"float32","name":"rnet/fc1/weights","shape":[576,128]},{"dtype":"float32","name":"rnet/fc1/bias","shape":[128]},{"dtype":"float32","name":"rnet/prelu4_alpha","shape":[128]},{"dtype":"float32","name":"rnet/fc2_1/weights","shape":[128,2]},{"dtype":"float32","name":"rnet/fc2_1/bias","shape":[2]},{"dtype":"float32","name":"rnet/fc2_2/weights","shape":[128,4]},{"dtype":"float32","name":"rnet/fc2_2/bias","shape":[4]},{"dtype":"float32","name":"onet/conv1/weights","shape":[3,3,3,32]},{"dtype":"float32","name":"onet/conv1/bias","shape":[32]},{"dtype":"float32","name":"onet/prelu1_alpha","shape":[32]},{"dtype":"float32","name":"onet/conv2/weights","shape":[3,3,32,64]},{"dtype":"float32","name":"onet/conv2/bias","shape":[64]},{"dtype":"float32","name":"onet/prelu2_alpha","shape":[64]},{"dtype":"float32","name":"onet/conv3/weights","shape":[3,3,64,64]},{"dtype":"float32","name":"onet/conv3/bias","shape":[64]},{"dtype":"float32","name":"onet/prelu3_alpha","shape":[64]},{"dtype":"float32","name":"onet/conv4/weights","shape":[2,2,64,128]},{"dtype":"float32","name":"onet/conv4/bias","shape":[128]},{"dtype":"float32","name":"onet/prelu4_alpha","shape":[128]},{"dtype":"float32","name":"onet/fc1/weights","shape":[1152,256]},{"dtype":"float32","name":"onet/fc1/bias","shape":[256]},{"dtype":"float32","name":"onet/prelu5_alpha","shape":[256]},{"dtype":"float32","name":"onet/fc2_1/weights","shape":[256,2]},{"dtype":"float32","name":"onet/fc2_1/bias","shape":[2]},{"dtype":"float32","name":"onet/fc2_2/weights","shape":[256,4]},{"dtype":"float32","name":"onet/fc2_2/bias","shape":[4]},{"dtype":"float32","name":"onet/fc2_3/weights","shape":[256,10]},{"dtype":"float32","name":"onet/fc2_3/bias","shape":[10]}]}]
|
||||
BIN
js/models/ssd_mobilenetv1_model-shard1
Normal file
BIN
js/models/ssd_mobilenetv1_model-shard1
Normal file
Binary file not shown.
137
js/models/ssd_mobilenetv1_model-shard2
Normal file
137
js/models/ssd_mobilenetv1_model-shard2
Normal file
File diff suppressed because one or more lines are too long
1
js/models/ssd_mobilenetv1_model-weights_manifest.json
Normal file
1
js/models/ssd_mobilenetv1_model-weights_manifest.json
Normal file
File diff suppressed because one or more lines are too long
BIN
js/models/tiny_face_detector_model-shard1
Normal file
BIN
js/models/tiny_face_detector_model-shard1
Normal file
Binary file not shown.
1
js/models/tiny_face_detector_model-weights_manifest.json
Normal file
1
js/models/tiny_face_detector_model-weights_manifest.json
Normal file
@@ -0,0 +1 @@
|
||||
[{"weights":[{"name":"conv0/filters","shape":[3,3,3,16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.009007044399485869,"min":-1.2069439495311063}},{"name":"conv0/bias","shape":[16],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.005263455241334205,"min":-0.9211046672334858}},{"name":"conv1/depthwise_filter","shape":[3,3,16,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.004001977630690033,"min":-0.5042491814669441}},{"name":"conv1/pointwise_filter","shape":[1,1,16,32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.013836609615999109,"min":-1.411334180831909}},{"name":"conv1/bias","shape":[32],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0015159862590771096,"min":-0.30926119685173037}},{"name":"conv2/depthwise_filter","shape":[3,3,32,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002666276225856706,"min":-0.317286870876948}},{"name":"conv2/pointwise_filter","shape":[1,1,32,64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.015265831292844286,"min":-1.6792414422128714}},{"name":"conv2/bias","shape":[64],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0020280554598453,"min":-0.37113414915168985}},{"name":"conv3/depthwise_filter","shape":[3,3,64,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006100742489683862,"min":-0.8907084034938438}},{"name":"conv3/pointwise_filter","shape":[1,1,64,128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.016276211832083907,"min":-2.0508026908425725}},{"name":"conv3/bias","shape":[128],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.003394414279975143,"min":-0.7637432129944072}},{"name":"conv4/depthwise_filter","shape":[3,3,128,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.006716050119961009,"min":-0.8059260143953211}},{"name":"conv4/pointwise_filter","shape":[1,1,128,256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.021875603993733724,"min":-2.8875797271728514}},{"name":"conv4/bias","shape":[256],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.0041141652009066415,"min":-0.8187188749804216}},{"name":"conv5/depthwise_filter","shape":[3,3,256,1],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008423839597141042,"min":-0.9013508368940915}},{"name":"conv5/pointwise_filter","shape":[1,1,256,512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.030007277283014035,"min":-3.8709387695088107}},{"name":"conv5/bias","shape":[512],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.008402082966823203,"min":-1.4871686851277068}},{"name":"conv8/filters","shape":[1,1,512,25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.028336129469030042,"min":-4.675461362389957}},{"name":"conv8/bias","shape":[25],"dtype":"float32","quantization":{"dtype":"uint8","scale":0.002268134028303857,"min":-0.41053225912299807}}],"paths":["tiny_face_detector_model-shard1"]}]
|
||||
@@ -262,6 +262,7 @@ function run_project() {
|
||||
if ((typeof Notification) != "undefined")
|
||||
Notification.requestPermission();
|
||||
isRunning = true
|
||||
$(".facial").attr("hidden", "hidden")
|
||||
try {
|
||||
var logicFunction = Function(globalCode);
|
||||
logicFunction()
|
||||
@@ -287,6 +288,7 @@ function run_project() {
|
||||
|
||||
function stop_project() {
|
||||
isRunning = false
|
||||
$(".facial").removeAttr("hidden")
|
||||
$("#grid").addClass("gridbg")
|
||||
$("#grid").children(".item").removeClass("itemrun")
|
||||
$("#grid").children(".item").draggable({
|
||||
@@ -1348,7 +1350,6 @@ function view_project(projectName, projectType) {
|
||||
cvtName = JSLang[lang].time
|
||||
else if (cvtName == "值")
|
||||
cvtName = JSLang[lang].value
|
||||
console.log(cvtName)
|
||||
tableFields.push({
|
||||
name: cvtName,
|
||||
type: 'text',
|
||||
|
||||
@@ -134,7 +134,7 @@ function showtext(text){
|
||||
});
|
||||
d.showModal();
|
||||
setTimeout(function(){
|
||||
d.close()
|
||||
d.close().remove();
|
||||
},1000)
|
||||
}
|
||||
|
||||
|
||||
229
js/widgets.js
229
js/widgets.js
@@ -5,7 +5,7 @@
|
||||
*/
|
||||
|
||||
tbd = undefined;
|
||||
|
||||
lastFacePublishTime = false;
|
||||
function add_block(width, height, contents, attrs) {
|
||||
var itemdiv = $("<div/>")
|
||||
itemdiv.attr("class", "item")
|
||||
@@ -5937,13 +5937,74 @@ function add_face(user_title, user_topic, user_content, user_style, title_style)
|
||||
cameraDiv.append(video)
|
||||
// floating canvas on top of the video
|
||||
var canvas = $("<canvas style='position:absolute;top:0;left:0'/>")
|
||||
var canvas2 = $("<canvas style='position:absolute;top:0;left:0;display:none'/>")
|
||||
cameraDiv.append(canvas)
|
||||
cameraDiv.append(canvas2)
|
||||
var addFacialDataButton = $('<a class="btn btn-primary facial" style="position:absolute;bottom:10px;right:10px;box-shadow:1px 1px 5px #4e73df"><i class="fa fa-plus"></i> 新增当前人脸数据</a>')
|
||||
contents.push(addFacialDataButton)
|
||||
// stopPropagation
|
||||
addFacialDataButton.bind('mousedown', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
addFacialDataButton.bind('mouseup', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
if (window.screen.width > 800)
|
||||
addFacialDataButton.bind('click', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
else
|
||||
addFacialDataButton.bind('touchend', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
var landmarks = false
|
||||
var isMouthOpen = -1
|
||||
addFacialDataButton.click(function() {
|
||||
if(landmarks)
|
||||
{
|
||||
// 备份当前landmarks
|
||||
var data = []
|
||||
for (var i = 0; i < landmarks.length; i++)
|
||||
{
|
||||
data.push(landmarks[i])
|
||||
}
|
||||
// 获取当前的user-content
|
||||
var user_content = title.parent().parent().attr('user-content')
|
||||
if (user_content == undefined || user_content == "")
|
||||
user_content = "[]"
|
||||
// 读取当前的user-content
|
||||
var user_data = JSON.parse(user_content)
|
||||
user_data.push(data)
|
||||
title.parent().parent().attr('user-content', JSON.stringify(user_data))
|
||||
showtext("人脸数据已保存。ID:" + (user_data.length - 1))
|
||||
}
|
||||
else
|
||||
{
|
||||
showtext("未检测到人脸")
|
||||
}
|
||||
})
|
||||
var removeAllFacialDataButton = $('<a class="btn btn-danger facial" style="position:absolute;bottom:10px;left:10px;box-shadow:1px 1px 5px #e74a3b"><i class="fa fa-trash"></i> 删除所有人脸数据</a>')
|
||||
contents.push(removeAllFacialDataButton)
|
||||
removeAllFacialDataButton.bind('mousedown', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
removeAllFacialDataButton.bind('mouseup', function(event) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
)
|
||||
if (window.screen.width > 800)
|
||||
removeAllFacialDataButton.bind('click', function(event) {
|
||||
event.stopPropagation()
|
||||
})
|
||||
else
|
||||
removeAllFacialDataButton.bind('touchend', function(event) {
|
||||
event.stopPropagation()
|
||||
}
|
||||
)
|
||||
removeAllFacialDataButton.click(function() {
|
||||
title.parent().parent().attr('user-content', "[]")
|
||||
showtext("所有人脸数据已删除")
|
||||
})
|
||||
var ctx = canvas[0].getContext('2d')
|
||||
// 居中显示Loading...
|
||||
|
||||
var ctx2 = canvas2[0].getContext('2d')
|
||||
navigator.mediaDevices.getUserMedia({
|
||||
video: {
|
||||
width: {
|
||||
@@ -5963,76 +6024,92 @@ function add_face(user_title, user_topic, user_content, user_style, title_style)
|
||||
ctx.font = "30px Arial"
|
||||
ctx.fillStyle = "#4e73df"
|
||||
ctx.textAlign = "center"
|
||||
ctx.fillText("Loading...", canvas.width() / 2, canvas.height() / 2)
|
||||
blazeface.load().then(function(model) {
|
||||
// 关闭镜面翻转
|
||||
const returnTensors = false;
|
||||
const flipHorizontal = false;
|
||||
const annotateBoxes = true;
|
||||
var fresh = function(){
|
||||
// if video ready
|
||||
if (video[0].readyState >1 && isAlive) {
|
||||
// video element size, not the video resolution
|
||||
canvas[0].height = cameraDiv.height()
|
||||
canvas[0].width = cameraDiv.width()
|
||||
canvas2[0].height = cameraDiv.height()
|
||||
canvas2[0].width = cameraDiv.width()
|
||||
// 在canvas中居中绘制,缩放到合适大小
|
||||
var scale = Math.min(canvas.width() / video[0].videoWidth, canvas.height() / video[0].videoHeight)
|
||||
var x = (canvas.width() - video[0].videoWidth * scale) / 2
|
||||
var y = (canvas.height() - video[0].videoHeight * scale) / 2
|
||||
ctx2.clearRect(0, 0, canvas2.width(), canvas2.height())
|
||||
ctx2.drawImage(video[0], x, y, video[0].videoWidth * scale, video[0].videoHeight * scale)
|
||||
model.estimateFaces(canvas2[0], returnTensors, flipHorizontal, annotateBoxes).then(predictions => {
|
||||
if (predictions.length > 0) {
|
||||
for (let i = 0; i < predictions.length; i++) {
|
||||
if (returnTensors) {
|
||||
predictions[i].topLeft = predictions[i].topLeft.arraySync();
|
||||
predictions[i].bottomRight = predictions[i].bottomRight.arraySync();
|
||||
if (annotateBoxes) {
|
||||
predictions[i].landmarks = predictions[i].landmarks.arraySync();
|
||||
}
|
||||
}
|
||||
const start = predictions[i].topLeft;
|
||||
const end = predictions[i].bottomRight;
|
||||
const size = [end[0] - start[0], end[1] - start[1]];
|
||||
ctx.clearRect(0, 0, canvas.width, canvas.height);
|
||||
// 四角框,标记人脸位置
|
||||
ctx.fillStyle = 'rgba(255, 255, 255, 0.3)';
|
||||
ctx.fillRect(start[0], start[1], size[0], size[1]);
|
||||
if (annotateBoxes) {
|
||||
const landmarks = predictions[i].landmarks
|
||||
if(isAlive && isRunning){
|
||||
var landmark_dict = {}
|
||||
var landmark_names = ['left_eye', 'right_eye', 'nose', 'mouth', 'left_ear', 'right_ear']
|
||||
for (let j = 0; j < landmarks.length; j++) {
|
||||
const x = landmarks[j][0];
|
||||
const y = landmarks[j][1];
|
||||
const name = landmark_names[j];
|
||||
landmark_dict[name+'_x'] = x
|
||||
landmark_dict[name+'_y'] = y
|
||||
}
|
||||
|
||||
publish(user_topic, JSON.stringify(landmark_dict))
|
||||
}
|
||||
ctx.fillStyle = 'blue';
|
||||
for (let j = 0; j < landmarks.length; j++) {
|
||||
const x = landmarks[j][0];
|
||||
const y = landmarks[j][1];
|
||||
ctx.fillRect(x, y, 5, 5);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}).catch(err => {
|
||||
console.log(err)
|
||||
})
|
||||
}
|
||||
}
|
||||
// wait for the video to be loaded
|
||||
setInterval(fresh, 500)
|
||||
})
|
||||
ctx.fillText("Loading...", 100, 100)
|
||||
Promise.all([
|
||||
faceapi.nets.tinyFaceDetector.loadFromUri('./js/models'),
|
||||
faceapi.nets.faceLandmark68Net.loadFromUri('./js/models'),
|
||||
faceapi.nets.faceRecognitionNet.loadFromUri('./js/models'),
|
||||
faceapi.nets.faceExpressionNet.loadFromUri('./js/models'),
|
||||
]).then(function(){
|
||||
var displaySize = { width: cameraDiv.width(), height: cameraDiv.height() }
|
||||
faceapi.matchDimensions(canvas[0], displaySize)
|
||||
setInterval(async () => {
|
||||
// 识别位置, 脸部特征, 表情
|
||||
// 设置最低置信度 0.4,最多检测一张脸
|
||||
var options = new faceapi.TinyFaceDetectorOptions({ inputSize: 256, scoreThreshold: 0.4 })
|
||||
const detections = await faceapi
|
||||
.detectAllFaces(video[0], options)
|
||||
.withFaceLandmarks()
|
||||
.withFaceExpressions()
|
||||
.withFaceDescriptors()
|
||||
|
||||
// 调整尺寸
|
||||
const resizedDetections = faceapi.resizeResults(detections, displaySize);
|
||||
|
||||
// 如果有人脸, 则保存用以进行人脸匹配的特征向量
|
||||
if(resizedDetections.length > 0)
|
||||
{
|
||||
// 获取RecogntionNet的128维特征向量
|
||||
landmarks = resizedDetections[0].descriptor
|
||||
// 计算嘴是否张开
|
||||
if(resizedDetections[0].expressions.happy > 0.5 || resizedDetections[0].expressions.surprised > 0.5)
|
||||
isMouthOpen = 1
|
||||
else
|
||||
isMouthOpen = 0
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
landmarks = false
|
||||
isMouthOpen = -1
|
||||
}
|
||||
// 尝试匹配user-content中的人脸数据
|
||||
var user_content = title.parent().parent().attr('user-content')
|
||||
if (user_content == undefined || user_content == "")
|
||||
user_content = "[]"
|
||||
var user_data = JSON.parse(user_content)
|
||||
var min_euclidean_distance = 0.4
|
||||
var min_index = -1
|
||||
for (var i = 0; i < user_data.length; i++)
|
||||
{
|
||||
var euclidean_distance = 0
|
||||
for (var j = 0; j < user_data[i].length; j++)
|
||||
{
|
||||
euclidean_distance += Math.pow(user_data[i][j] - landmarks[j], 2)
|
||||
}
|
||||
euclidean_distance = Math.sqrt(euclidean_distance)
|
||||
if(euclidean_distance < min_euclidean_distance)
|
||||
{
|
||||
min_euclidean_distance = euclidean_distance
|
||||
min_index = i
|
||||
}
|
||||
}
|
||||
canvas[0].getContext('2d')?.clearRect(0, 0, canvas[0].width, canvas[0].height); // 清空画布
|
||||
//faceapi.draw.drawDetections(canvas[0], resizedDetections); // 位置
|
||||
faceapi.draw.drawFaceLandmarks(canvas[0], resizedDetections); // 脸部特征
|
||||
faceapi.draw.drawFaceExpressions(canvas[0], resizedDetections); // 表情
|
||||
if(resizedDetections.length > 0)
|
||||
{
|
||||
ctx.font = "30px Arial"
|
||||
ctx.fillStyle = "#ff0000"
|
||||
if(min_index == -1)
|
||||
{
|
||||
const drawBox = new faceapi.draw.DrawBox(resizedDetections[0].detection.box, {"label":"ID:Unknown Mouth: " + (isMouthOpen == 1 ? "Open" : "Close")})
|
||||
drawBox.draw(canvas[0])
|
||||
}
|
||||
else
|
||||
{
|
||||
const drawBox = new faceapi.draw.DrawBox(resizedDetections[0].detection.box, {"label":"ID:" + min_index + " Mouth: " + (isMouthOpen == 1 ? "Open" : "Close")})
|
||||
drawBox.draw(canvas[0])
|
||||
}
|
||||
if(!lastPublishTime || new Date().getTime() - lastFacePublishTime >= 500)
|
||||
{
|
||||
publish(user_topic, JSON.stringify({id: min_index, isMouthOpen: isMouthOpen, face_probability: resizedDetections[0].detection.score, happy_probability: resizedDetections[0].expressions.happy, sad_probability: resizedDetections[0].expressions.sad, angry_probability: resizedDetections[0].expressions.angry, surprised_probability: resizedDetections[0].expressions.surprised, disgusted_probability: resizedDetections[0].expressions.disgusted, fearful_probability: resizedDetections[0].expressions.fearful}))
|
||||
lastFacePublishTime = new Date().getTime()
|
||||
}
|
||||
}
|
||||
}, 100);
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -6079,8 +6156,8 @@ function add_face(user_title, user_topic, user_content, user_style, title_style)
|
||||
if (countSubstr(grid.html(), 'user-title=\"' + title_input.val() + '\"', false) <= (title_input.val() == title.text() ? 1 : 0)) {
|
||||
title.parent().parent().attr('user-title', title_input.val())
|
||||
title.parent().parent().attr('user-topic', topic_input.val())
|
||||
if (title.parent().parent().attr('user-content') == undefined)
|
||||
title.parent().parent().attr('user-content', "")
|
||||
if (title.parent().parent().attr('user-content') == undefined || title.parent().parent().attr('user-content') == "")
|
||||
title.parent().parent().attr('user-content', "[]")
|
||||
title.text(title_input.val())
|
||||
topic.text(topic_input.val())
|
||||
modifyDia.close()
|
||||
|
||||
Reference in New Issue
Block a user