js_imgproc_camera.html 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700
  1. <!DOCTYPE html>
  2. <html >
  3. <head>
  4. <meta charset="utf-8">
  5. <title>Image Processing Video Example</title>
  6. <link href="js_example_style.css" rel="stylesheet" type="text/css" />
  7. <style type="text/css">
  8. .dg {
  9. text-align: left;
  10. }
  11. .dg .property-name {
  12. font: 11px Lucida Grande,sans-serif;
  13. line-height: 27px;
  14. }
  15. .dg.main .close-button {
  16. font: 11px Lucida Grande,sans-serif;
  17. line-height: 27px;
  18. }
  19. .cell-top {
  20. vertical-align: top;
  21. }
  22. </style>
  23. </head>
  24. <body>
  25. <h2>Image Processing Video Example</h2>
  26. <p>
  27. Open the controls and try different image processing filters.
  28. </p>
  29. <p class="err" id="errorMessage"></p>
  30. <div id="container">
  31. <table>
  32. <tr>
  33. <td></td>
  34. <td>
  35. <div>
  36. <span>Current Filter: </span><span id="filterName">Pass Through</span>
  37. </div>
  38. </td>
  39. <td>
  40. <div>Select Filter:</div>
  41. </td>
  42. <td></td>
  43. </tr>
  44. <tr>
  45. <td></td>
  46. <td class="cell-top">
  47. <canvas id="canvasOutput" width="640" height="480"></canvas>
  48. </td>
  49. <td class="cell-top">
  50. <div id="guiContainer"></div>
  51. </td>
  52. <td></td>
  53. </tr>
  54. </table>
  55. <div>
  56. <video id="videoInput" class="hidden">Your browser does not support the video tag.</video>
  57. </div>
  58. </div>
  59. <script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
  60. <script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js" type="text/javascript"></script>
  61. <script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.4/dat.gui.min.js" type="text/javascript"></script>
  62. <script src="utils.js" type="text/javascript"></script>
  63. <script type="text/javascript">
  64. let utils = new Utils('errorMessage');
  65. let width = 0;
  66. let height = 0;
  67. let resolution = window.innerWidth < 960 ? 'qvga' : 'vga';
  68. // whether streaming video from the camera.
  69. let streaming = false;
  70. let video = document.getElementById('videoInput');
  71. let vc = null;
  72. let container = document.getElementById('container');
  73. let lastFilter = '';
  74. let src = null;
  75. let dstC1 = null;
  76. let dstC3 = null;
  77. let dstC4 = null;
  78. function startVideoProcessing() {
  79. src = new cv.Mat(height, width, cv.CV_8UC4);
  80. dstC1 = new cv.Mat(height, width, cv.CV_8UC1);
  81. dstC3 = new cv.Mat(height, width, cv.CV_8UC3);
  82. dstC4 = new cv.Mat(height, width, cv.CV_8UC4);
  83. requestAnimationFrame(processVideo);
  84. }
  85. function passThrough(src) {
  86. return src;
  87. }
  88. function gray(src) {
  89. cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
  90. return dstC1;
  91. }
  92. function hsv(src) {
  93. cv.cvtColor(src, dstC3, cv.COLOR_RGBA2RGB);
  94. cv.cvtColor(dstC3, dstC3, cv.COLOR_RGB2HSV);
  95. return dstC3;
  96. }
  97. function canny(src) {
  98. cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
  99. cv.Canny(dstC1, dstC1, controls.cannyThreshold1, controls.cannyThreshold2,
  100. controls.cannyApertureSize, controls.cannyL2Gradient);
  101. return dstC1;
  102. }
  103. function inRange(src) {
  104. let lowValue = controls.inRangeLow;
  105. let lowScalar = new cv.Scalar(lowValue, lowValue, lowValue, 255);
  106. let highValue = controls.inRangeHigh;
  107. let highScalar = new cv.Scalar(highValue, highValue, highValue, 255);
  108. let low = new cv.Mat(height, width, src.type(), lowScalar);
  109. let high = new cv.Mat(height, width, src.type(), highScalar);
  110. cv.inRange(src, low, high, dstC1);
  111. low.delete(); high.delete();
  112. return dstC1;
  113. }
  114. function threshold(src) {
  115. cv.threshold(src, dstC4, controls.thresholdValue, 200, cv.THRESH_BINARY);
  116. return dstC4;
  117. }
  118. function adaptiveThreshold(src) {
  119. let mat = new cv.Mat(height, width, cv.CV_8U);
  120. cv.cvtColor(src, mat, cv.COLOR_RGBA2GRAY);
  121. cv.adaptiveThreshold(mat, dstC1, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C,
  122. cv.THRESH_BINARY, Number(controls.adaptiveBlockSize), 2);
  123. mat.delete();
  124. return dstC1;
  125. }
  126. function gaussianBlur(src) {
  127. cv.GaussianBlur(src, dstC4,
  128. {width: controls.gaussianBlurSize, height: controls.gaussianBlurSize},
  129. 0, 0, cv.BORDER_DEFAULT);
  130. return dstC4;
  131. }
  132. function bilateralFilter(src) {
  133. let mat = new cv.Mat(height, width, cv.CV_8UC3);
  134. cv.cvtColor(src, mat, cv.COLOR_RGBA2RGB);
  135. cv.bilateralFilter(mat, dstC3, controls.bilateralFilterDiameter, controls.bilateralFilterSigma,
  136. controls.bilateralFilterSigma, cv.BORDER_DEFAULT);
  137. mat.delete();
  138. return dstC3;
  139. }
  140. function medianBlur(src) {
  141. cv.medianBlur(src, dstC4, controls.medianBlurSize);
  142. return dstC4;
  143. }
  144. function sobel(src) {
  145. let mat = new cv.Mat(height, width, cv.CV_8UC1);
  146. cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY, 0);
  147. cv.Sobel(mat, dstC1, cv.CV_8U, 1, 0, controls.sobelSize, 1, 0, cv.BORDER_DEFAULT);
  148. mat.delete();
  149. return dstC1;
  150. }
  151. function scharr(src) {
  152. let mat = new cv.Mat(height, width, cv.CV_8UC1);
  153. cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY, 0);
  154. cv.Scharr(mat, dstC1, cv.CV_8U, 1, 0, 1, 0, cv.BORDER_DEFAULT);
  155. mat.delete();
  156. return dstC1;
  157. }
  158. function laplacian(src) {
  159. let mat = new cv.Mat(height, width, cv.CV_8UC1);
  160. cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY);
  161. cv.Laplacian(mat, dstC1, cv.CV_8U, controls.laplacianSize, 1, 0, cv.BORDER_DEFAULT);
  162. mat.delete();
  163. return dstC1;
  164. }
  165. let contoursColor = [];
  166. for (let i = 0; i < 10000; i++) {
  167. contoursColor.push([Math.round(Math.random() * 255),
  168. Math.round(Math.random() * 255),
  169. Math.round(Math.random() * 255), 0]);
  170. }
  171. function contours(src) {
  172. cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
  173. cv.threshold(dstC1, dstC4, 120, 200, cv.THRESH_BINARY);
  174. let contours = new cv.MatVector();
  175. let hierarchy = new cv.Mat();
  176. cv.findContours(dstC4, contours, hierarchy,
  177. Number(controls.contoursMode),
  178. Number(controls.contoursMethod), {x: 0, y: 0});
  179. dstC3.delete();
  180. dstC3 = cv.Mat.ones(height, width, cv.CV_8UC3);
  181. for (let i = 0; i<contours.size(); ++i) {
  182. let color = contoursColor[i];
  183. cv.drawContours(dstC3, contours, i, color, 1, cv.LINE_8, hierarchy);
  184. }
  185. contours.delete(); hierarchy.delete();
  186. return dstC3;
  187. }
  188. function calcHist(src) {
  189. cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
  190. let srcVec = new cv.MatVector();
  191. srcVec.push_back(dstC1);
  192. let scale = 2;
  193. let channels = [0];
  194. let histSize = [src.cols/scale];
  195. const ranges = [0, 255];
  196. let hist = new cv.Mat();
  197. let mask = new cv.Mat();
  198. let color = new cv.Scalar(0xfb, 0xca, 0x04, 0xff);
  199. cv.calcHist(srcVec, channels, mask, hist, histSize, ranges);
  200. let result = cv.minMaxLoc(hist, mask);
  201. let max = result.maxVal;
  202. cv.cvtColor(dstC1, dstC4, cv.COLOR_GRAY2RGBA);
  203. // draw histogram on src
  204. for (let i = 0; i < histSize[0]; i++) {
  205. let binVal = hist.data32F[i] * src.rows / max;
  206. cv.rectangle(dstC4, {x: i * scale, y: src.rows - 1},
  207. {x: (i + 1) * scale - 1, y: src.rows - binVal/3}, color, cv.FILLED);
  208. }
  209. srcVec.delete();
  210. mask.delete();
  211. hist.delete();
  212. return dstC4;
  213. }
  214. function equalizeHist(src) {
  215. cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY, 0);
  216. cv.equalizeHist(dstC1, dstC1);
  217. return dstC1;
  218. }
  219. let base;
  220. function backprojection(src) {
  221. if (lastFilter !== 'backprojection') {
  222. if (base instanceof cv.Mat) {
  223. base.delete();
  224. }
  225. base = src.clone();
  226. cv.cvtColor(base, base, cv.COLOR_RGB2HSV, 0);
  227. }
  228. cv.cvtColor(src, dstC3, cv.COLOR_RGB2HSV, 0);
  229. let baseVec = new cv.MatVector();
  230. let targetVec = new cv.MatVector();
  231. baseVec.push_back(base); targetVec.push_back(dstC3);
  232. let mask = new cv.Mat();
  233. let hist = new cv.Mat();
  234. let channels = [0];
  235. let histSize = [50];
  236. let ranges;
  237. if (controls.backprojectionRangeLow < controls.backprojectionRangeHigh) {
  238. ranges = [controls.backprojectionRangeLow, controls.backprojectionRangeHigh];
  239. } else {
  240. return src;
  241. }
  242. cv.calcHist(baseVec, channels, mask, hist, histSize, ranges);
  243. cv.normalize(hist, hist, 0, 255, cv.NORM_MINMAX);
  244. cv.calcBackProject(targetVec, channels, hist, dstC1, ranges, 1);
  245. baseVec.delete();
  246. targetVec.delete();
  247. mask.delete();
  248. hist.delete();
  249. return dstC1;
  250. }
  251. function erosion(src) {
  252. let kernelSize = controls.erosionSize;
  253. let kernel = cv.Mat.ones(kernelSize, kernelSize, cv.CV_8U);
  254. let color = new cv.Scalar();
  255. cv.erode(src, dstC4, kernel, {x: -1, y: -1}, 1, Number(controls.erosionBorderType), color);
  256. kernel.delete();
  257. return dstC4;
  258. }
  259. function dilation(src) {
  260. let kernelSize = controls.dilationSize;
  261. let kernel = cv.Mat.ones(kernelSize, kernelSize, cv.CV_8U);
  262. let color = new cv.Scalar();
  263. cv.dilate(src, dstC4, kernel, {x: -1, y: -1}, 1, Number(controls.dilationBorderType), color);
  264. kernel.delete();
  265. return dstC4;
  266. }
  267. function morphology(src) {
  268. let kernelSize = controls.morphologySize;
  269. let kernel = cv.getStructuringElement(Number(controls.morphologyShape),
  270. {width: kernelSize, height: kernelSize});
  271. let color = new cv.Scalar();
  272. let op = Number(controls.morphologyOp);
  273. let image = src;
  274. if (op === cv.MORPH_GRADIENT || op === cv.MORPH_TOPHAT || op === cv.MORPH_BLACKHAT) {
  275. cv.cvtColor(src, dstC3, cv.COLOR_RGBA2RGB);
  276. image = dstC3;
  277. }
  278. cv.morphologyEx(image, dstC4, op, kernel, {x: -1, y: -1}, 1,
  279. Number(controls.morphologyBorderType), color);
  280. kernel.delete();
  281. return dstC4;
  282. }
  283. function processVideo() {
  284. if (!streaming) return;
  285. stats.begin();
  286. vc.read(src);
  287. let result;
  288. switch (controls.filter) {
  289. case 'passThrough': result = passThrough(src); break;
  290. case 'gray': result = gray(src); break;
  291. case 'hsv': result = hsv(src); break;
  292. case 'canny': result = canny(src); break;
  293. case 'inRange': result = inRange(src); break;
  294. case 'threshold': result = threshold(src); break;
  295. case 'adaptiveThreshold': result = adaptiveThreshold(src); break;
  296. case 'gaussianBlur': result = gaussianBlur(src); break;
  297. case 'bilateralFilter': result = bilateralFilter(src); break;
  298. case 'medianBlur': result = medianBlur(src); break;
  299. case 'sobel': result = sobel(src); break;
  300. case 'scharr': result = scharr(src); break;
  301. case 'laplacian': result = laplacian(src); break;
  302. case 'contours': result = contours(src); break;
  303. case 'calcHist': result = calcHist(src); break;
  304. case 'equalizeHist': result = equalizeHist(src); break;
  305. case 'backprojection': result = backprojection(src); break;
  306. case 'erosion': result = erosion(src); break;
  307. case 'dilation': result = dilation(src); break;
  308. case 'morphology': result = morphology(src); break;
  309. default: result = passThrough(src);
  310. }
  311. cv.imshow('canvasOutput', result);
  312. stats.end();
  313. lastFilter = controls.filter;
  314. requestAnimationFrame(processVideo);
  315. }
  316. let stats = null;
  317. let filters = {
  318. 'passThrough': 'Pass Through',
  319. 'gray': 'Gray',
  320. 'hsv': 'HSV',
  321. 'canny': 'Canny Edge Detection',
  322. 'inRange': 'In Range',
  323. 'threshold': 'Threshold',
  324. 'adaptiveThreshold': 'Adaptive Threshold',
  325. 'gaussianBlur': 'Gaussian Blurring',
  326. 'medianBlur': 'Median Blurring',
  327. 'bilateralFilter': 'Bilateral Filtering',
  328. 'sobel': 'Sobel Derivatives',
  329. 'scharr': 'Scharr Derivatives',
  330. 'laplacian': 'Laplacian Derivatives',
  331. 'contours': 'Contours',
  332. 'calcHist': 'Calculation',
  333. 'equalizeHist': 'Equalization',
  334. 'backprojection': 'Backprojection',
  335. 'erosion': 'Erosion',
  336. 'dilation': 'Dilation',
  337. 'morphology': 'Morphology',
  338. };
  339. let filterName = document.getElementById('filterName');
  340. let controls;
  341. function initUI() {
  342. stats = new Stats();
  343. stats.showPanel(0);
  344. container.appendChild(stats.domElement);
  345. stats.domElement.style.position = 'absolute';
  346. stats.domElement.style.right = '0px';
  347. stats.domElement.style.top = '0px';
  348. controls = {
  349. filter: 'passThrough',
  350. setFilter: function(filter) {
  351. this.filter = filter;
  352. filterName.innerHTML = filters[filter];
  353. },
  354. passThrough: function() {
  355. this.setFilter('passThrough');
  356. },
  357. gray: function() {
  358. this.setFilter('gray');
  359. },
  360. hsv: function() {
  361. this.setFilter('hsv');
  362. },
  363. inRange: function() {
  364. this.setFilter('inRange');
  365. },
  366. inRangeLow: 75,
  367. inRangeHigh: 150,
  368. threshold: function() {
  369. this.setFilter('threshold');
  370. },
  371. thresholdValue: 100,
  372. adaptiveThreshold: function() {
  373. this.setFilter('adaptiveThreshold');
  374. },
  375. adaptiveBlockSize: 3,
  376. gaussianBlur: function() {
  377. this.setFilter('gaussianBlur');
  378. },
  379. gaussianBlurSize: 7,
  380. medianBlur: function() {
  381. this.setFilter('medianBlur');
  382. },
  383. medianBlurSize: 5,
  384. bilateralFilter: function() {
  385. this.setFilter('bilateralFilter');
  386. },
  387. bilateralFilterDiameter: 5,
  388. bilateralFilterSigma: 75,
  389. sobel: function() {
  390. this.setFilter('sobel');
  391. },
  392. sobelSize: 3,
  393. scharr: function() {
  394. this.setFilter('scharr');
  395. },
  396. laplacian: function() {
  397. this.setFilter('laplacian');
  398. },
  399. laplacianSize: 3,
  400. canny: function() {
  401. this.setFilter('canny');
  402. },
  403. cannyThreshold1: 150,
  404. cannyThreshold2: 300,
  405. cannyApertureSize: 3,
  406. cannyL2Gradient: false,
  407. contours: function() {
  408. this.setFilter('contours');
  409. },
  410. contoursMode: cv.RETR_CCOMP,
  411. contoursMethod: cv.CHAIN_APPROX_SIMPLE,
  412. calcHist: function() {
  413. this.setFilter('calcHist');
  414. },
  415. equalizeHist: function() {
  416. this.setFilter('equalizeHist');
  417. },
  418. backprojection: function() {
  419. this.setFilter('backprojection');
  420. },
  421. backprojectionRangeLow: 0,
  422. backprojectionRangeHigh: 150,
  423. morphology: function() {
  424. this.setFilter('morphology');
  425. },
  426. morphologyShape: cv.MORPH_RECT,
  427. morphologyOp: cv.MORPH_ERODE,
  428. morphologySize: 5,
  429. morphologyBorderType: cv.BORDER_CONSTANT,
  430. };
  431. let gui = new dat.GUI({autoPlace: false});
  432. let guiContainer = document.getElementById('guiContainer');
  433. guiContainer.appendChild(gui.domElement);
  434. let lastFolder = null;
  435. function closeLastFolder(folder) {
  436. if (lastFolder != null && lastFolder != folder) {
  437. lastFolder.close();
  438. }
  439. lastFolder = folder;
  440. }
  441. gui.add(controls, 'passThrough').name(filters['passThrough']).onChange(function() {
  442. closeLastFolder(null);
  443. });
  444. let colorConversion = gui.addFolder('Color Conversion');
  445. colorConversion.add(controls, 'gray').name(filters['gray']).onChange(function() {
  446. closeLastFolder(null);
  447. });
  448. colorConversion.add(controls, 'hsv').name(filters['hsv']).onChange(function() {
  449. closeLastFolder(null);
  450. });
  451. let inRange = colorConversion.addFolder(filters['inRange']);
  452. inRange.domElement.onclick = function() {
  453. closeLastFolder(inRange);
  454. controls.inRange();
  455. };
  456. inRange.add(controls, 'inRangeLow', 0, 255, 1).name('lower boundary');
  457. inRange.add(controls, 'inRangeHigh', 0, 255, 1).name('higher boundary');
  458. // let geometricTransformations = gui.addFolder('Geometric Transformations');
  459. // TODO
  460. let thresholding = gui.addFolder('Thresholding');
  461. let threshold = thresholding.addFolder(filters['threshold']);
  462. threshold.domElement.onclick = function() {
  463. closeLastFolder(threshold);
  464. controls.threshold();
  465. };
  466. threshold.add(controls, 'thresholdValue', 0, 200, 1).name('threshold value');
  467. let adaptiveThreshold = thresholding.addFolder(filters['adaptiveThreshold']);
  468. adaptiveThreshold.domElement.onclick = function() {
  469. closeLastFolder(adaptiveThreshold);
  470. controls.adaptiveThreshold();
  471. };
  472. adaptiveThreshold.add(
  473. controls, 'adaptiveBlockSize', 3, 99, 1).name('block size').onChange(
  474. function(value) {
  475. if (value % 2 === 0) controls.adaptiveBlockSize = value + 1;
  476. });
  477. let smoothing = gui.addFolder('Smoothing');
  478. let gaussianBlur = smoothing.addFolder(filters['gaussianBlur']);
  479. gaussianBlur.domElement.onclick = function() {
  480. closeLastFolder(gaussianBlur);
  481. controls.gaussianBlur();
  482. };
  483. gaussianBlur.add(
  484. controls, 'gaussianBlurSize', 7, 99, 1).name('kernel size').onChange(
  485. function(value) {
  486. if (value % 2 === 0) controls.gaussianBlurSize = value + 1;
  487. });
  488. let medianBlur = smoothing.addFolder(filters['medianBlur']);
  489. medianBlur.domElement.onclick = function() {
  490. closeLastFolder(medianBlur);
  491. controls.medianBlur();
  492. };
  493. medianBlur.add(
  494. controls, 'medianBlurSize', 3, 99, 1).name('kernel size').onChange(
  495. function(value) {
  496. if (value % 2 === 0) controls.medianBlurSize = value + 1;
  497. });
  498. let bilateralFilter = smoothing.addFolder(filters['bilateralFilter']);
  499. bilateralFilter.domElement.onclick = function() {
  500. closeLastFolder(bilateralFilter);
  501. controls.bilateralFilter();
  502. };
  503. bilateralFilter.add(controls, 'bilateralFilterDiameter', 1, 15, 1).name('diameter');
  504. bilateralFilter.add(controls, 'bilateralFilterSigma', 1, 255, 1).name('sigma');
  505. let morphology = gui.addFolder('Morphology');
  506. morphology.domElement.onclick = function() {
  507. closeLastFolder(morphology);
  508. controls.morphology();
  509. };
  510. morphology.add(
  511. controls, 'morphologyOp',
  512. {'MORPH_ERODE': cv.MORPH_ERODE,
  513. 'MORPH_DILATE': cv.MORPH_DILATE,
  514. 'MORPH_OPEN ': cv.MORPH_OPEN,
  515. 'MORPH_CLOSE': cv.MORPH_CLOSE,
  516. 'MORPH_GRADIENT': cv.MORPH_GRADIENT,
  517. 'MORPH_TOPHAT': cv.MORPH_TOPHAT,
  518. 'MORPH_BLACKHAT': cv.MORPH_BLACKHAT}).name('operation');
  519. morphology.add(
  520. controls, 'morphologyShape',
  521. {'MORPH_RECT': cv.MORPH_RECT,
  522. 'MORPH_CROSS': cv.MORPH_CROSS,
  523. 'MORPH_ELLIPSE': cv.MORPH_ELLIPSE}).name('shape');
  524. morphology.add(
  525. controls, 'morphologySize', 1, 15, 1).name('kernel size').onChange(
  526. function(value) {
  527. if (value % 2 === 0) controls.morphologySize = value + 1;
  528. });
  529. morphology.add(
  530. controls, 'morphologyBorderType',
  531. {'BORDER_CONSTANT': cv.BORDER_CONSTANT,
  532. 'BORDER_REPLICATE': cv.BORDER_REPLICATE,
  533. 'BORDER_REFLECT': cv.BORDER_REFLECT,
  534. 'BORDER_REFLECT_101': cv.BORDER_REFLECT_101}).name('boarder type');
  535. let gradients = gui.addFolder('Gradients');
  536. let sobel = gradients.addFolder(filters['sobel']);
  537. sobel.domElement.onclick = function() {
  538. closeLastFolder(sobel);
  539. controls.sobel();
  540. };
  541. sobel.add(controls, 'sobelSize', 3, 19, 1).name('kernel size').onChange(function(value) {
  542. if (value % 2 === 0) controls.sobelSize = value + 1;
  543. });
  544. gradients.add(controls, 'scharr').name(filters['scharr']).onChange(function() {
  545. closeLastFolder(null);
  546. });
  547. let laplacian = gradients.addFolder(filters['laplacian']);
  548. laplacian.domElement.onclick = function() {
  549. closeLastFolder(laplacian);
  550. controls.laplacian();
  551. };
  552. laplacian.add(
  553. controls, 'laplacianSize', 1, 19, 1).name('kernel size').onChange(
  554. function(value) {
  555. if (value % 2 === 0) controls.laplacianSize = value + 1;
  556. });
  557. let canny = gui.addFolder(filters['canny']);
  558. canny.domElement.onclick = function() {
  559. closeLastFolder(canny);
  560. controls.canny();
  561. };
  562. canny.add(controls, 'cannyThreshold1', 1, 500, 1).name('threshold1');
  563. canny.add(controls, 'cannyThreshold2', 1, 500, 1).name('threshold2');
  564. canny.add(controls, 'cannyApertureSize', 3, 7, 1).name('aperture size').onChange(
  565. function(value) {
  566. if (value % 2 === 0) controls.cannyApertureSize = value + 1;
  567. });
  568. canny.add(controls, 'cannyL2Gradient').name('l2 gradient');
  569. let contours = gui.addFolder(filters['contours']);
  570. contours.domElement.onclick = function() {
  571. closeLastFolder(contours);
  572. controls.contours();
  573. };
  574. contours.add(
  575. controls, 'contoursMode',
  576. {'RETR_EXTERNAL': cv.RETR_EXTERNAL,
  577. 'RETR_LIST': cv.RETR_LIST,
  578. 'RETR_CCOMP': cv.RETR_CCOMP,
  579. 'RETR_TREE': cv.RETR_TREE}).name('mode');
  580. contours.add(
  581. controls, 'contoursMethod',
  582. {'CHAIN_APPROX_NONE': cv.CHAIN_APPROX_NONE,
  583. 'CHAIN_APPROX_SIMPLE': cv.CHAIN_APPROX_SIMPLE,
  584. 'CHAIN_APPROX_TC89_L1': cv.CHAIN_APPROX_TC89_L1,
  585. 'CHAIN_APPROX_TC89_KCOS': cv.CHAIN_APPROX_TC89_KCOS}).name('method');
  586. let histograms = gui.addFolder('Histograms');
  587. histograms.add(controls, 'calcHist').name(filters['calcHist']).onChange(function() {
  588. closeLastFolder(null);
  589. });
  590. histograms.add(controls, 'equalizeHist').name(filters['equalizeHist']).onChange(function() {
  591. closeLastFolder(null);
  592. });
  593. let backprojection = histograms.addFolder(filters['backprojection']);
  594. backprojection.domElement.onclick = function() {
  595. closeLastFolder(backprojection);
  596. controls.backprojection();
  597. };
  598. backprojection.add(controls, 'backprojectionRangeLow', 0, 255, 1).name('range low');
  599. backprojection.add(controls, 'backprojectionRangeHigh', 0, 255, 1).name('range high');
  600. }
  601. function startCamera() {
  602. if (!streaming) {
  603. utils.clearError();
  604. utils.startCamera(resolution, onVideoStarted, 'videoInput');
  605. } else {
  606. utils.stopCamera();
  607. onVideoStopped();
  608. }
  609. }
  610. function onVideoStarted() {
  611. height = video.videoHeight;
  612. width = video.videoWidth;
  613. video.setAttribute('width', width);
  614. video.setAttribute('height', height);
  615. streaming = true;
  616. vc = new cv.VideoCapture(video);
  617. startVideoProcessing();
  618. }
  619. function stopVideoProcessing() {
  620. if (src != null && !src.isDeleted()) src.delete();
  621. if (dstC1 != null && !dstC1.isDeleted()) dstC1.delete();
  622. if (dstC3 != null && !dstC3.isDeleted()) dstC3.delete();
  623. if (dstC4 != null && !dstC4.isDeleted()) dstC4.delete();
  624. }
  625. function onVideoStopped() {
  626. if (!streaming) return;
  627. stopVideoProcessing();
  628. document.getElementById('canvasOutput').getContext('2d').clearRect(0, 0, width, height);
  629. streaming = false;
  630. }
  631. utils.loadOpenCv(() => {
  632. initUI();
  633. startCamera();
  634. });
  635. </script>
  636. </body>
  637. </html>