Web编程大作业(六)桌面直播+人脸识别+总结(ffmpeg,jsmpeg,jquery.facedetection)
桌面直播
只能算是一个基于ffmpeg和jsmpeg的应用。
首先需要安装的内容有:ffmpeg、jsmpeg、ws模块
安装过程reference:https://my.oschina.net/chengpengvb/blog/1832469 (ffmpeg建议在官网装最新的可执行版本)
直接把下载下来的jsmpeg的代码引入网站后端
var STREAM_SECRET = 'supersecret',
STREAM_PORT = 8081,
WEBSOCKET_PORT = 8082,
RECORD_STREAM = false;
// Websocket Server
var socketServer = new WebSocket.Server({port: WEBSOCKET_PORT, perMessageDeflate: false});
socketServer.connectionCount = 0;
socketServer.on('connection', function(socket, upgradeReq) {
socketServer.connectionCount++;
console.log(
'New WebSocket Connection: ',
(upgradeReq || socket.upgradeReq).socket.remoteAddress,
(upgradeReq || socket.upgradeReq).headers['user-agent'],
'('+socketServer.connectionCount+' total)'
);
socket.on('close', function(code, message){
socketServer.connectionCount--;
console.log(
'Disconnected WebSocket ('+socketServer.connectionCount+' total)'
);
});
});
socketServer.broadcast = function(data) {
socketServer.clients.forEach(function each(client) {
if (client.readyState === WebSocket.OPEN) {
client.send(data);
}
});
};
// HTTP Server to accept incomming MPEG-TS Stream from ffmpeg
var streamServer = http.createServer( function(request, response) {
var params = request.url.substr(1).split('/');
if (params[0] !== STREAM_SECRET) {
console.log(
'Failed Stream Connection: '+ request.socket.remoteAddress + ':' +
request.socket.remotePort + ' - wrong secret.'
);
response.end();
}
response.connection.setTimeout(0);
console.log(
'Stream Connected: ' +
request.socket.remoteAddress + ':' +
request.socket.remotePort
);
request.on('data', function(data){
socketServer.broadcast(data);
if (request.socket.recording) {
request.socket.recording.write(data);
}
});
request.on('end',function(){
console.log('close');
if (request.socket.recording) {
request.socket.recording.close();
}
});
// Record the stream to a local file?
if (RECORD_STREAM) {
var path = 'recordings/' + Date.now() + '.ts';
request.socket.recording = fs.createWriteStream(path);
}
})
// Keep the socket open for streaming
streamServer.headersTimeout = 0;
streamServer.listen(STREAM_PORT);
这段代码大概就是创建了用于接收视频流的服务器和推送视频流的websocket服务器。
把一些需要输入的参数直接给出定值。也就是把接受视频流端口设为8081,把ws服务器端口设为8082,密码设为supersecret。
然后教师端先要安装ffmpeg,通过ffmpeg把桌面视频流推送至8081
推流的ffmpeg命令参数如下:(参数含义基本可以从录制信息里面反推出来,比如分辨率和码率之类的,虽然很多还是不太理解但是能用就行)
ffmpeg -f gdigrab -framerate 30 -i desktop -f mpegts -codec:v mpeg1video -s 2560x1440 -b:v 150k -r 30 -bf 0 -ac 1 -b:a 128k http://127.0.0.1:8081/supersecret
(需要注意将最后的ip地址改为网站所在的ip地址)
学生端通过8082端口获取视频流。(在一个html页面中实现)
<!DOCTYPE html>
<html>
<head>
<title>JSMpeg Stream Client</title>
<style type="text/css">
html, body {
background-color: #111;
text-align: center;
}
.return_index{
color:white;
}
</style>
</head>
<body>
<canvas id="video-canvas"></canvas>
<script type="text/javascript" src="/jsmpeg-master/jsmpeg.min.js"></script>
<script type="text/javascript">
var canvas = document.getElementById('video-canvas');
var url = 'ws://'+window.location.hostname+':8082/';
var player = new JSMpeg.Player(url, {canvas: canvas});
</script>
<a class='return_index' href='/'>返回首页</a>
</body>
</html>
然后把这个页面作为“直播间”做到自己的网站里就算是实现了。
人脸识别
网上绝大多数人脸识别功能的教程都是用OpenCV+python来实现的。找了半天终于发现一个比较简单而且js能用的插件:jquery.facedetection。不过功能确实也相对比较简单。
通过npm install jquery.facedetection就能完成安装。通过script标签引入。
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="node_modules/jquery.facedetection/src/ccv.js"></script>
<script src="node_modules/jquery.facedetection/src/jquery.facedetection.js"></script>
<script src="node_modules/jquery.facedetection/src/cascade.js"></script>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Title</title>
<style type="text/css">
html,body{
margin: 0;
padding:0;
}
.drawDiv{
position: absolute;
border: 3px solid yellow;
}
#image{
float: left;
}
.imgDiv{
float: left;
}
</style>
</head>
<body>
<img id="image" src=""/>
<div class="imgDiv">
<div class="draw"></div>
<br/>
<input type="button" value="开始识别" onclick="identifyFace()">
<input type="file"onchange="selectImage(this);" />
</div>
<a class='return_index' href='/'>返回首页</a>
<script src="https://code.jquery.com/jquery-3.2.1.min.js"></script>
<script src="jquery.facedetection/src/ccv.js"></script>
<script src="jquery.facedetection/src/jquery.facedetection.js"></script>
<script src="jquery.facedetection/src/cascade.js"></script>
<script>
//识别框样式
var str='';
//上传图片,使用文件流
function selectImage(file){
if(!file.files || !file.files[0]){
return;
}
var reader = new FileReader();
reader.onload = function(evt){
console.log(evt);
$('#image').attr('src', evt.target.result);
}
str = '';
document.getElementsByClassName('draw')[0].innerHTML = '';
reader.readAsDataURL(file.files[0]);
}
//开始识别
function identifyFace() {
str='';
$('#image').faceDetection(
function (faces) {
for (var i in faces) {
//识别结果循环传入方法drawFace
console.log(faces[i]);
drawFace(faces[i].x, faces[i].y, faces[i].width, faces[i].height,faces[i].confidence);
}
}
);
}
//图片识别区的x,y轴以及宽高,confidence表示自信程度
function drawFace(x,y,width,height,confidence){
var confidenceStr='';
if(confidence<0){
confidenceStr='自信满满'
}else if(confidence>2){
confidenceStr='很不自信啊'
}else{
confidenceStr='一般般'
}
//将框框套上去
str+='<div class="drawDiv" style="left:'+x+'px;top:'+y+'px;width:'+width+'px;height:'+height+'px;">'+confidenceStr+'</div>'
document.getElementsByClassName('draw')[0].innerHTML=str
}
</script>
</body>
</html>
效果大概是这样
看一下识别后的对象属性
除了“脸部区域”的x坐标、y坐标和长宽这些比较基本的信息之外,比较有意思的是还有一个confidence属性来描述这张脸的自信程度。。然后根据自信程度可以给出一个简单的评价,比如“自信”、“一般般”、“不自信”(这个准确度有多少就不知道啦)
有了这个之后也可以把它做进网站里面,但是很明显这个插件只能检测到图像中“是否有人脸”,但不能识别出“这张脸是谁”,所以离实现“人脸识别签到”这个功能肯定还是有距离的。
另一个问题是如何用js控制树莓派的摄像头模块。同样,网上的博客教程基本都是用python实现的。。用js实现的我也没找到。。于是我只能想到一个笨办法,就是让树莓派摄像头定时拍摄,将图片存到一个指定的地址,让网页读取固定地址的图片进行识别。
raspistill在终端控制摄像头 2秒拍摄一次(时间设置一个很大的数,让它一直拍)
raspistill -o Web_v5/public/images/now.jpg -tl 2000 -t 9999999999
然而这个最后实现的效果。。有点一言难尽。首先是树莓派拍出来照片大小的问题,一张照片大概2-3M,做一次识别要花很长时间,其次虽然照片占的空间很大,但是清晰度又很差,导致很难识别出人脸(这个可能是因为没有把摄像头固定起来导致的)。最后摄像头稍微拍了一分多钟就有点开始发烫了。。应该是我让它拍的太频繁的问题。
总之这个功能实现的比较失败吧。。以后真的要做人脸识别类似的功能可能还是用OpenCV+python之类的比较好,回头研究了。。
总结
以上就是这个项目的全部内容。。之前总结的比较多,后面做的这些感觉也没啥好总结的。。
前半部分从无到有,自己用express和angular写框架和前后端交互的时候花的力气比较多,应该收获也是比较大的。最后做的几个要求比如视频推流和人脸识别这些就稍显敷衍,毕竟以前也没有接触过,主要就是想把这些功能都尝试一下。
一个感觉就是,整个项目做下来之后在计算机网络方面的知识确实是学到很多,但是好像对于javascript代码本身还是掌握的比较差,比方说如果拿到一个新的模块,基本上只能通过别人的代码来了解具体的用法、写法,很难通过官方文档来直接理解并构建代码。。(说白了就是只能做做增删改查,但是对底层原理一头雾水吧)