mirror of
https://gitcode.com/gh_mirrors/es/esp32-opencv.git
synced 2025-08-14 10:40:47 +08:00
701 lines
22 KiB
HTML
701 lines
22 KiB
HTML
<!DOCTYPE html>
|
|
<html >
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<title>Image Processing Video Example</title>
|
|
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
|
<style type="text/css">
|
|
.dg {
|
|
text-align: left;
|
|
}
|
|
.dg .property-name {
|
|
font: 11px Lucida Grande,sans-serif;
|
|
line-height: 27px;
|
|
}
|
|
.dg.main .close-button {
|
|
font: 11px Lucida Grande,sans-serif;
|
|
line-height: 27px;
|
|
}
|
|
.cell-top {
|
|
vertical-align: top;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<h2>Image Processing Video Example</h2>
|
|
<p>
|
|
Open the controls and try different image processing filters.
|
|
</p>
|
|
<p class="err" id="errorMessage"></p>
|
|
<div id="container">
|
|
<table>
|
|
<tr>
|
|
<td></td>
|
|
<td>
|
|
<div>
|
|
<span>Current Filter: </span><span id="filterName">Pass Through</span>
|
|
</div>
|
|
</td>
|
|
<td>
|
|
<div>Select Filter:</div>
|
|
</td>
|
|
<td></td>
|
|
</tr>
|
|
<tr>
|
|
<td></td>
|
|
<td class="cell-top">
|
|
<canvas id="canvasOutput" width="640" height="480"></canvas>
|
|
</td>
|
|
<td class="cell-top">
|
|
<div id="guiContainer"></div>
|
|
</td>
|
|
<td></td>
|
|
</tr>
|
|
</table>
|
|
<div>
|
|
<video id="videoInput" class="hidden">Your browser does not support the video tag.</video>
|
|
</div>
|
|
</div>
|
|
<script src="https://webrtc.github.io/adapter/adapter-5.0.4.js" type="text/javascript"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/stats.js/r16/Stats.min.js" type="text/javascript"></script>
|
|
<script src="https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.6.4/dat.gui.min.js" type="text/javascript"></script>
|
|
<script src="utils.js" type="text/javascript"></script>
|
|
<script type="text/javascript">
|
|
let utils = new Utils('errorMessage');
|
|
|
|
let width = 0;
|
|
let height = 0;
|
|
|
|
let resolution = window.innerWidth < 960 ? 'qvga' : 'vga';
|
|
|
|
// whether streaming video from the camera.
|
|
let streaming = false;
|
|
|
|
let video = document.getElementById('videoInput');
|
|
let vc = null;
|
|
|
|
let container = document.getElementById('container');
|
|
|
|
let lastFilter = '';
|
|
let src = null;
|
|
let dstC1 = null;
|
|
let dstC3 = null;
|
|
let dstC4 = null;
|
|
|
|
function startVideoProcessing() {
|
|
src = new cv.Mat(height, width, cv.CV_8UC4);
|
|
dstC1 = new cv.Mat(height, width, cv.CV_8UC1);
|
|
dstC3 = new cv.Mat(height, width, cv.CV_8UC3);
|
|
dstC4 = new cv.Mat(height, width, cv.CV_8UC4);
|
|
requestAnimationFrame(processVideo);
|
|
}
|
|
|
|
function passThrough(src) {
|
|
return src;
|
|
}
|
|
|
|
function gray(src) {
|
|
cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
|
|
return dstC1;
|
|
}
|
|
|
|
function hsv(src) {
|
|
cv.cvtColor(src, dstC3, cv.COLOR_RGBA2RGB);
|
|
cv.cvtColor(dstC3, dstC3, cv.COLOR_RGB2HSV);
|
|
return dstC3;
|
|
}
|
|
|
|
function canny(src) {
|
|
cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
|
|
cv.Canny(dstC1, dstC1, controls.cannyThreshold1, controls.cannyThreshold2,
|
|
controls.cannyApertureSize, controls.cannyL2Gradient);
|
|
return dstC1;
|
|
}
|
|
|
|
function inRange(src) {
|
|
let lowValue = controls.inRangeLow;
|
|
let lowScalar = new cv.Scalar(lowValue, lowValue, lowValue, 255);
|
|
let highValue = controls.inRangeHigh;
|
|
let highScalar = new cv.Scalar(highValue, highValue, highValue, 255);
|
|
let low = new cv.Mat(height, width, src.type(), lowScalar);
|
|
let high = new cv.Mat(height, width, src.type(), highScalar);
|
|
cv.inRange(src, low, high, dstC1);
|
|
low.delete(); high.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
function threshold(src) {
|
|
cv.threshold(src, dstC4, controls.thresholdValue, 200, cv.THRESH_BINARY);
|
|
return dstC4;
|
|
}
|
|
|
|
function adaptiveThreshold(src) {
|
|
let mat = new cv.Mat(height, width, cv.CV_8U);
|
|
cv.cvtColor(src, mat, cv.COLOR_RGBA2GRAY);
|
|
cv.adaptiveThreshold(mat, dstC1, 200, cv.ADAPTIVE_THRESH_GAUSSIAN_C,
|
|
cv.THRESH_BINARY, Number(controls.adaptiveBlockSize), 2);
|
|
mat.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
function gaussianBlur(src) {
|
|
cv.GaussianBlur(src, dstC4,
|
|
{width: controls.gaussianBlurSize, height: controls.gaussianBlurSize},
|
|
0, 0, cv.BORDER_DEFAULT);
|
|
return dstC4;
|
|
}
|
|
|
|
function bilateralFilter(src) {
|
|
let mat = new cv.Mat(height, width, cv.CV_8UC3);
|
|
cv.cvtColor(src, mat, cv.COLOR_RGBA2RGB);
|
|
cv.bilateralFilter(mat, dstC3, controls.bilateralFilterDiameter, controls.bilateralFilterSigma,
|
|
controls.bilateralFilterSigma, cv.BORDER_DEFAULT);
|
|
mat.delete();
|
|
return dstC3;
|
|
}
|
|
|
|
function medianBlur(src) {
|
|
cv.medianBlur(src, dstC4, controls.medianBlurSize);
|
|
return dstC4;
|
|
}
|
|
|
|
function sobel(src) {
|
|
let mat = new cv.Mat(height, width, cv.CV_8UC1);
|
|
cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY, 0);
|
|
cv.Sobel(mat, dstC1, cv.CV_8U, 1, 0, controls.sobelSize, 1, 0, cv.BORDER_DEFAULT);
|
|
mat.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
function scharr(src) {
|
|
let mat = new cv.Mat(height, width, cv.CV_8UC1);
|
|
cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY, 0);
|
|
cv.Scharr(mat, dstC1, cv.CV_8U, 1, 0, 1, 0, cv.BORDER_DEFAULT);
|
|
mat.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
function laplacian(src) {
|
|
let mat = new cv.Mat(height, width, cv.CV_8UC1);
|
|
cv.cvtColor(src, mat, cv.COLOR_RGB2GRAY);
|
|
cv.Laplacian(mat, dstC1, cv.CV_8U, controls.laplacianSize, 1, 0, cv.BORDER_DEFAULT);
|
|
mat.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
let contoursColor = [];
|
|
for (let i = 0; i < 10000; i++) {
|
|
contoursColor.push([Math.round(Math.random() * 255),
|
|
Math.round(Math.random() * 255),
|
|
Math.round(Math.random() * 255), 0]);
|
|
}
|
|
|
|
function contours(src) {
|
|
cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
|
|
cv.threshold(dstC1, dstC4, 120, 200, cv.THRESH_BINARY);
|
|
let contours = new cv.MatVector();
|
|
let hierarchy = new cv.Mat();
|
|
cv.findContours(dstC4, contours, hierarchy,
|
|
Number(controls.contoursMode),
|
|
Number(controls.contoursMethod), {x: 0, y: 0});
|
|
dstC3.delete();
|
|
dstC3 = cv.Mat.ones(height, width, cv.CV_8UC3);
|
|
for (let i = 0; i<contours.size(); ++i) {
|
|
let color = contoursColor[i];
|
|
cv.drawContours(dstC3, contours, i, color, 1, cv.LINE_8, hierarchy);
|
|
}
|
|
contours.delete(); hierarchy.delete();
|
|
return dstC3;
|
|
}
|
|
|
|
function calcHist(src) {
|
|
cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY);
|
|
let srcVec = new cv.MatVector();
|
|
srcVec.push_back(dstC1);
|
|
let scale = 2;
|
|
let channels = [0];
|
|
let histSize = [src.cols/scale];
|
|
const ranges = [0, 255];
|
|
let hist = new cv.Mat();
|
|
let mask = new cv.Mat();
|
|
let color = new cv.Scalar(0xfb, 0xca, 0x04, 0xff);
|
|
cv.calcHist(srcVec, channels, mask, hist, histSize, ranges);
|
|
let result = cv.minMaxLoc(hist, mask);
|
|
let max = result.maxVal;
|
|
cv.cvtColor(dstC1, dstC4, cv.COLOR_GRAY2RGBA);
|
|
// draw histogram on src
|
|
for (let i = 0; i < histSize[0]; i++) {
|
|
let binVal = hist.data32F[i] * src.rows / max;
|
|
cv.rectangle(dstC4, {x: i * scale, y: src.rows - 1},
|
|
{x: (i + 1) * scale - 1, y: src.rows - binVal/3}, color, cv.FILLED);
|
|
}
|
|
srcVec.delete();
|
|
mask.delete();
|
|
hist.delete();
|
|
return dstC4;
|
|
}
|
|
|
|
function equalizeHist(src) {
|
|
cv.cvtColor(src, dstC1, cv.COLOR_RGBA2GRAY, 0);
|
|
cv.equalizeHist(dstC1, dstC1);
|
|
return dstC1;
|
|
}
|
|
|
|
let base;
|
|
|
|
function backprojection(src) {
|
|
if (lastFilter !== 'backprojection') {
|
|
if (base instanceof cv.Mat) {
|
|
base.delete();
|
|
}
|
|
base = src.clone();
|
|
cv.cvtColor(base, base, cv.COLOR_RGB2HSV, 0);
|
|
}
|
|
cv.cvtColor(src, dstC3, cv.COLOR_RGB2HSV, 0);
|
|
let baseVec = new cv.MatVector();
|
|
let targetVec = new cv.MatVector();
|
|
baseVec.push_back(base); targetVec.push_back(dstC3);
|
|
let mask = new cv.Mat();
|
|
let hist = new cv.Mat();
|
|
let channels = [0];
|
|
let histSize = [50];
|
|
let ranges;
|
|
if (controls.backprojectionRangeLow < controls.backprojectionRangeHigh) {
|
|
ranges = [controls.backprojectionRangeLow, controls.backprojectionRangeHigh];
|
|
} else {
|
|
return src;
|
|
}
|
|
cv.calcHist(baseVec, channels, mask, hist, histSize, ranges);
|
|
cv.normalize(hist, hist, 0, 255, cv.NORM_MINMAX);
|
|
cv.calcBackProject(targetVec, channels, hist, dstC1, ranges, 1);
|
|
baseVec.delete();
|
|
targetVec.delete();
|
|
mask.delete();
|
|
hist.delete();
|
|
return dstC1;
|
|
}
|
|
|
|
function erosion(src) {
|
|
let kernelSize = controls.erosionSize;
|
|
let kernel = cv.Mat.ones(kernelSize, kernelSize, cv.CV_8U);
|
|
let color = new cv.Scalar();
|
|
cv.erode(src, dstC4, kernel, {x: -1, y: -1}, 1, Number(controls.erosionBorderType), color);
|
|
kernel.delete();
|
|
return dstC4;
|
|
}
|
|
|
|
function dilation(src) {
|
|
let kernelSize = controls.dilationSize;
|
|
let kernel = cv.Mat.ones(kernelSize, kernelSize, cv.CV_8U);
|
|
let color = new cv.Scalar();
|
|
cv.dilate(src, dstC4, kernel, {x: -1, y: -1}, 1, Number(controls.dilationBorderType), color);
|
|
kernel.delete();
|
|
return dstC4;
|
|
}
|
|
|
|
function morphology(src) {
|
|
let kernelSize = controls.morphologySize;
|
|
let kernel = cv.getStructuringElement(Number(controls.morphologyShape),
|
|
{width: kernelSize, height: kernelSize});
|
|
let color = new cv.Scalar();
|
|
let op = Number(controls.morphologyOp);
|
|
let image = src;
|
|
if (op === cv.MORPH_GRADIENT || op === cv.MORPH_TOPHAT || op === cv.MORPH_BLACKHAT) {
|
|
cv.cvtColor(src, dstC3, cv.COLOR_RGBA2RGB);
|
|
image = dstC3;
|
|
}
|
|
cv.morphologyEx(image, dstC4, op, kernel, {x: -1, y: -1}, 1,
|
|
Number(controls.morphologyBorderType), color);
|
|
kernel.delete();
|
|
return dstC4;
|
|
}
|
|
|
|
function processVideo() {
|
|
if (!streaming) return;
|
|
stats.begin();
|
|
vc.read(src);
|
|
let result;
|
|
switch (controls.filter) {
|
|
case 'passThrough': result = passThrough(src); break;
|
|
case 'gray': result = gray(src); break;
|
|
case 'hsv': result = hsv(src); break;
|
|
case 'canny': result = canny(src); break;
|
|
case 'inRange': result = inRange(src); break;
|
|
case 'threshold': result = threshold(src); break;
|
|
case 'adaptiveThreshold': result = adaptiveThreshold(src); break;
|
|
case 'gaussianBlur': result = gaussianBlur(src); break;
|
|
case 'bilateralFilter': result = bilateralFilter(src); break;
|
|
case 'medianBlur': result = medianBlur(src); break;
|
|
case 'sobel': result = sobel(src); break;
|
|
case 'scharr': result = scharr(src); break;
|
|
case 'laplacian': result = laplacian(src); break;
|
|
case 'contours': result = contours(src); break;
|
|
case 'calcHist': result = calcHist(src); break;
|
|
case 'equalizeHist': result = equalizeHist(src); break;
|
|
case 'backprojection': result = backprojection(src); break;
|
|
case 'erosion': result = erosion(src); break;
|
|
case 'dilation': result = dilation(src); break;
|
|
case 'morphology': result = morphology(src); break;
|
|
default: result = passThrough(src);
|
|
}
|
|
cv.imshow('canvasOutput', result);
|
|
stats.end();
|
|
lastFilter = controls.filter;
|
|
requestAnimationFrame(processVideo);
|
|
}
|
|
|
|
let stats = null;
|
|
|
|
let filters = {
|
|
'passThrough': 'Pass Through',
|
|
'gray': 'Gray',
|
|
'hsv': 'HSV',
|
|
'canny': 'Canny Edge Detection',
|
|
'inRange': 'In Range',
|
|
'threshold': 'Threshold',
|
|
'adaptiveThreshold': 'Adaptive Threshold',
|
|
'gaussianBlur': 'Gaussian Blurring',
|
|
'medianBlur': 'Median Blurring',
|
|
'bilateralFilter': 'Bilateral Filtering',
|
|
'sobel': 'Sobel Derivatives',
|
|
'scharr': 'Scharr Derivatives',
|
|
'laplacian': 'Laplacian Derivatives',
|
|
'contours': 'Contours',
|
|
'calcHist': 'Calculation',
|
|
'equalizeHist': 'Equalization',
|
|
'backprojection': 'Backprojection',
|
|
'erosion': 'Erosion',
|
|
'dilation': 'Dilation',
|
|
'morphology': 'Morphology',
|
|
};
|
|
|
|
let filterName = document.getElementById('filterName');
|
|
|
|
let controls;
|
|
|
|
function initUI() {
|
|
stats = new Stats();
|
|
stats.showPanel(0);
|
|
container.appendChild(stats.domElement);
|
|
stats.domElement.style.position = 'absolute';
|
|
stats.domElement.style.right = '0px';
|
|
stats.domElement.style.top = '0px';
|
|
|
|
controls = {
|
|
filter: 'passThrough',
|
|
setFilter: function(filter) {
|
|
this.filter = filter;
|
|
filterName.innerHTML = filters[filter];
|
|
},
|
|
passThrough: function() {
|
|
this.setFilter('passThrough');
|
|
},
|
|
gray: function() {
|
|
this.setFilter('gray');
|
|
},
|
|
hsv: function() {
|
|
this.setFilter('hsv');
|
|
},
|
|
inRange: function() {
|
|
this.setFilter('inRange');
|
|
},
|
|
inRangeLow: 75,
|
|
inRangeHigh: 150,
|
|
threshold: function() {
|
|
this.setFilter('threshold');
|
|
},
|
|
thresholdValue: 100,
|
|
adaptiveThreshold: function() {
|
|
this.setFilter('adaptiveThreshold');
|
|
},
|
|
adaptiveBlockSize: 3,
|
|
gaussianBlur: function() {
|
|
this.setFilter('gaussianBlur');
|
|
},
|
|
gaussianBlurSize: 7,
|
|
medianBlur: function() {
|
|
this.setFilter('medianBlur');
|
|
},
|
|
medianBlurSize: 5,
|
|
bilateralFilter: function() {
|
|
this.setFilter('bilateralFilter');
|
|
},
|
|
bilateralFilterDiameter: 5,
|
|
bilateralFilterSigma: 75,
|
|
sobel: function() {
|
|
this.setFilter('sobel');
|
|
},
|
|
sobelSize: 3,
|
|
scharr: function() {
|
|
this.setFilter('scharr');
|
|
},
|
|
laplacian: function() {
|
|
this.setFilter('laplacian');
|
|
},
|
|
laplacianSize: 3,
|
|
canny: function() {
|
|
this.setFilter('canny');
|
|
},
|
|
cannyThreshold1: 150,
|
|
cannyThreshold2: 300,
|
|
cannyApertureSize: 3,
|
|
cannyL2Gradient: false,
|
|
contours: function() {
|
|
this.setFilter('contours');
|
|
},
|
|
contoursMode: cv.RETR_CCOMP,
|
|
contoursMethod: cv.CHAIN_APPROX_SIMPLE,
|
|
calcHist: function() {
|
|
this.setFilter('calcHist');
|
|
},
|
|
equalizeHist: function() {
|
|
this.setFilter('equalizeHist');
|
|
},
|
|
backprojection: function() {
|
|
this.setFilter('backprojection');
|
|
},
|
|
backprojectionRangeLow: 0,
|
|
backprojectionRangeHigh: 150,
|
|
morphology: function() {
|
|
this.setFilter('morphology');
|
|
},
|
|
morphologyShape: cv.MORPH_RECT,
|
|
morphologyOp: cv.MORPH_ERODE,
|
|
morphologySize: 5,
|
|
morphologyBorderType: cv.BORDER_CONSTANT,
|
|
};
|
|
|
|
let gui = new dat.GUI({autoPlace: false});
|
|
let guiContainer = document.getElementById('guiContainer');
|
|
guiContainer.appendChild(gui.domElement);
|
|
|
|
let lastFolder = null;
|
|
function closeLastFolder(folder) {
|
|
if (lastFolder != null && lastFolder != folder) {
|
|
lastFolder.close();
|
|
}
|
|
lastFolder = folder;
|
|
}
|
|
|
|
gui.add(controls, 'passThrough').name(filters['passThrough']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
|
|
let colorConversion = gui.addFolder('Color Conversion');
|
|
colorConversion.add(controls, 'gray').name(filters['gray']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
|
|
colorConversion.add(controls, 'hsv').name(filters['hsv']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
|
|
let inRange = colorConversion.addFolder(filters['inRange']);
|
|
inRange.domElement.onclick = function() {
|
|
closeLastFolder(inRange);
|
|
controls.inRange();
|
|
};
|
|
inRange.add(controls, 'inRangeLow', 0, 255, 1).name('lower boundary');
|
|
inRange.add(controls, 'inRangeHigh', 0, 255, 1).name('higher boundary');
|
|
|
|
// let geometricTransformations = gui.addFolder('Geometric Transformations');
|
|
// TODO
|
|
|
|
let thresholding = gui.addFolder('Thresholding');
|
|
|
|
let threshold = thresholding.addFolder(filters['threshold']);
|
|
threshold.domElement.onclick = function() {
|
|
closeLastFolder(threshold);
|
|
controls.threshold();
|
|
};
|
|
threshold.add(controls, 'thresholdValue', 0, 200, 1).name('threshold value');
|
|
|
|
let adaptiveThreshold = thresholding.addFolder(filters['adaptiveThreshold']);
|
|
adaptiveThreshold.domElement.onclick = function() {
|
|
closeLastFolder(adaptiveThreshold);
|
|
controls.adaptiveThreshold();
|
|
};
|
|
adaptiveThreshold.add(
|
|
controls, 'adaptiveBlockSize', 3, 99, 1).name('block size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.adaptiveBlockSize = value + 1;
|
|
});
|
|
|
|
let smoothing = gui.addFolder('Smoothing');
|
|
|
|
let gaussianBlur = smoothing.addFolder(filters['gaussianBlur']);
|
|
gaussianBlur.domElement.onclick = function() {
|
|
closeLastFolder(gaussianBlur);
|
|
controls.gaussianBlur();
|
|
};
|
|
gaussianBlur.add(
|
|
controls, 'gaussianBlurSize', 7, 99, 1).name('kernel size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.gaussianBlurSize = value + 1;
|
|
});
|
|
|
|
let medianBlur = smoothing.addFolder(filters['medianBlur']);
|
|
medianBlur.domElement.onclick = function() {
|
|
closeLastFolder(medianBlur);
|
|
controls.medianBlur();
|
|
};
|
|
medianBlur.add(
|
|
controls, 'medianBlurSize', 3, 99, 1).name('kernel size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.medianBlurSize = value + 1;
|
|
});
|
|
|
|
let bilateralFilter = smoothing.addFolder(filters['bilateralFilter']);
|
|
bilateralFilter.domElement.onclick = function() {
|
|
closeLastFolder(bilateralFilter);
|
|
controls.bilateralFilter();
|
|
};
|
|
bilateralFilter.add(controls, 'bilateralFilterDiameter', 1, 15, 1).name('diameter');
|
|
bilateralFilter.add(controls, 'bilateralFilterSigma', 1, 255, 1).name('sigma');
|
|
|
|
let morphology = gui.addFolder('Morphology');
|
|
morphology.domElement.onclick = function() {
|
|
closeLastFolder(morphology);
|
|
controls.morphology();
|
|
};
|
|
morphology.add(
|
|
controls, 'morphologyOp',
|
|
{'MORPH_ERODE': cv.MORPH_ERODE,
|
|
'MORPH_DILATE': cv.MORPH_DILATE,
|
|
'MORPH_OPEN ': cv.MORPH_OPEN,
|
|
'MORPH_CLOSE': cv.MORPH_CLOSE,
|
|
'MORPH_GRADIENT': cv.MORPH_GRADIENT,
|
|
'MORPH_TOPHAT': cv.MORPH_TOPHAT,
|
|
'MORPH_BLACKHAT': cv.MORPH_BLACKHAT}).name('operation');
|
|
morphology.add(
|
|
controls, 'morphologyShape',
|
|
{'MORPH_RECT': cv.MORPH_RECT,
|
|
'MORPH_CROSS': cv.MORPH_CROSS,
|
|
'MORPH_ELLIPSE': cv.MORPH_ELLIPSE}).name('shape');
|
|
morphology.add(
|
|
controls, 'morphologySize', 1, 15, 1).name('kernel size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.morphologySize = value + 1;
|
|
});
|
|
morphology.add(
|
|
controls, 'morphologyBorderType',
|
|
{'BORDER_CONSTANT': cv.BORDER_CONSTANT,
|
|
'BORDER_REPLICATE': cv.BORDER_REPLICATE,
|
|
'BORDER_REFLECT': cv.BORDER_REFLECT,
|
|
'BORDER_REFLECT_101': cv.BORDER_REFLECT_101}).name('boarder type');
|
|
|
|
let gradients = gui.addFolder('Gradients');
|
|
let sobel = gradients.addFolder(filters['sobel']);
|
|
sobel.domElement.onclick = function() {
|
|
closeLastFolder(sobel);
|
|
controls.sobel();
|
|
};
|
|
sobel.add(controls, 'sobelSize', 3, 19, 1).name('kernel size').onChange(function(value) {
|
|
if (value % 2 === 0) controls.sobelSize = value + 1;
|
|
});
|
|
|
|
gradients.add(controls, 'scharr').name(filters['scharr']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
|
|
let laplacian = gradients.addFolder(filters['laplacian']);
|
|
laplacian.domElement.onclick = function() {
|
|
closeLastFolder(laplacian);
|
|
controls.laplacian();
|
|
};
|
|
laplacian.add(
|
|
controls, 'laplacianSize', 1, 19, 1).name('kernel size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.laplacianSize = value + 1;
|
|
});
|
|
|
|
let canny = gui.addFolder(filters['canny']);
|
|
canny.domElement.onclick = function() {
|
|
closeLastFolder(canny);
|
|
controls.canny();
|
|
};
|
|
canny.add(controls, 'cannyThreshold1', 1, 500, 1).name('threshold1');
|
|
canny.add(controls, 'cannyThreshold2', 1, 500, 1).name('threshold2');
|
|
canny.add(controls, 'cannyApertureSize', 3, 7, 1).name('aperture size').onChange(
|
|
function(value) {
|
|
if (value % 2 === 0) controls.cannyApertureSize = value + 1;
|
|
});
|
|
canny.add(controls, 'cannyL2Gradient').name('l2 gradient');
|
|
|
|
let contours = gui.addFolder(filters['contours']);
|
|
contours.domElement.onclick = function() {
|
|
closeLastFolder(contours);
|
|
controls.contours();
|
|
};
|
|
contours.add(
|
|
controls, 'contoursMode',
|
|
{'RETR_EXTERNAL': cv.RETR_EXTERNAL,
|
|
'RETR_LIST': cv.RETR_LIST,
|
|
'RETR_CCOMP': cv.RETR_CCOMP,
|
|
'RETR_TREE': cv.RETR_TREE}).name('mode');
|
|
contours.add(
|
|
controls, 'contoursMethod',
|
|
{'CHAIN_APPROX_NONE': cv.CHAIN_APPROX_NONE,
|
|
'CHAIN_APPROX_SIMPLE': cv.CHAIN_APPROX_SIMPLE,
|
|
'CHAIN_APPROX_TC89_L1': cv.CHAIN_APPROX_TC89_L1,
|
|
'CHAIN_APPROX_TC89_KCOS': cv.CHAIN_APPROX_TC89_KCOS}).name('method');
|
|
|
|
let histograms = gui.addFolder('Histograms');
|
|
histograms.add(controls, 'calcHist').name(filters['calcHist']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
histograms.add(controls, 'equalizeHist').name(filters['equalizeHist']).onChange(function() {
|
|
closeLastFolder(null);
|
|
});
|
|
|
|
let backprojection = histograms.addFolder(filters['backprojection']);
|
|
backprojection.domElement.onclick = function() {
|
|
closeLastFolder(backprojection);
|
|
controls.backprojection();
|
|
};
|
|
backprojection.add(controls, 'backprojectionRangeLow', 0, 255, 1).name('range low');
|
|
backprojection.add(controls, 'backprojectionRangeHigh', 0, 255, 1).name('range high');
|
|
}
|
|
|
|
function startCamera() {
|
|
if (!streaming) {
|
|
utils.clearError();
|
|
utils.startCamera(resolution, onVideoStarted, 'videoInput');
|
|
} else {
|
|
utils.stopCamera();
|
|
onVideoStopped();
|
|
}
|
|
}
|
|
|
|
function onVideoStarted() {
|
|
height = video.videoHeight;
|
|
width = video.videoWidth;
|
|
video.setAttribute('width', width);
|
|
video.setAttribute('height', height);
|
|
streaming = true;
|
|
vc = new cv.VideoCapture(video);
|
|
startVideoProcessing();
|
|
}
|
|
|
|
function stopVideoProcessing() {
|
|
if (src != null && !src.isDeleted()) src.delete();
|
|
if (dstC1 != null && !dstC1.isDeleted()) dstC1.delete();
|
|
if (dstC3 != null && !dstC3.isDeleted()) dstC3.delete();
|
|
if (dstC4 != null && !dstC4.isDeleted()) dstC4.delete();
|
|
}
|
|
|
|
function onVideoStopped() {
|
|
if (!streaming) return;
|
|
stopVideoProcessing();
|
|
document.getElementById('canvasOutput').getContext('2d').clearRect(0, 0, width, height);
|
|
streaming = false;
|
|
}
|
|
|
|
utils.loadOpenCv(() => {
|
|
initUI();
|
|
startCamera();
|
|
});
|
|
</script>
|
|
</body>
|
|
</html>
|