基于HTML5 的人脸识别活体认证的实现方法

(编辑:jimmy 日期: 2024/11/13 浏览:2)

近几年,人脸识别技术在身份认证领域的应用已经有了较多应用,例如:支付宝、招行的取款、养老金领取等方面,但在杜绝假冒、认证安全性等方面,目前还是一个比较需要进一步解决的课题,特别是在移动端的活体认证技术方面。

本文介绍了在HTML5 环境下可以采用clmtrackr.js 检测工具,结合人脸模型,实现人脸的跟踪检测。同时采用动作识别实现活体认证。

但本方案只能够在Firefox 或者Chrome中使用。并且只适合研究学习,实际场景中不太理想,需要进一步优化才能够应用。

如果有人有相关的技术,可以推荐介绍给我。

JavaScript Code复制内容到剪贴板
  1. <!DOCTYPE html>  
  2. <!--  
  3. Ideally these elements aren't created until it's confirmed that the   
  4. client supports video/camera, but for the sake of illustrating the   
  5. elements involved, they are created with markup (not JavaScript)  
  6. -->  
  7. <html>  
  8. <meta charset="GBK">  
  9. <style>  
  10. #container {  
  11. position : relative;  
  12. }  
  13.  
  14. #canvas {  
  15. position : absolute;  
  16. left : 0;  
  17. top : 0;  
  18. }  
  19. </style>  
  20. <script src="utils.js"></script>  
  21. <script src="clmtrackr.js"></script>  
  22. <script src="./models/model_pca_20_svm.js"></script>  
  23. <script src="numeric.js"></script>  
  24. <script src="ccv.js"></script>  
  25.   
  26. <audio id="media">   
  27. 你的浏览器不支持audio标签。  
  28. </audio>  
  29. <div id="container">  
  30. <video id="video" width="600" height="400" autoplay >   
  31. 您的浏览器不支持video标签  
  32. </video>  
  33. <canvas id="canvas" width="600" height="400"></canvas>  
  34. </div>      
  35.   
  36. <button id="snap">Snap Photo</button>  
  37.   
  38. <button id="start">Start</button>  
  39.   
  40. <button id="showposition">显示</button>  
  41.   
  42. <button id="hideposition">不显示</button>  
  43.   
  44. <br/>  
  45.   
  46. <button id="mouse">张嘴验证</button>   
  47. <button id="head">摇头验证</button>   
  48. <button id="eye">眨眼验证</button>  
  49.   
  50.   
  51. <div id="tip">  
  52. </div>  
  53. <div id="result">  
  54. </div>  
  55. <div id="msg">  
  56. </div>  
  57.   
  58. <div id="positions">  
  59. </div>  
  60.   
  61. <script>  
  62.   
  63. var showpos=false;  
  64. // Put event listeners into place  
  65. //window.addEventListener("DOMContentLoaded", function() {  
  66.   
  67. // Grab elements, create settings, etc.  
  68. var canvas = document.getElementById("canvas"),  
  69. context = canvas.getContext("2d"),  
  70. video = document.getElementById("video"),  
  71. videoObj = { "video": true },  
  72. errBack = function(error) {  
  73. if (error.PERMISSION_DENIED) {  
  74. jAlert('用户拒绝了浏览器请求媒体的权限', '提示');  
  75. } else if (error.NOT_SUPPORTED_ERROR) {  
  76. jAlert('对不起,您的浏览器不支持拍照功能,请使用其他浏览器', '提示');  
  77. } else if (error.MANDATORY_UNSATISFIED_ERROR) {  
  78. jAlert('指定的媒体类型未接收到媒体流', '提示');  
  79. } else {  
  80. jAlert('系统未能获取到摄像头,请确保摄像头已正确安装。或尝试刷新页面,重试', '提示');  
  81. }  
  82. };  
  83.   
  84. // Put video listeners into place  
  85. if(navigator.getUserMedia) { // Standard  
  86.   
  87. navigator.getUserMedia(videoObj, function(stream) {  
  88.   
  89. video.src = stream;  
  90. video.play();  
  91.   
  92. }, errBack);  
  93.   
  94. } else if(navigator.webkitGetUserMedia) { // WebKit-prefixed  
  95.   
  96. try{  
  97.   
  98. navigator.webkitGetUserMedia(videoObj, function(stream){   
  99. video.src = window.webkitURL.createObjectURL(stream);  
  100. video.play();  
  101. }, errBack);  
  102.   
  103. }catch(error){  
  104. alert(error);  
  105. }  
  106.   
  107. }  
  108. else if(navigator.mozGetUserMedia) { // Firefox-prefixed  
  109. navigator.mozGetUserMedia(videoObj, function(stream){  
  110.   
  111. video.src = window.URL.createObjectURL(stream);  
  112. video.play();  
  113. }, errBack);  
  114. }  
  115.   
  116.   
  117.   
  118. // Trigger photo take  
  119. document.getElementById("snap").addEventListener("click", function() {  
  120. context.drawImage(video, 0, 0, 600, 400);  
  121. });  
  122. document.getElementById("start").addEventListener("click", function() {  
  123. startTrack();  
  124. });  
  125.   
  126.   
  127. document.getElementById("showposition").addEventListener("click", function() {  
  128. showpos=true;  
  129. });  
  130.   
  131. document.getElementById("hideposition").addEventListener("click", function() {  
  132. showpos=false;  
  133. });  
  134.   
  135. document.getElementById("mouse").addEventListener("click", function() {  
  136. alive_mouse();  
  137. });  
  138. document.getElementById("head").addEventListener("click", function() {  
  139. alive_head();  
  140. });  
  141.   
  142. document.getElementById("eye").addEventListener("click", function() {  
  143. alive_eye();  
  144. });  
  145.   
  146.   
  147.   
  148.   
  149. //}, false);  
  150.   
  151.   
  152. </script>  
  153.   
  154. <script>  
  155.   
  156. //////////////////////////////////////////////////////////////////////////////  
  157. //活体  
  158. var last_time=0;//时间因素  
  159. var last_nose_left=0;  
  160. var last_nose_top=0;  
  161.   
  162. //张嘴动作  
  163. var is_mouse_ok=false;   
  164. var is_alive_mouse=false;  
  165. var last_dis_eye_norse=0;  
  166. var last_dis_mouse=0;  
  167. function alive_mouse(){  
  168.   
  169. var media = document.getElementById("media");  
  170. media.src="mp3/alive_mouse.mp3";  
  171. media.play();  
  172.   
  173. document.getElementById("tip").innerHTML="请张合嘴巴";  
  174. document.getElementById('result').innerHTML = "";  
  175.   
  176. is_mouse_ok=false;  
  177. last_dis_mouse=0;  
  178. last_time=0;  
  179. last_dis_eye_norse=100000000;   
  180.   
  181. is_alive_head=false;  
  182. is_alive_mouse=true;  
  183. is_alive_eye=false;  
  184.   
  185. }  
  186. //摇头动作  
  187. var is_head_ok=false;   
  188. var is_alive_head=false;  
  189. var last_dis_left_right=100000000;   
  190. function alive_head(){  
  191.   
  192. var media = document.getElementById("media");  
  193. media.src="mp3/alive_head.mp3";  
  194. media.play();  
  195.   
  196. document.getElementById("tip").innerHTML="请在水平方向左右摇头";  
  197. document.getElementById('result').innerHTML = "";  
  198.   
  199. is_head_ok=false;  
  200. last_dis_left_right=100000000;   
  201. last_time=0;   
  202. is_alive_head=true;  
  203. is_alive_mouse=false;  
  204. is_alive_eye=false;  
  205.   
  206. }  
  207.   
  208. //眨眼动作  
  209. var is_alive_eye=false;  
  210. var is_eye_ok = false;  
  211.   
  212. function alive_eye(){  
  213. var media = document.getElementById("media");  
  214. media.src="mp3/alive_eye.mp3";  
  215. media.play();  
  216.   
  217. document.getElementById("tip").innerHTML="请眨眼";  
  218. document.getElementById('result').innerHTML = "";  
  219.   
  220. is_eye_ok=false;  
  221. last_dis_eye_norse=100000000;   
  222.   
  223. last_nose_left=0;  
  224. last_nose_top=0;  
  225.   
  226. last_time=0;   
  227.   
  228. is_alive_head=false;  
  229. is_alive_mouse=false;  
  230. is_alive_eye=true;  
  231. }  
  232.   
  233.   
  234. function startTrack(){  
  235.   
  236. var videoInput = document.getElementById('video');  
  237.   
  238. var ctracker = new clm.tracker();  
  239. ctracker.init(pModel);  
  240. ctracker.start(videoInput);  
  241.   
  242.   
  243. var canvasInput = document.getElementById('canvas');  
  244. var cc = canvasInput.getContext('2d');  
  245. cc.lineWidth=3;  
  246.   
  247. function drawLoop() {  
  248. //requestAnimationFrame(drawLoop);  
  249.   
  250.   
  251. cc.clearRect(0, 0, canvasInput.width, canvasInput.height);  
  252. //ctracker.draw(canvasInput );  
  253. var positions = ctracker.getCurrentPosition();  
  254. if (showpos && positions) {  
  255.   
  256. for (var p = 0;p < positions.length;p++) {  
  257. positionString += "featurepoint "+p+" : ["+positions[p][0].toFixed(2)+","+positions[p][1].toFixed(2) +"]<br/>";  
  258. }  
  259. document.getElementById('positions').innerHTML = positionString;  
  260.   
  261.   
  262. }  
  263. if(positions){  
  264.   
  265. for (var p =0;p < 71;p++) {      
  266. cc.beginPath();  
  267. cc.arc(positions[p][0].toFixed(2), positions[p][1].toFixed(2),2, 0, Math.PI * 2, true);  
  268. cc.closePath();  
  269. cc.fillStyle = '#00FF00';  
  270. cc.fill();  
  271. }  
  272.   
  273.   
  274. //cc.strokeStyle = 'red';  
  275.   
  276. //0-14 轮廓  
  277. //7 下吧,最下  
  278.   
  279. //2 最左边  
  280. //12 最右边  
  281.   
  282.   
  283. //15-22 眉毛  
  284.   
  285.   
  286. //23-27 左眼睛五个点  
  287. //27 左眼中间  
  288. //63-66 左眼四个点  
  289.   
  290. //28-32 右眼睛五个点  
  291. //67-70 右眼四个点  
  292.   
  293.   
  294. //33-43 鼻子  
  295. //62 鼻中间  
  296.   
  297.   
  298. //44-61 嘴巴  
  299. //47 嘴巴上  
  300. //53 嘴巴下  
  301.   
  302. ///////////////////////////////////////////////////////////////////////////////////////////////  
  303.   
  304. //左眼中间  
  305. for (var p =27;p <=27;p++) {      
  306. cc.beginPath();  
  307. cc.arc(positions[p][0].toFixed(2), positions[p][1].toFixed(2), 2, 0, Math.PI * 2, true);  
  308. cc.closePath();  
  309. cc.fillStyle = 'red';  
  310. cc.fill();  
  311. }  
  312.   
  313. //鼻子中间  
  314. for (var p =62;p <=62;p++) {      
  315. cc.beginPath();  
  316. cc.arc(positions[p][0].toFixed(2), positions[p][1].toFixed(2), 2, 0, Math.PI * 2, true);  
  317. cc.closePath();  
  318. cc.fillStyle = 'red';  
  319. cc.fill();  
  320. }  
  321. //嘴巴上  
  322. for (var p =57;p <=57;p++) {      
  323. cc.beginPath();  
  324. cc.arc(positions[p][0].toFixed(2), positions[p][1].toFixed(2), 2, 0, Math.PI * 2, true);  
  325. cc.closePath();  
  326. cc.fillStyle = 'red';  
  327. cc.fill();  
  328. }  
  329. //嘴巴下  
  330. for (var p =60;p <=60;p++) {      
  331. cc.beginPath();  
  332. cc.arc(positions[p][0].toFixed(2), positions[p][1].toFixed(2), 2, 0, Math.PI * 2, true);  
  333. cc.closePath();  
  334. cc.fillStyle = 'red';  
  335. cc.fill();  
  336. }  
  337. //////////////////////////////////////  
  338. //head  
  339. if(is_alive_head==true){  
  340. if(last_time==0 || (new Date().getTime()-last_time>500 && new Date().getTime()-last_time<10000 ) ){  
  341. var xdiff_left = positions[62][0] - positions[2][0] ;  
  342. var ydiff_left = positions[62][1] - positions[2][1] ;  
  343. var dis_left = Math.pow((xdiff_left * xdiff_left + ydiff_left * ydiff_left), 0.5);  
  344.   
  345. var xdiff_right = positions[12][0] - positions[62][0] ;  
  346. var ydiff_right = positions[12][1] - positions[62][1] ;  
  347. var dis_right = Math.pow((xdiff_right * xdiff_right + ydiff_right * ydiff_right), 0.5);  
  348.   
  349. var xdiff_side = positions[12][0] - positions[2][0] ;  
  350. var ydiff_side = positions[12][1] - positions[2][1] ;  
  351. var dis_side = Math.pow((xdiff_side * xdiff_side + ydiff_side * ydiff_side), 0.5);  
  352.   
  353.   
  354. var dis_left_right = dis_left - dis_right;  
  355. document.getElementById('result').innerHTML = dis_left_right;  
  356.   
  357.   
  358. if(last_dis_left_right>0 && dis_left_right > dis_side/3){  
  359.   
  360. document.getElementById('result').innerHTML = "通过";  
  361.   
  362. is_head_ok=true;  
  363. is_alive_head=false;  
  364.   
  365. }  
  366.   
  367.   
  368.   
  369. last_dis_left_right=dis_left_right;   
  370. last_time = new Date().getTime();  
  371.   
  372. }  
  373. }  
  374.   
  375. /////////////////////////////////////  
  376. //mouse   
  377. if(is_alive_mouse==true){  
  378. if(last_time==0 || (new Date().getTime()-last_time>500 && new Date().getTime()-last_time<10000 ) ){  
  379.   
  380. //研究和鼻子距离  
  381. var xdiff = positions[62][0] - positions[27][0] ;  
  382. var ydiff = positions[62][1] - positions[27][1] ;   
  383. var dis_eye_norse = Math.pow((xdiff * xdiff + ydiff * ydiff), 0.5);  
  384.   
  385. //上嘴唇 和下嘴唇距离  
  386. var xdiff_mouse = positions[53][0] - positions[47][0] ;  
  387. var ydiff_mouse = positions[53][1] - positions[47][1] ;   
  388. var dis_mouse = Math.pow((xdiff_mouse * xdiff_mouse + ydiff_mouse * ydiff_mouse), 0.5);  
  389.   
  390. //上次的眼鼻距离和这次的眼鼻距离差  
  391. var dn= Math.abs(dis_eye_norse-last_dis_eye_norse);  
  392.   
  393. //上次的嘴距离和本次的嘴距离差  
  394. var dm=Math.abs(dis_mouse - last_dis_mouse);  
  395.   
  396.   
  397.   
  398.   
  399. //鼻子的位置确保变化不大  
  400. if(last_nose_left>0 && last_nose_top>0  
  401. && Math.abs(positions[62][0]-last_nose_left)<5  
  402. && Math.abs(positions[62][1]-last_nose_top)<5  
  403. ){  
  404.   
  405. document.getElementById('msg').innerHTML = dn;  
  406.   
  407. if(last_dis_eye_norse>0 && dn < dis_eye_norse*1/50){   
  408.   
  409. if(last_dis_mouse>0 && dm > dis_mouse/10){  
  410.   
  411. document.getElementById('result').innerHTML = "通过";  
  412.   
  413. is_alive_mouse=false;  
  414. is_mouse_ok=true;  
  415. }  
  416.   
  417. }  
  418. }  
  419.   
  420.   
  421. last_dis_mouse = dis_mouse;  
  422. last_dis_eye_norse = dis_eye_norse;  
  423. last_time = new Date().getTime();   
  424.   
  425. last_nose_left = positions[62][0];  
  426. last_nose_top = positions[62][1];  
  427.   
  428. }  
  429. }  
  430.   
  431. /////////////////////////////////////  
  432. //eye   
  433. if(is_alive_eye==true){  
  434. if(last_time==0 || (new Date().getTime()-last_time>10 ) ){  
  435.   
  436.   
  437. var xdiff1 = positions[62][0] - positions[27][0] ;  
  438. var ydiff1 = positions[62][1] - positions[27][1] ;   
  439. var dis_eye_norse1 = Math.pow((xdiff1 * xdiff1 + ydiff1 * ydiff1), 0.5);  
  440.   
  441. var xdiff2 = positions[62][0] - positions[32][0] ;  
  442. var ydiff2 = positions[62][1] - positions[32][1] ;   
  443. var dis_eye_norse2 = Math.pow((xdiff2 * xdiff2 + ydiff2 * ydiff2), 0.5);  
  444.   
  445. var dis_eye_norse = (dis_eye_norse1 + dis_eye_norse2);  
  446.   
  447.   
  448.   
  449. if(last_nose_left>0 && last_nose_top>0  
  450. && Math.abs(positions[62][0]-last_nose_left)<0.5  
  451. && Math.abs(positions[62][1]-last_nose_top)<0.5  
  452. ){  
  453. document.getElementById('msg').innerHTML = Math.abs(dis_eye_norse - last_dis_eye_norse) - dis_eye_norse*1/20;  
  454.   
  455. if(last_dis_eye_norse>0 && (Math.abs(dis_eye_norse - last_dis_eye_norse) > dis_eye_norse*1/20 ) ){  
  456.   
  457. document.getElementById('result').innerHTML = "通过";  
  458.   
  459. is_alive_eye=false;  
  460. is_eye_ok=true;  
  461.   
  462. }  
  463. }  
  464.   
  465.   
  466. last_nose_left = positions[62][0];  
  467. last_nose_top = positions[62][1];  
  468.   
  469. last_dis_eye_norse = dis_eye_norse;  
  470. last_time = new Date().getTime();   
  471.   
  472. }  
  473.   
  474.   
  475. }  
  476.   
  477.   
  478. }  
  479.   
  480. requestAnimationFrame(drawLoop);  
  481.   
  482. }  
  483.   
  484. drawLoop();  
  485.   
  486. }  
  487.   
  488.    
  489.   
  490. </script>  
  491. </html>  

以上就是小编为大家带来的基于HTML5 的人脸识别活体认证的实现方法全部内容了,希望大家多多支持~

原文地址:http://www.cnblogs.com/lilies/archive/2016/06/21/5604212.html