face_alignment_webcam.html 9.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. <!doctype html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>tracking.js - face alignment with camera</title>
  6. <!-- here is the frame around each example - to be removed - to a fullscreen video - working on mobile too -->
  7. <!-- <link rel="stylesheet" href="assets/demo.css"> -->
  8. <script src="../build/tracking.js"></script>
  9. <script src="../build/data/face-min.js"></script>
  10. <script src="../src/alignment/training/Landmarks.js"></script>
  11. <script src="../src/alignment/training/Regressor.js"></script>
  12. <script src="../node_modules/dat.gui/build/dat.gui.min.js"></script>
  13. </head>
  14. <body>
  15. <style>
  16. #videoWebcam {
  17. position: absolute;
  18. top: 0px;
  19. left: 0px;
  20. width : 320px;
  21. height: auto;
  22. zoom: 3;
  23. }
  24. #canvasDetection {
  25. position: absolute;
  26. top: 0px;
  27. left: 0px;
  28. width : 320px;
  29. height: auto;
  30. zoom: 3;
  31. }
  32. </style>
  33. <video id="videoWebcam" width="368" height="288" autoplay loop>
  34. <source src="./assets/franck.mp4" type="video/mp4"/>
  35. <source src="./assets/franck.ogv" type="video/ogg"/>
  36. </video>
  37. <!-- <video id="videoWebcam" preload autoplay loop muted></video> -->
  38. <canvas id="canvasDetection"></canvas>
  39. <script>
  40. var canvasDetection = document.querySelector('#canvasDetection');
  41. canvasDetection.width = 320
  42. canvasDetection.height = 240
  43. var context = canvasDetection.getContext('2d');
  44. // tracking.LBF.maxNumStages = 10
  45. var tracker = new tracking.LandmarksTracker();
  46. tracker.setEdgesDensity(0.1);
  47. tracker.setInitialScale(4);
  48. tracker.setStepSize(2);
  49. tracker.setInitialScale(2);
  50. tracker.setStepSize(1);
  51. var gui = new dat.GUI();
  52. gui.add(tracker, 'edgesDensity', 0.1, 0.5).step(0.01).listen();
  53. gui.add(tracker, 'initialScale', 1.0, 10.0).step(0.1).listen();
  54. gui.add(tracker, 'stepSize', 0.5, 5).step(0.1).listen();
  55. var videoElement = document.querySelector('#videoWebcam')
  56. tracking.track(videoElement, tracker);
  57. // tracking.track(videoElement, tracker, { camera: true });
  58. var landmarksPerFace = 30
  59. var landmarkFeatures = {
  60. jaw : {
  61. first: 0,
  62. last: 8,
  63. fillStyle: 'white',
  64. closed: false,
  65. },
  66. nose : {
  67. first:15,
  68. last: 18,
  69. fillStyle: 'green',
  70. closed: true,
  71. },
  72. mouth : {
  73. first:27,
  74. last: 30,
  75. fillStyle: 'red',
  76. closed: true,
  77. },
  78. eyeL : {
  79. first:19,
  80. last: 22,
  81. fillStyle: 'purple',
  82. closed: false,
  83. },
  84. eyeR : {
  85. first:23,
  86. last: 26,
  87. fillStyle: 'purple',
  88. closed: false,
  89. },
  90. eyeBrowL : {
  91. first: 9,
  92. last: 11,
  93. fillStyle: 'yellow',
  94. closed: false,
  95. },
  96. eyeBrowR : {
  97. first:12,
  98. last: 14,
  99. fillStyle: 'yellow',
  100. closed: false,
  101. },
  102. }
  103. //////////////////////////////////////////////////////////////////////////////
  104. // Code Separator
  105. //////////////////////////////////////////////////////////////////////////////
  106. var parameters = {
  107. landmarkLerpFactor : 0.7,
  108. boundinBoxVisible : true,
  109. jawVisible : true,
  110. eyeBrowLVisible : true,
  111. eyeBrowRVisible : true,
  112. noseVisible : true,
  113. eyeLVisible : true,
  114. eyeRVisible : true,
  115. mouthVisible : true,
  116. }
  117. gui.add(parameters, 'landmarkLerpFactor', 0.0, 1).listen().name('Landmarks Lerp');
  118. gui.add(parameters, 'boundinBoxVisible', 0.0, 1).listen().name('bounding box');
  119. Object.keys(landmarkFeatures).forEach(function(featureLabel){
  120. gui.add(parameters, featureLabel + 'Visible').listen().name(featureLabel);
  121. })
  122. var lerpedFacesLandmarks = []
  123. tracker.on('track', function(event) {
  124. // clear debug canvasDetection
  125. context.clearRect(0,0,canvasDetection.width, canvasDetection.height);
  126. if( event.data === undefined ) return;
  127. event.data.faces.forEach(function(boundingBox, faceIndex) {
  128. var faceLandmarks = event.data.landmarks[faceIndex]
  129. if( parameters.boundinBoxVisible === true ) displayFaceLandmarksBoundingBox(boundingBox, faceIndex)
  130. // lerpFacesLandmarks
  131. lerpFacesLandmarks(faceLandmarks)
  132. // display each faceLandmarks
  133. displayFaceLandmarksDot(lerpedFacesLandmarks)
  134. });
  135. })
  136. function lerpFacesLandmarks(newFaceLandmarks){
  137. // init lerpFacesLandmarks if needed
  138. for(var i = 0; i < newFaceLandmarks.length; i++){
  139. if( lerpedFacesLandmarks[i] !== undefined ) continue
  140. lerpedFacesLandmarks[i] = [
  141. newFaceLandmarks[i][0],
  142. newFaceLandmarks[i][1],
  143. ]
  144. }
  145. // init lerpFacesLandmarks if needed
  146. for(var i = 0; i < newFaceLandmarks.length; i++){
  147. var lerpFactor = parameters.landmarkLerpFactor
  148. lerpedFacesLandmarks[i][0] = newFaceLandmarks[i][0] * lerpFactor + lerpedFacesLandmarks[i][0] * (1-lerpFactor)
  149. lerpedFacesLandmarks[i][1] = newFaceLandmarks[i][1] * lerpFactor + lerpedFacesLandmarks[i][1] * (1-lerpFactor)
  150. }
  151. }
  152. //////////////////////////////////////////////////////////////////////////////
  153. // Code Separator
  154. //////////////////////////////////////////////////////////////////////////////
  155. function displayFaceLandmarksBoundingBox(boundingBox, faceIndex){
  156. // display the box
  157. context.strokeStyle = '#a64ceb';
  158. context.strokeRect(boundingBox.x, boundingBox.y, boundingBox.width, boundingBox.height);
  159. // display the size of the box
  160. context.font = '11px Helvetica';
  161. context.fillStyle = "#fff";
  162. context.fillText('idx: '+faceIndex, boundingBox.x + boundingBox.width + 5, boundingBox.y + 11);
  163. context.fillText('x: ' + boundingBox.x + 'px', boundingBox.x + boundingBox.width + 5, boundingBox.y + 22);
  164. context.fillText('y: ' + boundingBox.y + 'px', boundingBox.x + boundingBox.width + 5, boundingBox.y + 33);
  165. }
  166. function displayFaceLandmarksDot(faceLandmarks){
  167. Object.keys(landmarkFeatures).forEach(function(featureLabel){
  168. if( parameters[featureLabel+'Visible'] === false ) return
  169. displayFaceLandmarksFeature(faceLandmarks, featureLabel)
  170. })
  171. }
  172. function displayFaceLandmarksFeature(faceLandmarks, featureLabel){
  173. var feature = landmarkFeatures[featureLabel]
  174. // draw dots
  175. context.fillStyle = feature.fillStyle
  176. for(var i = feature.first; i <= feature.last; i++){
  177. var xy = faceLandmarks[i]
  178. context.beginPath();
  179. context.arc(xy[0],xy[1],1,0,2*Math.PI);
  180. context.fill();
  181. }
  182. // draw lines
  183. var feature = landmarkFeatures[featureLabel]
  184. context.strokeStyle = feature.fillStyle
  185. context.beginPath();
  186. for(var i = feature.first; i <= feature.last; i++){
  187. var x = faceLandmarks[i][0]
  188. var y = faceLandmarks[i][1]
  189. if( i === 0 ){
  190. context.moveTo(x, y)
  191. }else{
  192. context.lineTo(x, y)
  193. }
  194. }
  195. if( feature.closed === true ){
  196. var x = faceLandmarks[feature.first][0]
  197. var y = faceLandmarks[feature.first][1]
  198. context.lineTo(x, y)
  199. }
  200. context.stroke();
  201. }
  202. </script></body>