js_image_classification.html 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263
  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Image Classification Example</title>
  6. <link href="js_example_style.css" rel="stylesheet" type="text/css" />
  7. </head>
  8. <body>
  9. <h2>Image Classification Example</h2>
  10. <p>
  11. This tutorial shows you how to write an image classification example with OpenCV.js.<br>
  12. To try the example you should click the <b>modelFile</b> button(and <b>configFile</b> button if needed) to upload inference model.
  13. You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
  14. Then You should change the parameters in the first code snippet according to the uploaded model.
  15. Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
  16. </p>
  17. <div class="control"><button id="tryIt" disabled>Try it</button></div>
  18. <div>
  19. <table cellpadding="0" cellspacing="0" width="0" border="0">
  20. <tr>
  21. <td>
  22. <canvas id="canvasInput" width="400" height="400"></canvas>
  23. </td>
  24. <td>
  25. <table style="visibility: hidden;" id="result">
  26. <thead>
  27. <tr>
  28. <th scope="col">#</th>
  29. <th scope="col" width=300>Label</th>
  30. <th scope="col">Probability</th>
  31. </tr>
  32. </thead>
  33. <tbody>
  34. <tr>
  35. <th scope="row">1</th>
  36. <td id="label0" align="center"></td>
  37. <td id="prob0" align="center"></td>
  38. </tr>
  39. <tr>
  40. <th scope="row">2</th>
  41. <td id="label1" align="center"></td>
  42. <td id="prob1" align="center"></td>
  43. </tr>
  44. <tr>
  45. <th scope="row">3</th>
  46. <td id="label2" align="center"></td>
  47. <td id="prob2" align="center"></td>
  48. </tr>
  49. </tbody>
  50. </table>
  51. <p id='status' align="left"></p>
  52. </td>
  53. </tr>
  54. <tr>
  55. <td>
  56. <div class="caption">
  57. canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
  58. </div>
  59. </td>
  60. <td></td>
  61. </tr>
  62. <tr>
  63. <td>
  64. <div class="caption">
  65. modelFile <input type="file" id="modelFile">
  66. </div>
  67. </td>
  68. </tr>
  69. <tr>
  70. <td>
  71. <div class="caption">
  72. configFile <input type="file" id="configFile">
  73. </div>
  74. </td>
  75. </tr>
  76. </table>
  77. </div>
  78. <div>
  79. <p class="err" id="errorMessage"></p>
  80. </div>
  81. <div>
  82. <h3>Help function</h3>
  83. <p>1.The parameters for model inference which you can modify to investigate more models.</p>
  84. <textarea class="code" rows="13" cols="100" id="codeEditor" spellcheck="false"></textarea>
  85. <p>2.Main loop in which will read the image from canvas and do inference once.</p>
  86. <textarea class="code" rows="17" cols="100" id="codeEditor1" spellcheck="false"></textarea>
  87. <p>3.Load labels from txt file and process it into an array.</p>
  88. <textarea class="code" rows="7" cols="100" id="codeEditor2" spellcheck="false"></textarea>
  89. <p>4.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
  90. <textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
  91. <p>5.Fetch model file and save to emscripten file system once click the input button.</p>
  92. <textarea class="code" rows="17" cols="100" id="codeEditor4" spellcheck="false"></textarea>
  93. <p>6.The post-processing, including softmax if needed and get the top classes from the output vector.</p>
  94. <textarea class="code" rows="35" cols="100" id="codeEditor5" spellcheck="false"></textarea>
  95. </div>
  96. <div id="appendix">
  97. <h2>Model Info:</h2>
  98. </div>
  99. <script src="utils.js" type="text/javascript"></script>
  100. <script src="js_dnn_example_helper.js" type="text/javascript"></script>
  101. <script id="codeSnippet" type="text/code-snippet">
  102. inputSize = [224,224];
  103. mean = [104, 117, 123];
  104. std = 1;
  105. swapRB = false;
  106. // record if need softmax function for post-processing
  107. needSoftmax = false;
  108. // url for label file, can from local or Internet
  109. labelsUrl = "https://raw.githubusercontent.com/opencv/opencv/4.x/samples/data/dnn/classification_classes_ILSVRC2012.txt";
  110. </script>
  111. <script id="codeSnippet1" type="text/code-snippet">
  112. main = async function() {
  113. const labels = await loadLables(labelsUrl);
  114. const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
  115. let net = cv.readNet(configPath, modelPath);
  116. net.setInput(input);
  117. const start = performance.now();
  118. const result = net.forward();
  119. const time = performance.now()-start;
  120. const probs = softmax(result);
  121. const classes = getTopClasses(probs, labels);
  122. updateResult(classes, time);
  123. input.delete();
  124. net.delete();
  125. result.delete();
  126. }
  127. </script>
  128. <script id="codeSnippet5" type="text/code-snippet">
  129. softmax = function(result) {
  130. let arr = result.data32F;
  131. if (needSoftmax) {
  132. const maxNum = Math.max(...arr);
  133. const expSum = arr.map((num) => Math.exp(num - maxNum)).reduce((a, b) => a + b);
  134. return arr.map((value, index) => {
  135. return Math.exp(value - maxNum) / expSum;
  136. });
  137. } else {
  138. return arr;
  139. }
  140. }
  141. </script>
  142. <script type="text/javascript">
  143. let jsonUrl = "js_image_classification_model_info.json";
  144. drawInfoTable(jsonUrl, 'appendix');
  145. let utils = new Utils('errorMessage');
  146. utils.loadCode('codeSnippet', 'codeEditor');
  147. utils.loadCode('codeSnippet1', 'codeEditor1');
  148. let loadLablesCode = 'loadLables = ' + loadLables.toString();
  149. document.getElementById('codeEditor2').value = loadLablesCode;
  150. let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
  151. document.getElementById('codeEditor3').value = getBlobFromImageCode;
  152. let loadModelCode = 'loadModel = ' + loadModel.toString();
  153. document.getElementById('codeEditor4').value = loadModelCode;
  154. utils.loadCode('codeSnippet5', 'codeEditor5');
  155. let getTopClassesCode = 'getTopClasses = ' + getTopClasses.toString();
  156. document.getElementById('codeEditor5').value += '\n' + '\n' + getTopClassesCode;
  157. let canvas = document.getElementById('canvasInput');
  158. let ctx = canvas.getContext('2d');
  159. let img = new Image();
  160. img.crossOrigin = 'anonymous';
  161. img.src = 'space_shuttle.jpg';
  162. img.onload = function() {
  163. ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
  164. };
  165. let tryIt = document.getElementById('tryIt');
  166. tryIt.addEventListener('click', () => {
  167. initStatus();
  168. document.getElementById('status').innerHTML = 'Running function main()...';
  169. utils.executeCode('codeEditor');
  170. utils.executeCode('codeEditor1');
  171. if (modelPath === "") {
  172. document.getElementById('status').innerHTML = 'Runing failed.';
  173. utils.printError('Please upload model file by clicking the button first.');
  174. } else {
  175. setTimeout(main, 1);
  176. }
  177. });
  178. let fileInput = document.getElementById('fileInput');
  179. fileInput.addEventListener('change', (e) => {
  180. initStatus();
  181. loadImageToCanvas(e, 'canvasInput');
  182. });
  183. let configPath = "";
  184. let configFile = document.getElementById('configFile');
  185. configFile.addEventListener('change', async (e) => {
  186. initStatus();
  187. configPath = await loadModel(e);
  188. document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
  189. });
  190. let modelPath = "";
  191. let modelFile = document.getElementById('modelFile');
  192. modelFile.addEventListener('change', async (e) => {
  193. initStatus();
  194. modelPath = await loadModel(e);
  195. document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
  196. configPath = "";
  197. configFile.value = "";
  198. });
  199. utils.loadOpenCv(() => {
  200. tryIt.removeAttribute('disabled');
  201. });
  202. var main = async function() {};
  203. var softmax = function(result){};
  204. var getTopClasses = function(mat, labels, topK = 3){};
  205. utils.executeCode('codeEditor1');
  206. utils.executeCode('codeEditor2');
  207. utils.executeCode('codeEditor3');
  208. utils.executeCode('codeEditor4');
  209. utils.executeCode('codeEditor5');
  210. function updateResult(classes, time) {
  211. try{
  212. classes.forEach((c,i) => {
  213. let labelElement = document.getElementById('label'+i);
  214. let probElement = document.getElementById('prob'+i);
  215. labelElement.innerHTML = c.label;
  216. probElement.innerHTML = c.prob + '%';
  217. });
  218. let result = document.getElementById('result');
  219. result.style.visibility = 'visible';
  220. document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
  221. <b>Inference time:</b> ${time.toFixed(2)} ms`;
  222. } catch(e) {
  223. console.log(e);
  224. }
  225. }
  226. function initStatus() {
  227. document.getElementById('status').innerHTML = '';
  228. document.getElementById('result').style.visibility = 'hidden';
  229. utils.clearError();
  230. }
  231. </script>
  232. </body>
  233. </html>