由于项目缘由,须要使用人脸检测(face detection)功能。身为一名前JAVA业务程序员和现前端程序员,这样的功能仍是陌生的领域。那能不能经过搜索和学习能力,加上已有的编程思想,快速实现功能呢?这就是这篇文章的重点,凭借本身的技术与积累,走向本身不熟悉的领域。html
使用PC加摄像头,经过人脸检测,完成自动拍照功能。在PC的屏幕上,显示摄像头的实时画面,要是画面中检测出人脸,则触发拍照。前端
抽其关键点:摄像头,实时画面,人脸检测,和拍照node
项目并无要求开发应用的类型,那么我确定是先从自身拥有的技能出发,看是否能寻求解决方案。身为前端,深知前端技术潜力无限,确定有本身还不知道的技术。果不其然,找到了Tracking.jsgit
Tracking.js是一个颇有意思的库,体积小巧,在浏览器上,直接经过JS提供一些基本的Computer Vison相关的功能,如人脸检测(face detection),颜色识别(color detection),特征识别(feature detection)。关键是,出了对静态图片可以进行识别和处理以外,还可以直接对视频(video)和摄像头(webcam)视屏流进行处理,这就基本给出了人脸识别的方案。程序员
那如何拍照呢?我找到了WebcamJS。可以在浏览器上读取摄像头视频流,调用函数截取某个时刻视频流帧为图片,即视为拍照。github
两个库一结合,就有了初步的解决方案,实现了功能,简单快速。web
在Tracking.js的官网上能够看到,demo的视频尺寸都是很小的,320 * 240,才能有30FPS的处理速度。尺寸若是大了,则识别速度慢,卡顿明显。项目中视频显示大小基本为1080P分辨率屏幕的三分之一,直接处理这个大小的视频,速度确定不够。就算我不直接对大尺寸视频流进行处理,转而对一个隐藏的小尺寸视频流处理,将人脸位置映射到大视频流中,速度上没问题,可是可检测的人脸大小就有限了,即人必须离摄像头比较近才能被检测到。编程
使用的是罗技的1080P的网络摄像头,可是在浏览器上可以看到的,好像并无以1080P的分辨率进行展现。尝试了一些参数的修改,可是结果都不尽人意。浏览器
实时的视频流人脸识别,是很耗CPU的,下图中右边那个蓝色的陡坡就是在我关闭了Tracking.js的demo页面后CPU降低的曲线。服务器
这种状况下,想添加一些传统的网页动效,简直卡出翔来。(关于这点,使用web worker进行人脸检测的工做,应该能有所帮助,可是本身并无往这方面走)
为了寻找上面的问题的解决办法,我了解到了Tracking.js和WebcamJS的运行原理。好比在浏览器上获取摄像头视频流,是经过getUserMedia,是基于WebRTC的支持。
WebcamJS就是经过getuserMedia()
方法,得到摄像头的视频流信息,做为<video>
标签的src
属性,历来可以在网页上进行显示实时画面。经过Canvas
的drawImage()
方法,将video标签传入,便可绘制那个时刻视频帧的图像。(也是经过此次机会我才了解到drawImage()
原来还能够接受HTMLVideoElement
做为参数的)
以前就知道,通常作计算机视觉的,都会用opencv库,这是个C++的库。同时又查到了,有人在node上作了opencv的扩展,而且看到了这个Github项目。因而为了检测效果,本身作了尝试。
经过上面的学习,我已经可以在浏览器段获取摄像头的帧图像,而且知道opencv能作人脸检测。那么此次的方案思路就是:将视频流的帧图像,经过websocket发到后台服务器上,在服务器里使用opencv进行人脸分析,将人脸的坐标发送到前端。
这里后台我并无使用node-opencv,而是使用QT直接作websocket服务器和调用opencv库(仗着本身曾也学过C++,就大胆的直接奔着C++去了)。
可是结果也不理想,缘由以下。
将图片发送给后台,首先想到的是使用Canvas的toDataURL()
方法,将图片转成base64字符串,发给后台。但实测该方法很慢!640 * 480大小的图片,经过toDataURL()
,大体须要50ms时间。
而后考虑使用getImageData(0, 0, 640, 480)
方法,获取图片像素信息,而后转成字符串发到后台。经测,该方法比toDataURL()
确实快很多,大体在5ms左右。可是将它转成JSON字符串,则很慢很慢。
最后查到,toDataURL('image/jpeg')
会加快速度,由于这里不须要计算Alpha通道。实测,小于10ms。
以前有担忧的网络传输耗时问题,却是获得了证明,这个担忧是没有必要的。由于是本地传输,经过websocket传输一张图片(小尺寸或者大尺寸)base64字符串大小的内容,耗时都很小,算下来FPS可以上50。
Approach | CPU % |
---|---|
QT Opencv Face Detection | 30% |
Tracking.js Face Detection | 50% |
Websocket + Opencv | 90% |
不肯定本身在实现上是否哪里出了问题,致使这么高的CPU使用率。但无论怎么,仍是放弃了这个方案。
居然都使用上了QT,就大步向前走好了,毕竟这样的图像处理程序,仍是作桌面应用是作合适的。何况QT体系中的QML语言,可以使用JS,学起来有点像在学一个新的前端MVVM框架,好感度和信心瞬间提高很多。
使用QML作界面,使用Camera和VideoOutput组件进行摄像头视频的实时显示,这里能指定显示分辨率和FPS,很方便;配合使用QVideoFilterRunnable和QAbstractVideoFilter类对帧进行处理,异步返回给主界面人脸检测的结果;opencv和另一个能作人脸识别的C++库Dlib结合使用,可以完成640 * 480尺寸的30FPS处理。
再优化!给每一帧图片进行人脸识别,速度和识别能力均可以提升,就是经过Dlib中提供的Video Object Tracking来完成。一旦对某一帧可以检测到人脸以后,对以后的帧执行该人脸区域图像的tracking。这样作的效果可以得到更高的FPS,同时tracking还能完成更远距离脸部的捕获。
到这里,方案才以为差很少了。
面对项目中本身的未知领域,若是不缺钱,那么直接买商业解决方案。Visage Tech提供的HTML5的人脸识别解决方案(好像用了WebAssembly),简直变态:快速!准确!稳定!核心科技就是和咱们这些小打小闹的不同。
若是不购买商用解决方案,那么应该尽可能找到可以帮助本身的朋友,指条正确的方向可以节省不少调查摸索的时间。好比,若是需求要求程序在拍照时还能控制外接的灯泡,完成闪光灯的效果。那么如何使用软件完成对外部硬件的控制呢?这样的功能对于我这个非计算机专业的而言,真是蒙圈了。最后仍是经历的大半天的摸索,才找到GPIO的解决办法。
提升编程的素养,扩大本身的兴趣面,热爱技术,善于google,逻辑思路清晰,那么在面对不熟悉的领域,新的技术,也可以找到解决方案。而且这个过程能让本身得到很多知识,face detection, object tracking, tracking.js, webcamJS, getUserMedia(), toDataURL()的性能,opencv,dlib,QML,GPIO,树莓派,我还差点去现学了Python。这些东西没有必要都是深究,可是知道他们的存在,会给扩展本身的思路。