js_camshift.html 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>CamShift Example</title>
  6. <link href="js_example_style.css" rel="stylesheet" type="text/css" />
  7. </head>
  8. <body>
  9. <h2>CamShift Example</h2>
  10. <p>
  11. Click <b>Start/Stop</b> button to start or stop the video.<br>
  12. The <b>videoInput</b> is a &lt;video&gt; element used as CamShift input.
  13. The <b>canvasOutput</b> is a &lt;canvas&gt; element used as CamShift output.<br>
  14. The code of &lt;textarea&gt; will be executed when video is started.
  15. You can modify the code to investigate more.
  16. </p>
  17. <div>
  18. <div class="control"><button id="startAndStop" disabled>Start</button></div>
  19. <textarea class="code" rows="29" cols="100" id="codeEditor" spellcheck="false">
  20. </textarea>
  21. </div>
  22. <p class="err" id="errorMessage"></p>
  23. <div>
  24. <table cellpadding="0" cellspacing="0" width="0" border="0">
  25. <tr>
  26. <td>
  27. <video id="videoInput" width="320" height="240" muted loop></video>
  28. </td>
  29. <td>
  30. <canvas id="canvasOutput" width="320" height="240"></canvas>
  31. </td>
  32. <td></td>
  33. <td></td>
  34. </tr>
  35. <tr>
  36. <td>
  37. <div class="caption">videoInput</div>
  38. </td>
  39. <td>
  40. <div class="caption">canvasOutput</div>
  41. </td>
  42. <td></td>
  43. <td></td>
  44. </tr>
  45. </table>
  46. </div>
  47. <script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
  48. <script src="utils.js" type="text/javascript"></script>
  49. <script id="codeSnippet" type="text/code-snippet">
  50. let video = document.getElementById('videoInput');
  51. let cap = new cv.VideoCapture(video);
  52. // take first frame of the video
  53. let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4);
  54. cap.read(frame);
  55. // hardcode the initial location of window
  56. let trackWindow = new cv.Rect(150, 60, 63, 125);
  57. // set up the ROI for tracking
  58. let roi = frame.roi(trackWindow);
  59. let hsvRoi = new cv.Mat();
  60. cv.cvtColor(roi, hsvRoi, cv.COLOR_RGBA2RGB);
  61. cv.cvtColor(hsvRoi, hsvRoi, cv.COLOR_RGB2HSV);
  62. let mask = new cv.Mat();
  63. let lowScalar = new cv.Scalar(30, 30, 0);
  64. let highScalar = new cv.Scalar(180, 180, 180);
  65. let low = new cv.Mat(hsvRoi.rows, hsvRoi.cols, hsvRoi.type(), lowScalar);
  66. let high = new cv.Mat(hsvRoi.rows, hsvRoi.cols, hsvRoi.type(), highScalar);
  67. cv.inRange(hsvRoi, low, high, mask);
  68. let roiHist = new cv.Mat();
  69. let hsvRoiVec = new cv.MatVector();
  70. hsvRoiVec.push_back(hsvRoi);
  71. cv.calcHist(hsvRoiVec, [0], mask, roiHist, [180], [0, 180]);
  72. cv.normalize(roiHist, roiHist, 0, 255, cv.NORM_MINMAX);
  73. // delete useless mats.
  74. roi.delete(); hsvRoi.delete(); mask.delete(); low.delete(); high.delete(); hsvRoiVec.delete();
  75. // Setup the termination criteria, either 10 iteration or move by at least 1 pt
  76. let termCrit = new cv.TermCriteria(cv.TERM_CRITERIA_EPS | cv.TERM_CRITERIA_COUNT, 10, 1);
  77. let hsv = new cv.Mat(video.height, video.width, cv.CV_8UC3);
  78. let hsvVec = new cv.MatVector();
  79. hsvVec.push_back(hsv);
  80. let dst = new cv.Mat();
  81. let trackBox = null;
  82. const FPS = 30;
  83. function processVideo() {
  84. try {
  85. if (!streaming) {
  86. // clean and stop.
  87. frame.delete(); dst.delete(); hsvVec.delete(); roiHist.delete(); hsv.delete();
  88. return;
  89. }
  90. let begin = Date.now();
  91. // start processing.
  92. cap.read(frame);
  93. cv.cvtColor(frame, hsv, cv.COLOR_RGBA2RGB);
  94. cv.cvtColor(hsv, hsv, cv.COLOR_RGB2HSV);
  95. cv.calcBackProject(hsvVec, [0], roiHist, dst, [0, 180], 1);
  96. // apply camshift to get the new location
  97. [trackBox, trackWindow] = cv.CamShift(dst, trackWindow, termCrit);
  98. // Draw it on image
  99. let pts = cv.rotatedRectPoints(trackBox);
  100. cv.line(frame, pts[0], pts[1], [255, 0, 0, 255], 3);
  101. cv.line(frame, pts[1], pts[2], [255, 0, 0, 255], 3);
  102. cv.line(frame, pts[2], pts[3], [255, 0, 0, 255], 3);
  103. cv.line(frame, pts[3], pts[0], [255, 0, 0, 255], 3);
  104. cv.imshow('canvasOutput', frame);
  105. // schedule the next one.
  106. let delay = 1000/FPS - (Date.now() - begin);
  107. setTimeout(processVideo, delay);
  108. } catch (err) {
  109. utils.printError(err);
  110. }
  111. };
  112. // schedule the first one.
  113. setTimeout(processVideo, 0);
  114. </script>
  115. <script type="text/javascript">
  116. let utils = new Utils('errorMessage');
  117. utils.loadCode('codeSnippet', 'codeEditor');
  118. let streaming = false;
  119. let videoInput = document.getElementById('videoInput');
  120. let startAndStop = document.getElementById('startAndStop');
  121. let canvasOutput = document.getElementById('canvasOutput');
  122. let canvasContext = canvasOutput.getContext('2d');
  123. startAndStop.addEventListener('click', () => {
  124. if (!streaming) {
  125. utils.clearError();
  126. videoInput.play().then(() => {
  127. onVideoStarted();
  128. });
  129. } else {
  130. videoInput.pause();
  131. videoInput.currentTime = 0;
  132. onVideoStopped();
  133. }
  134. });
  135. function onVideoStarted() {
  136. streaming = true;
  137. startAndStop.innerText = 'Stop';
  138. videoInput.height = videoInput.width * (videoInput.videoHeight / videoInput.videoWidth);
  139. utils.executeCode('codeEditor');
  140. }
  141. function onVideoStopped() {
  142. streaming = false;
  143. canvasContext.clearRect(0, 0, canvasOutput.width, canvasOutput.height);
  144. startAndStop.innerText = 'Start';
  145. }
  146. utils.loadOpenCv(() => {
  147. videoInput.addEventListener('canplay', () => {
  148. startAndStop.removeAttribute('disabled');
  149. });
  150. videoInput.src = 'cup.mp4';
  151. });
  152. </script>
  153. </body>
  154. </html>