mirror of
https://github.com/opencv/opencv.git
synced 2025-06-07 17:44:04 +08:00
Merge remote-tracking branch 'upstream/3.4' into merge-3.4
This commit is contained in:
commit
6fdb7aee84
@ -6,6 +6,7 @@
|
||||
if(BUILD_ZLIB)
|
||||
ocv_clear_vars(ZLIB_FOUND)
|
||||
else()
|
||||
ocv_clear_internal_cache_vars(ZLIB_LIBRARY ZLIB_INCLUDE_DIR)
|
||||
find_package(ZLIB "${MIN_VER_ZLIB}")
|
||||
if(ZLIB_FOUND AND ANDROID)
|
||||
if(ZLIB_LIBRARIES MATCHES "/usr/(lib|lib32|lib64)/libz.so$")
|
||||
@ -31,11 +32,12 @@ if(WITH_JPEG)
|
||||
if(BUILD_JPEG)
|
||||
ocv_clear_vars(JPEG_FOUND)
|
||||
else()
|
||||
ocv_clear_internal_cache_vars(JPEG_LIBRARY JPEG_INCLUDE_DIR)
|
||||
include(FindJPEG)
|
||||
endif()
|
||||
|
||||
if(NOT JPEG_FOUND)
|
||||
ocv_clear_vars(JPEG_LIBRARY JPEG_LIBRARIES JPEG_INCLUDE_DIR)
|
||||
ocv_clear_vars(JPEG_LIBRARY JPEG_INCLUDE_DIR)
|
||||
|
||||
if(NOT BUILD_JPEG_TURBO_DISABLE)
|
||||
set(JPEG_LIBRARY libjpeg-turbo CACHE INTERNAL "")
|
||||
@ -76,6 +78,7 @@ if(WITH_TIFF)
|
||||
if(BUILD_TIFF)
|
||||
ocv_clear_vars(TIFF_FOUND)
|
||||
else()
|
||||
ocv_clear_internal_cache_vars(TIFF_LIBRARY TIFF_INCLUDE_DIR)
|
||||
include(FindTIFF)
|
||||
if(TIFF_FOUND)
|
||||
ocv_parse_header("${TIFF_INCLUDE_DIR}/tiff.h" TIFF_VERSION_LINES TIFF_VERSION_CLASSIC TIFF_VERSION_BIG TIFF_VERSION TIFF_BIGTIFF_VERSION)
|
||||
@ -119,6 +122,7 @@ if(WITH_WEBP)
|
||||
if(BUILD_WEBP)
|
||||
ocv_clear_vars(WEBP_FOUND WEBP_LIBRARY WEBP_LIBRARIES WEBP_INCLUDE_DIR)
|
||||
else()
|
||||
ocv_clear_internal_cache_vars(WEBP_LIBRARY WEBP_INCLUDE_DIR)
|
||||
include(cmake/OpenCVFindWebP.cmake)
|
||||
if(WEBP_FOUND)
|
||||
set(HAVE_WEBP 1)
|
||||
@ -212,6 +216,7 @@ if(WITH_PNG)
|
||||
if(BUILD_PNG)
|
||||
ocv_clear_vars(PNG_FOUND)
|
||||
else()
|
||||
ocv_clear_internal_cache_vars(PNG_LIBRARY PNG_INCLUDE_DIR)
|
||||
include(FindPNG)
|
||||
if(PNG_FOUND)
|
||||
include(CheckIncludeFile)
|
||||
@ -243,6 +248,7 @@ endif()
|
||||
if(WITH_OPENEXR)
|
||||
ocv_clear_vars(HAVE_OPENEXR)
|
||||
if(NOT BUILD_OPENEXR)
|
||||
ocv_clear_internal_cache_vars(OPENEXR_INCLUDE_PATHS OPENEXR_LIBRARIES OPENEXR_ILMIMF_LIBRARY OPENEXR_VERSION)
|
||||
include("${OpenCV_SOURCE_DIR}/cmake/OpenCVFindOpenEXR.cmake")
|
||||
endif()
|
||||
|
||||
|
@ -98,15 +98,6 @@ macro(ocv_add_dependencies full_modname)
|
||||
endforeach()
|
||||
unset(__depsvar)
|
||||
|
||||
# hack for python
|
||||
set(__python_idx)
|
||||
list(FIND OPENCV_MODULE_${full_modname}_WRAPPERS "python" __python_idx)
|
||||
if (NOT __python_idx EQUAL -1)
|
||||
list(REMOVE_ITEM OPENCV_MODULE_${full_modname}_WRAPPERS "python")
|
||||
list(APPEND OPENCV_MODULE_${full_modname}_WRAPPERS "python_bindings_generator" "python2" "python3")
|
||||
endif()
|
||||
unset(__python_idx)
|
||||
|
||||
ocv_list_unique(OPENCV_MODULE_${full_modname}_REQ_DEPS)
|
||||
ocv_list_unique(OPENCV_MODULE_${full_modname}_OPT_DEPS)
|
||||
ocv_list_unique(OPENCV_MODULE_${full_modname}_PRIVATE_REQ_DEPS)
|
||||
@ -210,9 +201,17 @@ macro(ocv_add_module _name)
|
||||
set(OPENCV_MODULES_DISABLED_USER ${OPENCV_MODULES_DISABLED_USER} "${the_module}" CACHE INTERNAL "List of OpenCV modules explicitly disabled by user")
|
||||
endif()
|
||||
|
||||
# add reverse wrapper dependencies
|
||||
# add reverse wrapper dependencies (BINDINDS)
|
||||
foreach (wrapper ${OPENCV_MODULE_${the_module}_WRAPPERS})
|
||||
ocv_add_dependencies(opencv_${wrapper} OPTIONAL ${the_module})
|
||||
if(wrapper STREQUAL "python") # hack for python (BINDINDS)
|
||||
ocv_add_dependencies(opencv_python2 OPTIONAL ${the_module})
|
||||
ocv_add_dependencies(opencv_python3 OPTIONAL ${the_module})
|
||||
else()
|
||||
ocv_add_dependencies(opencv_${wrapper} OPTIONAL ${the_module})
|
||||
endif()
|
||||
if(DEFINED OPENCV_MODULE_opencv_${wrapper}_bindings_generator_CLASS)
|
||||
ocv_add_dependencies(opencv_${wrapper}_bindings_generator OPTIONAL ${the_module})
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
# stop processing of current file
|
||||
|
@ -400,6 +400,24 @@ macro(ocv_clear_vars)
|
||||
endforeach()
|
||||
endmacro()
|
||||
|
||||
|
||||
# Clears passed variables with INTERNAL type from CMake cache
|
||||
macro(ocv_clear_internal_cache_vars)
|
||||
foreach(_var ${ARGN})
|
||||
get_property(_propertySet CACHE ${_var} PROPERTY TYPE SET)
|
||||
if(_propertySet)
|
||||
get_property(_type CACHE ${_var} PROPERTY TYPE)
|
||||
if(_type STREQUAL "INTERNAL")
|
||||
message("Cleaning INTERNAL cached variable: ${_var}")
|
||||
unset(${_var} CACHE)
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
||||
unset(_propertySet)
|
||||
unset(_type)
|
||||
endmacro()
|
||||
|
||||
|
||||
set(OCV_COMPILER_FAIL_REGEX
|
||||
"argument .* is not valid" # GCC 9+ (including support of unicode quotes)
|
||||
"command[- ]line option .* is valid for .* but not for C\\+\\+" # GNU
|
||||
|
1
cmake/platforms/OpenCV-Emscripten.cmake
Normal file
1
cmake/platforms/OpenCV-Emscripten.cmake
Normal file
@ -0,0 +1 @@
|
||||
set(OPENCV_SKIP_LINK_AS_NEEDED 1)
|
119
doc/js_tutorials/js_assets/js_dnn_example_helper.js
Normal file
119
doc/js_tutorials/js_assets/js_dnn_example_helper.js
Normal file
@ -0,0 +1,119 @@
|
||||
getBlobFromImage = function(inputSize, mean, std, swapRB, image) {
|
||||
let mat;
|
||||
if (typeof(image) === 'string') {
|
||||
mat = cv.imread(image);
|
||||
} else {
|
||||
mat = image;
|
||||
}
|
||||
|
||||
let matC3 = new cv.Mat(mat.matSize[0], mat.matSize[1], cv.CV_8UC3);
|
||||
cv.cvtColor(mat, matC3, cv.COLOR_RGBA2BGR);
|
||||
let input = cv.blobFromImage(matC3, std, new cv.Size(inputSize[0], inputSize[1]),
|
||||
new cv.Scalar(mean[0], mean[1], mean[2]), swapRB);
|
||||
|
||||
matC3.delete();
|
||||
return input;
|
||||
}
|
||||
|
||||
loadLables = async function(labelsUrl) {
|
||||
let response = await fetch(labelsUrl);
|
||||
let label = await response.text();
|
||||
label = label.split('\n');
|
||||
return label;
|
||||
}
|
||||
|
||||
loadModel = async function(e) {
|
||||
return new Promise((resolve) => {
|
||||
let file = e.target.files[0];
|
||||
let path = file.name;
|
||||
let reader = new FileReader();
|
||||
reader.readAsArrayBuffer(file);
|
||||
reader.onload = function(ev) {
|
||||
if (reader.readyState === 2) {
|
||||
let buffer = reader.result;
|
||||
let data = new Uint8Array(buffer);
|
||||
cv.FS_createDataFile('/', path, data, true, false, false);
|
||||
resolve(path);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
getTopClasses = function(probs, labels, topK = 3) {
|
||||
probs = Array.from(probs);
|
||||
let indexes = probs.map((prob, index) => [prob, index]);
|
||||
let sorted = indexes.sort((a, b) => {
|
||||
if (a[0] === b[0]) {return 0;}
|
||||
return a[0] < b[0] ? -1 : 1;
|
||||
});
|
||||
sorted.reverse();
|
||||
let classes = [];
|
||||
for (let i = 0; i < topK; ++i) {
|
||||
let prob = sorted[i][0];
|
||||
let index = sorted[i][1];
|
||||
let c = {
|
||||
label: labels[index],
|
||||
prob: (prob * 100).toFixed(2)
|
||||
}
|
||||
classes.push(c);
|
||||
}
|
||||
return classes;
|
||||
}
|
||||
|
||||
loadImageToCanvas = function(e, canvasId) {
|
||||
let files = e.target.files;
|
||||
let imgUrl = URL.createObjectURL(files[0]);
|
||||
let canvas = document.getElementById(canvasId);
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = imgUrl;
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
}
|
||||
|
||||
drawInfoTable = async function(jsonUrl, divId) {
|
||||
let response = await fetch(jsonUrl);
|
||||
let json = await response.json();
|
||||
|
||||
let appendix = document.getElementById(divId);
|
||||
for (key of Object.keys(json)) {
|
||||
let h3 = document.createElement('h3');
|
||||
h3.textContent = key + " model";
|
||||
appendix.appendChild(h3);
|
||||
|
||||
let table = document.createElement('table');
|
||||
let head_tr = document.createElement('tr');
|
||||
for (head of Object.keys(json[key][0])) {
|
||||
let th = document.createElement('th');
|
||||
th.textContent = head;
|
||||
th.style.border = "1px solid black";
|
||||
head_tr.appendChild(th);
|
||||
}
|
||||
table.appendChild(head_tr)
|
||||
|
||||
for (model of json[key]) {
|
||||
let tr = document.createElement('tr');
|
||||
for (params of Object.keys(model)) {
|
||||
let td = document.createElement('td');
|
||||
td.style.border = "1px solid black";
|
||||
if (params !== "modelUrl" && params !== "configUrl" && params !== "labelsUrl") {
|
||||
td.textContent = model[params];
|
||||
tr.appendChild(td);
|
||||
} else {
|
||||
let a = document.createElement('a');
|
||||
let link = document.createTextNode('link');
|
||||
a.append(link);
|
||||
a.href = model[params];
|
||||
td.appendChild(a);
|
||||
tr.appendChild(td);
|
||||
}
|
||||
}
|
||||
table.appendChild(tr);
|
||||
}
|
||||
table.style.width = "800px";
|
||||
table.style.borderCollapse = "collapse";
|
||||
appendix.appendChild(table);
|
||||
}
|
||||
}
|
263
doc/js_tutorials/js_assets/js_image_classification.html
Normal file
263
doc/js_tutorials/js_assets/js_image_classification.html
Normal file
@ -0,0 +1,263 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Image Classification Example</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Image Classification Example</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an image classification example with OpenCV.js.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configFile</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="tryIt" disabled>Try it</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="canvasInput" width="400" height="400"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<table style="visibility: hidden;" id="result">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col" width=300>Label</th>
|
||||
<th scope="col">Probability</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">1</th>
|
||||
<td id="label0" align="center"></td>
|
||||
<td id="prob0" align="center"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">2</th>
|
||||
<td id="label1" align="center"></td>
|
||||
<td id="prob1" align="center"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">3</th>
|
||||
<td id="label2" align="center"></td>
|
||||
<td id="prob2" align="center"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="13" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.Main loop in which will read the image from canvas and do inference once.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Load labels from txt file and process it into an array.</p>
|
||||
<textarea class="code" rows="7" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
<p>6.The post-processing, including softmax if needed and get the top classes from the output vector.</p>
|
||||
<textarea class="code" rows="35" cols="100" id="codeEditor5" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [224,224];
|
||||
mean = [104, 117, 123];
|
||||
std = 1;
|
||||
swapRB = false;
|
||||
|
||||
// record if need softmax function for post-processing
|
||||
needSoftmax = false;
|
||||
|
||||
// url for label file, can from local or Internet
|
||||
labelsUrl = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt";
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
main = async function() {
|
||||
const labels = await loadLables(labelsUrl);
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const probs = softmax(result);
|
||||
const classes = getTopClasses(probs, labels);
|
||||
|
||||
updateResult(classes, time);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet5" type="text/code-snippet">
|
||||
softmax = function(result) {
|
||||
let arr = result.data32F;
|
||||
if (needSoftmax) {
|
||||
const maxNum = Math.max(...arr);
|
||||
const expSum = arr.map((num) => Math.exp(num - maxNum)).reduce((a, b) => a + b);
|
||||
return arr.map((value, index) => {
|
||||
return Math.exp(value - maxNum) / expSum;
|
||||
});
|
||||
} else {
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_image_classification_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let loadLablesCode = 'loadLables = ' + loadLables.toString();
|
||||
document.getElementById('codeEditor2').value = loadLablesCode;
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor3').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor4').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet5', 'codeEditor5');
|
||||
let getTopClassesCode = 'getTopClasses = ' + getTopClasses.toString();
|
||||
document.getElementById('codeEditor5').value += '\n' + '\n' + getTopClassesCode;
|
||||
|
||||
let canvas = document.getElementById('canvasInput');
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = 'space_shuttle.jpg';
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
let tryIt = document.getElementById('tryIt');
|
||||
tryIt.addEventListener('click', () => {
|
||||
initStatus();
|
||||
document.getElementById('status').innerHTML = 'Running function main()...';
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
if (modelPath === "") {
|
||||
document.getElementById('status').innerHTML = 'Runing failed.';
|
||||
utils.printError('Please upload model file by clicking the button first.');
|
||||
} else {
|
||||
setTimeout(main, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
initStatus();
|
||||
loadImageToCanvas(e, 'canvasInput');
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
tryIt.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function() {};
|
||||
var softmax = function(result){};
|
||||
var getTopClasses = function(mat, labels, topK = 3){};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
utils.executeCode('codeEditor5');
|
||||
|
||||
function updateResult(classes, time) {
|
||||
try{
|
||||
classes.forEach((c,i) => {
|
||||
let labelElement = document.getElementById('label'+i);
|
||||
let probElement = document.getElementById('prob'+i);
|
||||
labelElement.innerHTML = c.label;
|
||||
probElement.innerHTML = c.prob + '%';
|
||||
});
|
||||
let result = document.getElementById('result');
|
||||
result.style.visibility = 'visible';
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('result').style.visibility = 'hidden';
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,65 @@
|
||||
{
|
||||
"caffe": [
|
||||
{
|
||||
"model": "alexnet",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"needSoftmax": "false",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt",
|
||||
"modelUrl": "http://dl.caffe.berkeleyvision.org/bvlc_alexnet.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/BVLC/caffe/master/models/bvlc_alexnet/deploy.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "densenet",
|
||||
"mean": "127.5, 127.5, 127.5",
|
||||
"std": "0.007843",
|
||||
"swapRB": "false",
|
||||
"needSoftmax": "true",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt",
|
||||
"modelUrl": "https://drive.google.com/open?id=0B7ubpZO7HnlCcHlfNmJkU2VPelE",
|
||||
"configUrl": "https://raw.githubusercontent.com/shicai/DenseNet-Caffe/master/DenseNet_121.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "googlenet",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"needSoftmax": "false",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt",
|
||||
"modelUrl": "http://dl.caffe.berkeleyvision.org/bvlc_googlenet.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/BVLC/caffe/master/models/bvlc_googlenet/deploy.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "squeezenet",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"needSoftmax": "false",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt",
|
||||
"modelUrl": "https://raw.githubusercontent.com/forresti/SqueezeNet/master/SqueezeNet_v1.0/squeezenet_v1.0.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/forresti/SqueezeNet/master/SqueezeNet_v1.0/deploy.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "VGG",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"needSoftmax": "false",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt",
|
||||
"modelUrl": "http://www.robots.ox.ac.uk/~vgg/software/very_deep/caffe/VGG_ILSVRC_19_layers.caffemodel",
|
||||
"configUrl": "https://gist.githubusercontent.com/ksimonyan/3785162f95cd2d5fee77/raw/f02f8769e64494bcd3d7e97d5d747ac275825721/VGG_ILSVRC_19_layers_deploy.prototxt"
|
||||
}
|
||||
],
|
||||
"tensorflow": [
|
||||
{
|
||||
"model": "inception",
|
||||
"mean": "123, 117, 104",
|
||||
"std": "1",
|
||||
"swapRB": "true",
|
||||
"needSoftmax": "false",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/petewarden/tf_ios_makefile_example/master/data/imagenet_comp_graph_label_strings.txt",
|
||||
"modelUrl": "https://raw.githubusercontent.com/petewarden/tf_ios_makefile_example/master/data/tensorflow_inception_graph.pb"
|
||||
}
|
||||
]
|
||||
}
|
@ -0,0 +1,281 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Image Classification Example with Camera</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Image Classification Example with Camera</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an image classification example with camera.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configFile</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Start/Stop</b> button to start or stop the camera capture.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="startAndStop" disabled>Start</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<video id="videoInput" width="400" height="400"></video>
|
||||
</td>
|
||||
<td>
|
||||
<table style="visibility: hidden;" id="result">
|
||||
<thead>
|
||||
<tr>
|
||||
<th scope="col">#</th>
|
||||
<th scope="col" width=300>Label</th>
|
||||
<th scope="col">Probability</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<th scope="row">1</th>
|
||||
<td id="label0" align="center"></td>
|
||||
<td id="prob0" align="center"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">2</th>
|
||||
<td id="label1" align="center"></td>
|
||||
<td id="prob1" align="center"></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th scope="row">3</th>
|
||||
<td id="label2" align="center"></td>
|
||||
<td id="prob2" align="center"></td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
videoInput
|
||||
</div>
|
||||
</td>
|
||||
<td></td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="13" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.The function to capture video from camera, and the main loop in which will do inference once.</p>
|
||||
<textarea class="code" rows="35" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Load labels from txt file and process it into an array.</p>
|
||||
<textarea class="code" rows="7" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
<p>6.The post-processing, including softmax if needed and get the top classes from the output vector.</p>
|
||||
<textarea class="code" rows="35" cols="100" id="codeEditor5" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [224,224];
|
||||
mean = [104, 117, 123];
|
||||
std = 1;
|
||||
swapRB = false;
|
||||
|
||||
// record if need softmax function for post-processing
|
||||
needSoftmax = false;
|
||||
|
||||
// url for label file, can from local or Internet
|
||||
labelsUrl = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/classification_classes_ILSVRC2012.txt";
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
let frame = new cv.Mat(video.height, video.width, cv.CV_8UC4);
|
||||
let cap = new cv.VideoCapture(video);
|
||||
|
||||
main = async function(frame) {
|
||||
const labels = await loadLables(labelsUrl);
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, frame);
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const probs = softmax(result);
|
||||
const classes = getTopClasses(probs, labels);
|
||||
|
||||
updateResult(classes, time);
|
||||
setTimeout(processVideo, 0);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
|
||||
function processVideo() {
|
||||
try {
|
||||
if (!streaming) {
|
||||
return;
|
||||
}
|
||||
cap.read(frame);
|
||||
main(frame);
|
||||
} catch (err) {
|
||||
utils.printError(err);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(processVideo, 0);
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet5" type="text/code-snippet">
|
||||
softmax = function(result) {
|
||||
let arr = result.data32F;
|
||||
if (needSoftmax) {
|
||||
const maxNum = Math.max(...arr);
|
||||
const expSum = arr.map((num) => Math.exp(num - maxNum)).reduce((a, b) => a + b);
|
||||
return arr.map((value, index) => {
|
||||
return Math.exp(value - maxNum) / expSum;
|
||||
});
|
||||
} else {
|
||||
return arr;
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_image_classification_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let loadLablesCode = 'loadLables = ' + loadLables.toString();
|
||||
document.getElementById('codeEditor2').value = loadLablesCode;
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor3').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor4').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet5', 'codeEditor5');
|
||||
let getTopClassesCode = 'getTopClasses = ' + getTopClasses.toString();
|
||||
document.getElementById('codeEditor5').value += '\n' + '\n' + getTopClassesCode;
|
||||
|
||||
let video = document.getElementById('videoInput');
|
||||
let streaming = false;
|
||||
let startAndStop = document.getElementById('startAndStop');
|
||||
startAndStop.addEventListener('click', () => {
|
||||
if (!streaming) {
|
||||
utils.clearError();
|
||||
utils.startCamera('qvga', onVideoStarted, 'videoInput');
|
||||
} else {
|
||||
utils.stopCamera();
|
||||
onVideoStopped();
|
||||
}
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
startAndStop.removeAttribute('disabled');
|
||||
|
||||
});
|
||||
|
||||
var main = async function(frame) {};
|
||||
var softmax = function(result){};
|
||||
var getTopClasses = function(mat, labels, topK = 3){};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
utils.executeCode('codeEditor5');
|
||||
|
||||
function onVideoStarted() {
|
||||
streaming = true;
|
||||
startAndStop.innerText = 'Stop';
|
||||
videoInput.width = videoInput.videoWidth;
|
||||
videoInput.height = videoInput.videoHeight;
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
}
|
||||
|
||||
function onVideoStopped() {
|
||||
streaming = false;
|
||||
startAndStop.innerText = 'Start';
|
||||
initStatus();
|
||||
}
|
||||
|
||||
function updateResult(classes, time) {
|
||||
try{
|
||||
classes.forEach((c,i) => {
|
||||
let labelElement = document.getElementById('label'+i);
|
||||
let probElement = document.getElementById('prob'+i);
|
||||
labelElement.innerHTML = c.label;
|
||||
probElement.innerHTML = c.prob + '%';
|
||||
});
|
||||
let result = document.getElementById('result');
|
||||
result.style.visibility = 'visible';
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('result').style.visibility = 'hidden';
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
387
doc/js_tutorials/js_assets/js_object_detection.html
Normal file
387
doc/js_tutorials/js_assets/js_object_detection.html
Normal file
@ -0,0 +1,387 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Object Detection Example</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Object Detection Example</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an object detection example with OpenCV.js.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configFile</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="tryIt" disabled>Try it</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="canvasInput" width="400" height="400"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas id="canvasOutput" style="visibility: hidden;" width="400" height="400"></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile" name="file">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="15" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.Main loop in which will read the image from canvas and do inference once.</p>
|
||||
<textarea class="code" rows="16" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Load labels from txt file and process it into an array.</p>
|
||||
<textarea class="code" rows="7" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
<p>6.The post-processing, including get boxes from output and draw boxes into the image.</p>
|
||||
<textarea class="code" rows="35" cols="100" id="codeEditor5" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [300, 300];
|
||||
mean = [127.5, 127.5, 127.5];
|
||||
std = 0.007843;
|
||||
swapRB = false;
|
||||
confThreshold = 0.5;
|
||||
nmsThreshold = 0.4;
|
||||
|
||||
// The type of output, can be YOLO or SSD
|
||||
outType = "SSD";
|
||||
|
||||
// url for label file, can from local or Internet
|
||||
labelsUrl = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/object_detection_classes_pascal_voc.txt";
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
main = async function() {
|
||||
const labels = await loadLables(labelsUrl);
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const output = postProcess(result, labels);
|
||||
|
||||
updateResult(output, time);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet5" type="text/code-snippet">
|
||||
postProcess = function(result, labels) {
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
const outputWidth = canvasOutput.width;
|
||||
const outputHeight = canvasOutput.height;
|
||||
const resultData = result.data32F;
|
||||
|
||||
// Get the boxes(with class and confidence) from the output
|
||||
let boxes = [];
|
||||
switch(outType) {
|
||||
case "YOLO": {
|
||||
const vecNum = result.matSize[0];
|
||||
const vecLength = result.matSize[1];
|
||||
const classNum = vecLength - 5;
|
||||
|
||||
for (let i = 0; i < vecNum; ++i) {
|
||||
let vector = resultData.slice(i*vecLength, (i+1)*vecLength);
|
||||
let scores = vector.slice(5, vecLength);
|
||||
let classId = scores.indexOf(Math.max(...scores));
|
||||
let confidence = scores[classId];
|
||||
if (confidence > confThreshold) {
|
||||
let center_x = Math.round(vector[0] * outputWidth);
|
||||
let center_y = Math.round(vector[1] * outputHeight);
|
||||
let width = Math.round(vector[2] * outputWidth);
|
||||
let height = Math.round(vector[3] * outputHeight);
|
||||
let left = Math.round(center_x - width / 2);
|
||||
let top = Math.round(center_y - height / 2);
|
||||
|
||||
let box = {
|
||||
scores: scores,
|
||||
classId: classId,
|
||||
confidence: confidence,
|
||||
bounding: [left, top, width, height],
|
||||
toDraw: true
|
||||
}
|
||||
boxes.push(box);
|
||||
}
|
||||
}
|
||||
|
||||
// NMS(Non Maximum Suppression) algorithm
|
||||
let boxNum = boxes.length;
|
||||
let tmp_boxes = [];
|
||||
let sorted_boxes = [];
|
||||
for (let c = 0; c < classNum; ++c) {
|
||||
for (let i = 0; i < boxes.length; ++i) {
|
||||
tmp_boxes[i] = [boxes[i], i];
|
||||
}
|
||||
sorted_boxes = tmp_boxes.sort((a, b) => { return (b[0].scores[c] - a[0].scores[c]); });
|
||||
for (let i = 0; i < boxNum; ++i) {
|
||||
if (sorted_boxes[i][0].scores[c] === 0) continue;
|
||||
else {
|
||||
for (let j = i + 1; j < boxNum; ++j) {
|
||||
if (IOU(sorted_boxes[i][0], sorted_boxes[j][0]) >= nmsThreshold) {
|
||||
boxes[sorted_boxes[j][1]].toDraw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case "SSD": {
|
||||
const vecNum = result.matSize[2];
|
||||
const vecLength = 7;
|
||||
|
||||
for (let i = 0; i < vecNum; ++i) {
|
||||
let vector = resultData.slice(i*vecLength, (i+1)*vecLength);
|
||||
let confidence = vector[2];
|
||||
if (confidence > confThreshold) {
|
||||
let left, top, right, bottom, width, height;
|
||||
left = Math.round(vector[3]);
|
||||
top = Math.round(vector[4]);
|
||||
right = Math.round(vector[5]);
|
||||
bottom = Math.round(vector[6]);
|
||||
width = right - left + 1;
|
||||
height = bottom - top + 1;
|
||||
if (width <= 2 || height <= 2) {
|
||||
left = Math.round(vector[3] * outputWidth);
|
||||
top = Math.round(vector[4] * outputHeight);
|
||||
right = Math.round(vector[5] * outputWidth);
|
||||
bottom = Math.round(vector[6] * outputHeight);
|
||||
width = right - left + 1;
|
||||
height = bottom - top + 1;
|
||||
}
|
||||
let box = {
|
||||
classId: vector[1] - 1,
|
||||
confidence: confidence,
|
||||
bounding: [left, top, width, height],
|
||||
toDraw: true
|
||||
}
|
||||
boxes.push(box);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
console.error(`Unsupported output type ${outType}`)
|
||||
}
|
||||
|
||||
// Draw the saved box into the image
|
||||
let image = cv.imread("canvasInput");
|
||||
let output = new cv.Mat(outputWidth, outputHeight, cv.CV_8UC3);
|
||||
cv.cvtColor(image, output, cv.COLOR_RGBA2RGB);
|
||||
let boxNum = boxes.length;
|
||||
for (let i = 0; i < boxNum; ++i) {
|
||||
if (boxes[i].toDraw) {
|
||||
drawBox(boxes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
|
||||
// Calculate the IOU(Intersection over Union) of two boxes
|
||||
function IOU(box1, box2) {
|
||||
let bounding1 = box1.bounding;
|
||||
let bounding2 = box2.bounding;
|
||||
let s1 = bounding1[2] * bounding1[3];
|
||||
let s2 = bounding2[2] * bounding2[3];
|
||||
|
||||
let left1 = bounding1[0];
|
||||
let right1 = left1 + bounding1[2];
|
||||
let left2 = bounding2[0];
|
||||
let right2 = left2 + bounding2[2];
|
||||
let overlapW = calOverlap([left1, right1], [left2, right2]);
|
||||
|
||||
let top1 = bounding2[1];
|
||||
let bottom1 = top1 + bounding1[3];
|
||||
let top2 = bounding2[1];
|
||||
let bottom2 = top2 + bounding2[3];
|
||||
let overlapH = calOverlap([top1, bottom1], [top2, bottom2]);
|
||||
|
||||
let overlapS = overlapW * overlapH;
|
||||
return overlapS / (s1 + s2 + overlapS);
|
||||
}
|
||||
|
||||
// Calculate the overlap range of two vector
|
||||
function calOverlap(range1, range2) {
|
||||
let min1 = range1[0];
|
||||
let max1 = range1[1];
|
||||
let min2 = range2[0];
|
||||
let max2 = range2[1];
|
||||
|
||||
if (min2 > min1 && min2 < max1) {
|
||||
return max1 - min2;
|
||||
} else if (max2 > min1 && max2 < max1) {
|
||||
return max2 - min1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw one predict box into the origin image
|
||||
function drawBox(box) {
|
||||
let bounding = box.bounding;
|
||||
let left = bounding[0];
|
||||
let top = bounding[1];
|
||||
let width = bounding[2];
|
||||
let height = bounding[3];
|
||||
|
||||
cv.rectangle(output, new cv.Point(left, top), new cv.Point(left + width, top + height),
|
||||
new cv.Scalar(0, 255, 0));
|
||||
cv.rectangle(output, new cv.Point(left, top), new cv.Point(left + width, top + 15),
|
||||
new cv.Scalar(255, 255, 255), cv.FILLED);
|
||||
let text = `${labels[box.classId]}: ${box.confidence.toFixed(4)}`;
|
||||
cv.putText(output, text, new cv.Point(left, top + 10), cv.FONT_HERSHEY_SIMPLEX, 0.3,
|
||||
new cv.Scalar(0, 0, 0));
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_object_detection_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let loadLablesCode = 'loadLables = ' + loadLables.toString();
|
||||
document.getElementById('codeEditor2').value = loadLablesCode;
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor3').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor4').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet5', 'codeEditor5');
|
||||
|
||||
let canvas = document.getElementById('canvasInput');
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = 'lena.png';
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
let tryIt = document.getElementById('tryIt');
|
||||
tryIt.addEventListener('click', () => {
|
||||
initStatus();
|
||||
document.getElementById('status').innerHTML = 'Running function main()...';
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
if (modelPath === "") {
|
||||
document.getElementById('status').innerHTML = 'Runing failed.';
|
||||
utils.printError('Please upload model file by clicking the button first.');
|
||||
} else {
|
||||
setTimeout(main, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
initStatus();
|
||||
loadImageToCanvas(e, 'canvasInput');
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
tryIt.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function() {};
|
||||
var postProcess = function(result, labels) {};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
utils.executeCode('codeEditor5');
|
||||
|
||||
|
||||
function updateResult(output, time) {
|
||||
try{
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
canvasOutput.style.visibility = "visible";
|
||||
cv.imshow('canvasOutput', output);
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('canvasOutput').style.visibility = "hidden";
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,39 @@
|
||||
{
|
||||
"caffe": [
|
||||
{
|
||||
"model": "mobilenet_SSD",
|
||||
"inputSize": "300, 300",
|
||||
"mean": "127.5, 127.5, 127.5",
|
||||
"std": "0.007843",
|
||||
"swapRB": "false",
|
||||
"outType": "SSD",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/object_detection_classes_pascal_voc.txt",
|
||||
"modelUrl": "https://raw.githubusercontent.com/chuanqi305/MobileNet-SSD/master/mobilenet_iter_73000.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/chuanqi305/MobileNet-SSD/master/deploy.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "VGG_SSD",
|
||||
"inputSize": "300, 300",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"outType": "SSD",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/object_detection_classes_pascal_voc.txt",
|
||||
"modelUrl": "https://drive.google.com/uc?id=0BzKzrI_SkD1_WVVTSmQxU0dVRzA&export=download",
|
||||
"configUrl": "https://drive.google.com/uc?id=0BzKzrI_SkD1_WVVTSmQxU0dVRzA&export=download"
|
||||
}
|
||||
],
|
||||
"darknet": [
|
||||
{
|
||||
"model": "yolov2_tiny",
|
||||
"inputSize": "416, 416",
|
||||
"mean": "0, 0, 0",
|
||||
"std": "0.00392",
|
||||
"swapRB": "false",
|
||||
"outType": "YOLO",
|
||||
"labelsUrl": "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/object_detection_classes_yolov3.txt",
|
||||
"modelUrl": "https://pjreddie.com/media/files/yolov2-tiny.weights",
|
||||
"configUrl": "https://raw.githubusercontent.com/pjreddie/darknet/master/cfg/yolov2-tiny.cfg"
|
||||
}
|
||||
]
|
||||
}
|
402
doc/js_tutorials/js_assets/js_object_detection_with_camera.html
Normal file
402
doc/js_tutorials/js_assets/js_object_detection_with_camera.html
Normal file
@ -0,0 +1,402 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Object Detection Example with Camera</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Object Detection Example with Camera </h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an object detection example with camera.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configInput</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Start/Stop</b> button to start or stop the camera capture.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="startAndStop" disabled>Start</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<video id="videoInput" width="400" height="400"></video>
|
||||
</td>
|
||||
<td>
|
||||
<canvas id="canvasOutput" style="visibility: hidden;" width="400" height="400"></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
videoInput
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile" name="file">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="15" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.The function to capture video from camera, and the main loop in which will do inference once.</p>
|
||||
<textarea class="code" rows="34" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Load labels from txt file and process it into an array.</p>
|
||||
<textarea class="code" rows="7" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
<p>6.The post-processing, including get boxes from output and draw boxes into the image.</p>
|
||||
<textarea class="code" rows="35" cols="100" id="codeEditor5" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [300, 300];
|
||||
mean = [127.5, 127.5, 127.5];
|
||||
std = 0.007843;
|
||||
swapRB = false;
|
||||
confThreshold = 0.5;
|
||||
nmsThreshold = 0.4;
|
||||
|
||||
// the type of output, can be YOLO or SSD
|
||||
outType = "SSD";
|
||||
|
||||
// url for label file, can from local or Internet
|
||||
labelsUrl = "https://raw.githubusercontent.com/opencv/opencv/master/samples/data/dnn/object_detection_classes_pascal_voc.txt";
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
let frame = new cv.Mat(videoInput.height, videoInput.width, cv.CV_8UC4);
|
||||
let cap = new cv.VideoCapture(videoInput);
|
||||
|
||||
main = async function(frame) {
|
||||
const labels = await loadLables(labelsUrl);
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, frame);
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const output = postProcess(result, labels, frame);
|
||||
|
||||
updateResult(output, time);
|
||||
setTimeout(processVideo, 0);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
|
||||
function processVideo() {
|
||||
try {
|
||||
if (!streaming) {
|
||||
return;
|
||||
}
|
||||
cap.read(frame);
|
||||
main(frame);
|
||||
} catch (err) {
|
||||
utils.printError(err);
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(processVideo, 0);
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet5" type="text/code-snippet">
|
||||
postProcess = function(result, labels, frame) {
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
const outputWidth = canvasOutput.width;
|
||||
const outputHeight = canvasOutput.height;
|
||||
const resultData = result.data32F;
|
||||
|
||||
// Get the boxes(with class and confidence) from the output
|
||||
let boxes = [];
|
||||
switch(outType) {
|
||||
case "YOLO": {
|
||||
const vecNum = result.matSize[0];
|
||||
const vecLength = result.matSize[1];
|
||||
const classNum = vecLength - 5;
|
||||
|
||||
for (let i = 0; i < vecNum; ++i) {
|
||||
let vector = resultData.slice(i*vecLength, (i+1)*vecLength);
|
||||
let scores = vector.slice(5, vecLength);
|
||||
let classId = scores.indexOf(Math.max(...scores));
|
||||
let confidence = scores[classId];
|
||||
if (confidence > confThreshold) {
|
||||
let center_x = Math.round(vector[0] * outputWidth);
|
||||
let center_y = Math.round(vector[1] * outputHeight);
|
||||
let width = Math.round(vector[2] * outputWidth);
|
||||
let height = Math.round(vector[3] * outputHeight);
|
||||
let left = Math.round(center_x - width / 2);
|
||||
let top = Math.round(center_y - height / 2);
|
||||
|
||||
let box = {
|
||||
scores: scores,
|
||||
classId: classId,
|
||||
confidence: confidence,
|
||||
bounding: [left, top, width, height],
|
||||
toDraw: true
|
||||
}
|
||||
boxes.push(box);
|
||||
}
|
||||
}
|
||||
|
||||
// NMS(Non Maximum Suppression) algorithm
|
||||
let boxNum = boxes.length;
|
||||
let tmp_boxes = [];
|
||||
let sorted_boxes = [];
|
||||
for (let c = 0; c < classNum; ++c) {
|
||||
for (let i = 0; i < boxes.length; ++i) {
|
||||
tmp_boxes[i] = [boxes[i], i];
|
||||
}
|
||||
sorted_boxes = tmp_boxes.sort((a, b) => { return (b[0].scores[c] - a[0].scores[c]); });
|
||||
for (let i = 0; i < boxNum; ++i) {
|
||||
if (sorted_boxes[i][0].scores[c] === 0) continue;
|
||||
else {
|
||||
for (let j = i + 1; j < boxNum; ++j) {
|
||||
if (IOU(sorted_boxes[i][0], sorted_boxes[j][0]) >= nmsThreshold) {
|
||||
boxes[sorted_boxes[j][1]].toDraw = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} break;
|
||||
case "SSD": {
|
||||
const vecNum = result.matSize[2];
|
||||
const vecLength = 7;
|
||||
|
||||
for (let i = 0; i < vecNum; ++i) {
|
||||
let vector = resultData.slice(i*vecLength, (i+1)*vecLength);
|
||||
let confidence = vector[2];
|
||||
if (confidence > confThreshold) {
|
||||
let left, top, right, bottom, width, height;
|
||||
left = Math.round(vector[3]);
|
||||
top = Math.round(vector[4]);
|
||||
right = Math.round(vector[5]);
|
||||
bottom = Math.round(vector[6]);
|
||||
width = right - left + 1;
|
||||
height = bottom - top + 1;
|
||||
if (width <= 2 || height <= 2) {
|
||||
left = Math.round(vector[3] * outputWidth);
|
||||
top = Math.round(vector[4] * outputHeight);
|
||||
right = Math.round(vector[5] * outputWidth);
|
||||
bottom = Math.round(vector[6] * outputHeight);
|
||||
width = right - left + 1;
|
||||
height = bottom - top + 1;
|
||||
}
|
||||
let box = {
|
||||
classId: vector[1] - 1,
|
||||
confidence: confidence,
|
||||
bounding: [left, top, width, height],
|
||||
toDraw: true
|
||||
}
|
||||
boxes.push(box);
|
||||
}
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
console.error(`Unsupported output type ${outType}`)
|
||||
}
|
||||
|
||||
// Draw the saved box into the image
|
||||
let output = new cv.Mat(outputWidth, outputHeight, cv.CV_8UC3);
|
||||
cv.cvtColor(frame, output, cv.COLOR_RGBA2RGB);
|
||||
let boxNum = boxes.length;
|
||||
for (let i = 0; i < boxNum; ++i) {
|
||||
if (boxes[i].toDraw) {
|
||||
drawBox(boxes[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
|
||||
|
||||
// Calculate the IOU(Intersection over Union) of two boxes
|
||||
function IOU(box1, box2) {
|
||||
let bounding1 = box1.bounding;
|
||||
let bounding2 = box2.bounding;
|
||||
let s1 = bounding1[2] * bounding1[3];
|
||||
let s2 = bounding2[2] * bounding2[3];
|
||||
|
||||
let left1 = bounding1[0];
|
||||
let right1 = left1 + bounding1[2];
|
||||
let left2 = bounding2[0];
|
||||
let right2 = left2 + bounding2[2];
|
||||
let overlapW = calOverlap([left1, right1], [left2, right2]);
|
||||
|
||||
let top1 = bounding2[1];
|
||||
let bottom1 = top1 + bounding1[3];
|
||||
let top2 = bounding2[1];
|
||||
let bottom2 = top2 + bounding2[3];
|
||||
let overlapH = calOverlap([top1, bottom1], [top2, bottom2]);
|
||||
|
||||
let overlapS = overlapW * overlapH;
|
||||
return overlapS / (s1 + s2 + overlapS);
|
||||
}
|
||||
|
||||
// Calculate the overlap range of two vector
|
||||
function calOverlap(range1, range2) {
|
||||
let min1 = range1[0];
|
||||
let max1 = range1[1];
|
||||
let min2 = range2[0];
|
||||
let max2 = range2[1];
|
||||
|
||||
if (min2 > min1 && min2 < max1) {
|
||||
return max1 - min2;
|
||||
} else if (max2 > min1 && max2 < max1) {
|
||||
return max2 - min1;
|
||||
} else {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Draw one predict box into the origin image
|
||||
function drawBox(box) {
|
||||
let bounding = box.bounding;
|
||||
let left = bounding[0];
|
||||
let top = bounding[1];
|
||||
let width = bounding[2];
|
||||
let height = bounding[3];
|
||||
|
||||
cv.rectangle(output, new cv.Point(left, top), new cv.Point(left + width, top + height),
|
||||
new cv.Scalar(0, 255, 0));
|
||||
cv.rectangle(output, new cv.Point(left, top), new cv.Point(left + width, top + 15),
|
||||
new cv.Scalar(255, 255, 255), cv.FILLED);
|
||||
let text = `${labels[box.classId]}: ${box.confidence.toFixed(4)}`;
|
||||
cv.putText(output, text, new cv.Point(left, top + 10), cv.FONT_HERSHEY_SIMPLEX, 0.3,
|
||||
new cv.Scalar(0, 0, 0));
|
||||
}
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_object_detection_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let loadLablesCode = 'loadLables = ' + loadLables.toString();
|
||||
document.getElementById('codeEditor2').value = loadLablesCode;
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor3').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor4').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet5', 'codeEditor5');
|
||||
|
||||
let videoInput = document.getElementById('videoInput');
|
||||
let streaming = false;
|
||||
let startAndStop = document.getElementById('startAndStop');
|
||||
startAndStop.addEventListener('click', () => {
|
||||
if (!streaming) {
|
||||
utils.clearError();
|
||||
utils.startCamera('qvga', onVideoStarted, 'videoInput');
|
||||
} else {
|
||||
utils.stopCamera();
|
||||
onVideoStopped();
|
||||
}
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
startAndStop.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function(frame) {};
|
||||
var postProcess = function(result, labels, frame) {};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
utils.executeCode('codeEditor5');
|
||||
|
||||
function onVideoStarted() {
|
||||
streaming = true;
|
||||
startAndStop.innerText = 'Stop';
|
||||
videoInput.width = videoInput.videoWidth;
|
||||
videoInput.height = videoInput.videoHeight;
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
}
|
||||
|
||||
function onVideoStopped() {
|
||||
streaming = false;
|
||||
startAndStop.innerText = 'Start';
|
||||
initStatus();
|
||||
}
|
||||
|
||||
function updateResult(output, time) {
|
||||
try{
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
canvasOutput.style.visibility = "visible";
|
||||
cv.imshow('canvasOutput', output);
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('canvasOutput').style.visibility = "hidden";
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
327
doc/js_tutorials/js_assets/js_pose_estimation.html
Normal file
327
doc/js_tutorials/js_assets/js_pose_estimation.html
Normal file
@ -0,0 +1,327 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Pose Estimation Example</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Pose Estimation Example</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an pose estimation example with OpenCV.js.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configInput</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="tryIt" disabled>Try it</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="canvasInput" width="400" height="250"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas id="canvasOutput" style="visibility: hidden;" width="400" height="250"></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile" name="file">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="9" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.Main loop in which will read the image from canvas and do inference once.</p>
|
||||
<textarea class="code" rows="15" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.The pairs of keypoints of different dataset.</p>
|
||||
<textarea class="code" rows="30" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
<p>6.The post-processing, including get the predicted points and draw lines into the image.</p>
|
||||
<textarea class="code" rows="30" cols="100" id="codeEditor5" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [368, 368];
|
||||
mean = [0, 0, 0];
|
||||
std = 0.00392;
|
||||
swapRB = false;
|
||||
threshold = 0.1;
|
||||
|
||||
// the pairs of keypoint, can be "COCO", "MPI" and "BODY_25"
|
||||
dataset = "COCO";
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
main = async function() {
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const output = postProcess(result);
|
||||
|
||||
updateResult(output, time);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet4" type="text/code-snippet">
|
||||
BODY_PARTS = {};
|
||||
POSE_PAIRS = [];
|
||||
|
||||
if (dataset === 'COCO') {
|
||||
BODY_PARTS = { "Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
|
||||
"LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
|
||||
"RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "REye": 14,
|
||||
"LEye": 15, "REar": 16, "LEar": 17, "Background": 18 };
|
||||
|
||||
POSE_PAIRS = [ ["Neck", "RShoulder"], ["Neck", "LShoulder"], ["RShoulder", "RElbow"],
|
||||
["RElbow", "RWrist"], ["LShoulder", "LElbow"], ["LElbow", "LWrist"],
|
||||
["Neck", "RHip"], ["RHip", "RKnee"], ["RKnee", "RAnkle"], ["Neck", "LHip"],
|
||||
["LHip", "LKnee"], ["LKnee", "LAnkle"], ["Neck", "Nose"], ["Nose", "REye"],
|
||||
["REye", "REar"], ["Nose", "LEye"], ["LEye", "LEar"] ]
|
||||
} else if (dataset === 'MPI') {
|
||||
BODY_PARTS = { "Head": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
|
||||
"LShoulder": 5, "LElbow": 6, "LWrist": 7, "RHip": 8, "RKnee": 9,
|
||||
"RAnkle": 10, "LHip": 11, "LKnee": 12, "LAnkle": 13, "Chest": 14,
|
||||
"Background": 15 }
|
||||
|
||||
POSE_PAIRS = [ ["Head", "Neck"], ["Neck", "RShoulder"], ["RShoulder", "RElbow"],
|
||||
["RElbow", "RWrist"], ["Neck", "LShoulder"], ["LShoulder", "LElbow"],
|
||||
["LElbow", "LWrist"], ["Neck", "Chest"], ["Chest", "RHip"], ["RHip", "RKnee"],
|
||||
["RKnee", "RAnkle"], ["Chest", "LHip"], ["LHip", "LKnee"], ["LKnee", "LAnkle"] ]
|
||||
} else if (dataset === 'BODY_25') {
|
||||
BODY_PARTS = { "Nose": 0, "Neck": 1, "RShoulder": 2, "RElbow": 3, "RWrist": 4,
|
||||
"LShoulder": 5, "LElbow": 6, "LWrist": 7, "MidHip": 8, "RHip": 9,
|
||||
"RKnee": 10, "RAnkle": 11, "LHip": 12, "LKnee": 13, "LAnkle": 14,
|
||||
"REye": 15, "LEye": 16, "REar": 17, "LEar": 18, "LBigToe": 19,
|
||||
"LSmallToe": 20, "LHeel": 21, "RBigToe": 22, "RSmallToe": 23,
|
||||
"RHeel": 24, "Background": 25 }
|
||||
|
||||
POSE_PAIRS = [ ["Neck", "Nose"], ["Neck", "RShoulder"],
|
||||
["Neck", "LShoulder"], ["RShoulder", "RElbow"],
|
||||
["RElbow", "RWrist"], ["LShoulder", "LElbow"],
|
||||
["LElbow", "LWrist"], ["Nose", "REye"],
|
||||
["REye", "REar"], ["Neck", "LEye"],
|
||||
["LEye", "LEar"], ["Neck", "MidHip"],
|
||||
["MidHip", "RHip"], ["RHip", "RKnee"],
|
||||
["RKnee", "RAnkle"], ["RAnkle", "RBigToe"],
|
||||
["RBigToe", "RSmallToe"], ["RAnkle", "RHeel"],
|
||||
["MidHip", "LHip"], ["LHip", "LKnee"],
|
||||
["LKnee", "LAnkle"], ["LAnkle", "LBigToe"],
|
||||
["LBigToe", "LSmallToe"], ["LAnkle", "LHeel"] ]
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet5" type="text/code-snippet">
|
||||
postProcess = function(result) {
|
||||
const resultData = result.data32F;
|
||||
const matSize = result.matSize;
|
||||
const size1 = matSize[1];
|
||||
const size2 = matSize[2];
|
||||
const size3 = matSize[3];
|
||||
const mapSize = size2 * size3;
|
||||
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
const outputWidth = canvasOutput.width;
|
||||
const outputHeight = canvasOutput.height;
|
||||
|
||||
let image = cv.imread("canvasInput");
|
||||
let output = new cv.Mat(outputWidth, outputHeight, cv.CV_8UC3);
|
||||
cv.cvtColor(image, output, cv.COLOR_RGBA2RGB);
|
||||
|
||||
// get position of keypoints from output
|
||||
let points = [];
|
||||
for (let i = 0; i < Object.keys(BODY_PARTS).length; ++i) {
|
||||
heatMap = resultData.slice(i*mapSize, (i+1)*mapSize);
|
||||
|
||||
let maxIndex = 0;
|
||||
let maxConf = heatMap[0];
|
||||
for (index in heatMap) {
|
||||
if (heatMap[index] > heatMap[maxIndex]) {
|
||||
maxIndex = index;
|
||||
maxConf = heatMap[index];
|
||||
}
|
||||
}
|
||||
|
||||
if (maxConf > threshold) {
|
||||
indexX = maxIndex % size3;
|
||||
indexY = maxIndex / size3;
|
||||
|
||||
x = outputWidth * indexX / size3;
|
||||
y = outputHeight * indexY / size2;
|
||||
|
||||
points[i] = [Math.round(x), Math.round(y)];
|
||||
}
|
||||
}
|
||||
|
||||
// draw the points and lines into the image
|
||||
for (pair of POSE_PAIRS) {
|
||||
partFrom = pair[0];
|
||||
partTo = pair[1];
|
||||
idFrom = BODY_PARTS[partFrom];
|
||||
idTo = BODY_PARTS[partTo];
|
||||
pointFrom = points[idFrom];
|
||||
pointTo = points[idTo];
|
||||
|
||||
if (points[idFrom] && points[idTo]) {
|
||||
cv.line(output, new cv.Point(pointFrom[0], pointFrom[1]),
|
||||
new cv.Point(pointTo[0], pointTo[1]), new cv.Scalar(0, 255, 0), 3);
|
||||
cv.ellipse(output, new cv.Point(pointFrom[0], pointFrom[1]), new cv.Size(3, 3), 0, 0, 360,
|
||||
new cv.Scalar(0, 0, 255), cv.FILLED);
|
||||
cv.ellipse(output, new cv.Point(pointTo[0], pointTo[1]), new cv.Size(3, 3), 0, 0, 360,
|
||||
new cv.Scalar(0, 0, 255), cv.FILLED);
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_pose_estimation_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor2').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor3').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet4', 'codeEditor4');
|
||||
utils.loadCode('codeSnippet5', 'codeEditor5');
|
||||
|
||||
let canvas = document.getElementById('canvasInput');
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = 'roi.jpg';
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
let tryIt = document.getElementById('tryIt');
|
||||
tryIt.addEventListener('click', () => {
|
||||
initStatus();
|
||||
document.getElementById('status').innerHTML = 'Running function main()...';
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
if (modelPath === "") {
|
||||
document.getElementById('status').innerHTML = 'Runing failed.';
|
||||
utils.printError('Please upload model file by clicking the button first.');
|
||||
} else {
|
||||
setTimeout(main, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
initStatus();
|
||||
loadImageToCanvas(e, 'canvasInput');
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
tryIt.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function() {};
|
||||
var postProcess = function(result) {};
|
||||
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
utils.executeCode('codeEditor5');
|
||||
|
||||
function updateResult(output, time) {
|
||||
try{
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
canvasOutput.style.visibility = "visible";
|
||||
let resized = new cv.Mat(canvasOutput.width, canvasOutput.height, cv.CV_8UC4);
|
||||
cv.resize(output, resized, new cv.Size(canvasOutput.width, canvasOutput.height));
|
||||
cv.imshow('canvasOutput', resized);
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('canvasOutput').style.visibility = "hidden";
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,34 @@
|
||||
{
|
||||
"caffe": [
|
||||
{
|
||||
"model": "body_25",
|
||||
"inputSize": "368, 368",
|
||||
"mean": "0, 0, 0",
|
||||
"std": "0.00392",
|
||||
"swapRB": "false",
|
||||
"dataset": "BODY_25",
|
||||
"modelUrl": "http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/body_25/pose_iter_584000.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/pose/body_25/pose_deploy.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "coco",
|
||||
"inputSize": "368, 368",
|
||||
"mean": "0, 0, 0",
|
||||
"std": "0.00392",
|
||||
"swapRB": "false",
|
||||
"dataset": "COCO",
|
||||
"modelUrl": "http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/coco/pose_iter_440000.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/pose/coco/pose_deploy_linevec.prototxt"
|
||||
},
|
||||
{
|
||||
"model": "mpi",
|
||||
"inputSize": "368, 368",
|
||||
"mean": "0, 0, 0",
|
||||
"std": "0.00392",
|
||||
"swapRB": "false",
|
||||
"dataset": "MPI",
|
||||
"modelUrl": "http://posefs1.perception.cs.cmu.edu/OpenPose/models/pose/mpi/pose_iter_160000.caffemodel",
|
||||
"configUrl": "https://raw.githubusercontent.com/CMU-Perceptual-Computing-Lab/openpose/master/models/pose/mpi/pose_deploy_linevec.prototxt"
|
||||
}
|
||||
]
|
||||
}
|
243
doc/js_tutorials/js_assets/js_semantic_segmentation.html
Normal file
243
doc/js_tutorials/js_assets/js_semantic_segmentation.html
Normal file
@ -0,0 +1,243 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Semantic Segmentation Example</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Semantic Segmentation Example</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an semantic segmentation example with OpenCV.js.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configInput</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="tryIt" disabled>Try it</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="canvasInput" width="400" height="400"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas id="canvasOutput" style="visibility: hidden;" width="400" height="400"></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile" name="file">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="5" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.Main loop in which will read the image from canvas and do inference once.</p>
|
||||
<textarea class="code" rows="16" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.The post-processing, including gengerate colors for different classes and argmax to get the classes for each pixel.</p>
|
||||
<textarea class="code" rows="34" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [513, 513];
|
||||
mean = [127.5, 127.5, 127.5];
|
||||
std = 0.007843;
|
||||
swapRB = false;
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
main = async function() {
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const colors = generateColors(result);
|
||||
const output = argmax(result, colors);
|
||||
|
||||
updateResult(output, time);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet4" type="text/code-snippet">
|
||||
generateColors = function(result) {
|
||||
const numClasses = result.matSize[1];
|
||||
let colors = [0,0,0];
|
||||
while(colors.length < numClasses*3){
|
||||
colors.push(Math.round((Math.random()*255 + colors[colors.length-3]) / 2));
|
||||
}
|
||||
return colors;
|
||||
}
|
||||
|
||||
argmax = function(result, colors) {
|
||||
const C = result.matSize[1];
|
||||
const H = result.matSize[2];
|
||||
const W = result.matSize[3];
|
||||
const resultData = result.data32F;
|
||||
const imgSize = H*W;
|
||||
|
||||
let classId = [];
|
||||
for (i = 0; i<imgSize; ++i) {
|
||||
let id = 0;
|
||||
for (j = 0; j < C; ++j) {
|
||||
if (resultData[j*imgSize+i] > resultData[id*imgSize+i]) {
|
||||
id = j;
|
||||
}
|
||||
}
|
||||
classId.push(colors[id*3]);
|
||||
classId.push(colors[id*3+1]);
|
||||
classId.push(colors[id*3+2]);
|
||||
classId.push(255);
|
||||
}
|
||||
|
||||
output = cv.matFromArray(H,W,cv.CV_8UC4,classId);
|
||||
return output;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_semantic_segmentation_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor2').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor3').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet4', 'codeEditor4');
|
||||
|
||||
let canvas = document.getElementById('canvasInput');
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = 'roi.jpg';
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
let tryIt = document.getElementById('tryIt');
|
||||
tryIt.addEventListener('click', () => {
|
||||
initStatus();
|
||||
document.getElementById('status').innerHTML = 'Running function main()...';
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
if (modelPath === "") {
|
||||
document.getElementById('status').innerHTML = 'Runing failed.';
|
||||
utils.printError('Please upload model file by clicking the button first.');
|
||||
} else {
|
||||
setTimeout(main, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
initStatus();
|
||||
loadImageToCanvas(e, 'canvasInput');
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
tryIt.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function() {};
|
||||
var generateColors = function(result) {};
|
||||
var argmax = function(result, colors) {};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
|
||||
function updateResult(output, time) {
|
||||
try{
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
canvasOutput.style.visibility = "visible";
|
||||
let resized = new cv.Mat(canvasOutput.width, canvasOutput.height, cv.CV_8UC4);
|
||||
cv.resize(output, resized, new cv.Size(canvasOutput.width, canvasOutput.height));
|
||||
cv.imshow('canvasOutput', resized);
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('canvasOutput').style.visibility = "hidden";
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
@ -0,0 +1,12 @@
|
||||
{
|
||||
"tensorflow": [
|
||||
{
|
||||
"model": "deeplabv3",
|
||||
"inputSize": "513, 513",
|
||||
"mean": "127.5, 127.5, 127.5",
|
||||
"std": "0.007843",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://drive.google.com/uc?id=1v-hfGenaE9tiGOzo5qdgMNG_gqQ5-Xn4&export=download"
|
||||
}
|
||||
]
|
||||
}
|
228
doc/js_tutorials/js_assets/js_style_transfer.html
Normal file
228
doc/js_tutorials/js_assets/js_style_transfer.html
Normal file
@ -0,0 +1,228 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<title>Style Transfer Example</title>
|
||||
<link href="js_example_style.css" rel="stylesheet" type="text/css" />
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<h2>Style Transfer Example</h2>
|
||||
<p>
|
||||
This tutorial shows you how to write an style transfer example with OpenCV.js.<br>
|
||||
To try the example you should click the <b>modelFile</b> button(and <b>configFile</b> button if needed) to upload inference model.
|
||||
You can find the model URLs and parameters in the <a href="#appendix">model info</a> section.
|
||||
Then You should change the parameters in the first code snippet according to the uploaded model.
|
||||
Finally click <b>Try it</b> button to see the result. You can choose any other images.<br>
|
||||
</p>
|
||||
|
||||
<div class="control"><button id="tryIt" disabled>Try it</button></div>
|
||||
<div>
|
||||
<table cellpadding="0" cellspacing="0" width="0" border="0">
|
||||
<tr>
|
||||
<td>
|
||||
<canvas id="canvasInput" width="400" height="400"></canvas>
|
||||
</td>
|
||||
<td>
|
||||
<canvas id="canvasOutput" style="visibility: hidden;" width="400" height="400"></canvas>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
canvasInput <input type="file" id="fileInput" name="file" accept="image/*">
|
||||
</div>
|
||||
</td>
|
||||
<td>
|
||||
<p id='status' align="left"></p>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
modelFile <input type="file" id="modelFile" name="file">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>
|
||||
<div class="caption">
|
||||
configFile <input type="file" id="configFile">
|
||||
</div>
|
||||
</td>
|
||||
</tr>
|
||||
</table>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<p class="err" id="errorMessage"></p>
|
||||
</div>
|
||||
|
||||
<div>
|
||||
<h3>Help function</h3>
|
||||
<p>1.The parameters for model inference which you can modify to investigate more models.</p>
|
||||
<textarea class="code" rows="5" cols="100" id="codeEditor" spellcheck="false"></textarea>
|
||||
<p>2.Main loop in which will read the image from canvas and do inference once.</p>
|
||||
<textarea class="code" rows="15" cols="100" id="codeEditor1" spellcheck="false"></textarea>
|
||||
<p>3.Get blob from image as input for net, and standardize it with <b>mean</b> and <b>std</b>.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor2" spellcheck="false"></textarea>
|
||||
<p>4.Fetch model file and save to emscripten file system once click the input button.</p>
|
||||
<textarea class="code" rows="17" cols="100" id="codeEditor3" spellcheck="false"></textarea>
|
||||
<p>5.The post-processing, including scaling and reordering.</p>
|
||||
<textarea class="code" rows="21" cols="100" id="codeEditor4" spellcheck="false"></textarea>
|
||||
</div>
|
||||
|
||||
<div id="appendix">
|
||||
<h2>Model Info:</h2>
|
||||
</div>
|
||||
|
||||
<script src="utils.js" type="text/javascript"></script>
|
||||
<script src="js_dnn_example_helper.js" type="text/javascript"></script>
|
||||
|
||||
<script id="codeSnippet" type="text/code-snippet">
|
||||
inputSize = [224, 224];
|
||||
mean = [104, 117, 123];
|
||||
std = 1;
|
||||
swapRB = false;
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet1" type="text/code-snippet">
|
||||
main = async function() {
|
||||
const input = getBlobFromImage(inputSize, mean, std, swapRB, 'canvasInput');
|
||||
let net = cv.readNet(configPath, modelPath);
|
||||
net.setInput(input);
|
||||
const start = performance.now();
|
||||
const result = net.forward();
|
||||
const time = performance.now()-start;
|
||||
const output = postProcess(result);
|
||||
|
||||
updateResult(output, time);
|
||||
input.delete();
|
||||
net.delete();
|
||||
result.delete();
|
||||
}
|
||||
</script>
|
||||
|
||||
<script id="codeSnippet4" type="text/code-snippet">
|
||||
postProcess = function(result) {
|
||||
const resultData = result.data32F;
|
||||
const C = result.matSize[1];
|
||||
const H = result.matSize[2];
|
||||
const W = result.matSize[3];
|
||||
const mean = [104, 117, 123];
|
||||
|
||||
let normData = [];
|
||||
for (let h = 0; h < H; ++h) {
|
||||
for (let w = 0; w < W; ++w) {
|
||||
for (let c = 0; c < C; ++c) {
|
||||
normData.push(resultData[c*H*W + h*W + w] + mean[c]);
|
||||
}
|
||||
normData.push(255);
|
||||
}
|
||||
}
|
||||
|
||||
let output = new cv.matFromArray(H, W, cv.CV_8UC4, normData);
|
||||
return output;
|
||||
}
|
||||
</script>
|
||||
|
||||
<script type="text/javascript">
|
||||
let jsonUrl = "js_style_transfer_model_info.json";
|
||||
drawInfoTable(jsonUrl, 'appendix');
|
||||
|
||||
let utils = new Utils('errorMessage');
|
||||
utils.loadCode('codeSnippet', 'codeEditor');
|
||||
utils.loadCode('codeSnippet1', 'codeEditor1');
|
||||
|
||||
let getBlobFromImageCode = 'getBlobFromImage = ' + getBlobFromImage.toString();
|
||||
document.getElementById('codeEditor2').value = getBlobFromImageCode;
|
||||
let loadModelCode = 'loadModel = ' + loadModel.toString();
|
||||
document.getElementById('codeEditor3').value = loadModelCode;
|
||||
|
||||
utils.loadCode('codeSnippet4', 'codeEditor4');
|
||||
|
||||
let canvas = document.getElementById('canvasInput');
|
||||
let ctx = canvas.getContext('2d');
|
||||
let img = new Image();
|
||||
img.crossOrigin = 'anonymous';
|
||||
img.src = 'lena.png';
|
||||
img.onload = function() {
|
||||
ctx.drawImage(img, 0, 0, canvas.width, canvas.height);
|
||||
};
|
||||
|
||||
let tryIt = document.getElementById('tryIt');
|
||||
tryIt.addEventListener('click', () => {
|
||||
initStatus();
|
||||
document.getElementById('status').innerHTML = 'Running function main()...';
|
||||
utils.executeCode('codeEditor');
|
||||
utils.executeCode('codeEditor1');
|
||||
if (modelPath === "") {
|
||||
document.getElementById('status').innerHTML = 'Runing failed.';
|
||||
utils.printError('Please upload model file by clicking the button first.');
|
||||
} else {
|
||||
setTimeout(main, 1);
|
||||
}
|
||||
});
|
||||
|
||||
let fileInput = document.getElementById('fileInput');
|
||||
fileInput.addEventListener('change', (e) => {
|
||||
initStatus();
|
||||
loadImageToCanvas(e, 'canvasInput');
|
||||
});
|
||||
|
||||
let configPath = "";
|
||||
let configFile = document.getElementById('configFile');
|
||||
configFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
configPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The config file '${configPath}' is created successfully.`;
|
||||
});
|
||||
|
||||
let modelPath = "";
|
||||
let modelFile = document.getElementById('modelFile');
|
||||
modelFile.addEventListener('change', async (e) => {
|
||||
initStatus();
|
||||
modelPath = await loadModel(e);
|
||||
document.getElementById('status').innerHTML = `The model file '${modelPath}' is created successfully.`;
|
||||
configPath = "";
|
||||
configFile.value = "";
|
||||
});
|
||||
|
||||
utils.loadOpenCv(() => {
|
||||
tryIt.removeAttribute('disabled');
|
||||
});
|
||||
|
||||
var main = async function() {};
|
||||
var postProcess = function(result) {};
|
||||
|
||||
utils.executeCode('codeEditor1');
|
||||
utils.executeCode('codeEditor2');
|
||||
utils.executeCode('codeEditor3');
|
||||
utils.executeCode('codeEditor4');
|
||||
|
||||
function updateResult(output, time) {
|
||||
try{
|
||||
let canvasOutput = document.getElementById('canvasOutput');
|
||||
canvasOutput.style.visibility = "visible";
|
||||
let resized = new cv.Mat(canvasOutput.width, canvasOutput.height, cv.CV_8UC4);
|
||||
cv.resize(output, resized, new cv.Size(canvasOutput.width, canvasOutput.height));
|
||||
cv.imshow('canvasOutput', resized);
|
||||
document.getElementById('status').innerHTML = `<b>Model:</b> ${modelPath}<br>
|
||||
<b>Inference time:</b> ${time.toFixed(2)} ms`;
|
||||
} catch(e) {
|
||||
console.log(e);
|
||||
}
|
||||
}
|
||||
|
||||
function initStatus() {
|
||||
document.getElementById('status').innerHTML = '';
|
||||
document.getElementById('canvasOutput').style.visibility = "hidden";
|
||||
utils.clearError();
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
76
doc/js_tutorials/js_assets/js_style_transfer_model_info.json
Normal file
76
doc/js_tutorials/js_assets/js_style_transfer_model_info.json
Normal file
@ -0,0 +1,76 @@
|
||||
{
|
||||
"torch": [
|
||||
{
|
||||
"model": "candy.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/candy.t7"
|
||||
},
|
||||
{
|
||||
"model": "composition_vii.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//eccv16/composition_vii.t7"
|
||||
},
|
||||
{
|
||||
"model": "feathers.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/feathers.t7"
|
||||
},
|
||||
{
|
||||
"model": "la_muse.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/la_muse.t7"
|
||||
},
|
||||
{
|
||||
"model": "mosaic.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/mosaic.t7"
|
||||
},
|
||||
{
|
||||
"model": "starry_night.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//eccv16/starry_night.t7"
|
||||
},
|
||||
{
|
||||
"model": "the_scream.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/the_scream.t7"
|
||||
},
|
||||
{
|
||||
"model": "the_wave.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//eccv16/the_wave.t7"
|
||||
},
|
||||
{
|
||||
"model": "udnie.t7",
|
||||
"inputSize": "224, 224",
|
||||
"mean": "104, 117, 123",
|
||||
"std": "1",
|
||||
"swapRB": "false",
|
||||
"modelUrl": "https://cs.stanford.edu/people/jcjohns/fast-neural-style/models//instance_norm/udnie.t7"
|
||||
}
|
||||
]
|
||||
}
|
@ -7,7 +7,7 @@ function Utils(errorOutputId) { // eslint-disable-line no-unused-vars
|
||||
let script = document.createElement('script');
|
||||
script.setAttribute('async', '');
|
||||
script.setAttribute('type', 'text/javascript');
|
||||
script.addEventListener('load', () => {
|
||||
script.addEventListener('load', async () => {
|
||||
if (cv.getBuildInformation)
|
||||
{
|
||||
console.log(cv.getBuildInformation());
|
||||
@ -16,9 +16,15 @@ function Utils(errorOutputId) { // eslint-disable-line no-unused-vars
|
||||
else
|
||||
{
|
||||
// WASM
|
||||
cv['onRuntimeInitialized']=()=>{
|
||||
if (cv instanceof Promise) {
|
||||
cv = await cv;
|
||||
console.log(cv.getBuildInformation());
|
||||
onloadCallback();
|
||||
} else {
|
||||
cv['onRuntimeInitialized']=()=>{
|
||||
console.log(cv.getBuildInformation());
|
||||
onloadCallback();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
@ -0,0 +1,13 @@
|
||||
Image Classification Example {#tutorial_js_image_classification}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for image classification.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_image_classification.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,15 @@
|
||||
Image Classification Example with Camera {#tutorial_js_image_classification_with_camera}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for image classification example with camera.
|
||||
|
||||
@note If you don't know how to capture video from camera, please review @ref tutorial_js_video_display.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_image_classification_with_camera.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,13 @@
|
||||
Object Detection Example {#tutorial_js_object_detection}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for object detection.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_object_detection.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,13 @@
|
||||
Object Detection Example with Camera{#tutorial_js_object_detection_with_camera}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for object detection with camera.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_object_detection_with_camera.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,13 @@
|
||||
Pose Estimation Example {#tutorial_js_pose_estimation}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for pose estimation.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_pose_estimation.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,13 @@
|
||||
Semantic Segmentation Example {#tutorial_js_semantic_segmentation}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for semantic segmentation.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_semantic_segmentation.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
@ -0,0 +1,13 @@
|
||||
Style Transfer Example {#tutorial_js_style_transfer}
|
||||
=======================================
|
||||
|
||||
Goal
|
||||
----
|
||||
|
||||
- In this tutorial you will learn how to use OpenCV.js dnn module for style transfer.
|
||||
|
||||
\htmlonly
|
||||
<iframe src="../../js_style_transfer.html" width="100%"
|
||||
onload="this.style.height=this.contentDocument.body.scrollHeight +'px';">
|
||||
</iframe>
|
||||
\endhtmlonly
|
30
doc/js_tutorials/js_dnn/js_table_of_contents_dnn.markdown
Normal file
30
doc/js_tutorials/js_dnn/js_table_of_contents_dnn.markdown
Normal file
@ -0,0 +1,30 @@
|
||||
Deep Neural Networks (dnn module) {#tutorial_js_table_of_contents_dnn}
|
||||
============
|
||||
|
||||
- @subpage tutorial_js_image_classification
|
||||
|
||||
Image classification example
|
||||
|
||||
- @subpage tutorial_js_image_classification_with_camera
|
||||
|
||||
Image classification example with camera
|
||||
|
||||
- @subpage tutorial_js_object_detection
|
||||
|
||||
Object detection example
|
||||
|
||||
- @subpage tutorial_js_object_detection_with_camera
|
||||
|
||||
Object detection example with camera
|
||||
|
||||
- @subpage tutorial_js_semantic_segmentation
|
||||
|
||||
Semantic segmentation example
|
||||
|
||||
- @subpage tutorial_js_style_transfer
|
||||
|
||||
Style transfer example
|
||||
|
||||
- @subpage tutorial_js_pose_estimation
|
||||
|
||||
Pose estimation example
|
@ -26,3 +26,7 @@ OpenCV.js Tutorials {#tutorial_js_root}
|
||||
|
||||
In this section you
|
||||
will object detection techniques like face detection etc.
|
||||
|
||||
- @subpage tutorial_js_table_of_contents_dnn
|
||||
|
||||
These tutorials show how to use dnn module in JavaScript
|
||||
|
@ -109,7 +109,7 @@ const string NAME = source.substr(0, pAt) + argv[2][0] + ".avi"; // Form the n
|
||||
@code{.cpp}
|
||||
CV_FOURCC('P','I','M,'1') // this is an MPEG1 codec from the characters to integer
|
||||
@endcode
|
||||
If you pass for this argument minus one than a window will pop up at runtime that contains all
|
||||
If you pass for this argument minus one then a window will pop up at runtime that contains all
|
||||
the codec installed on your system and ask you to select the one to use:
|
||||
|
||||

|
||||
|
@ -91,7 +91,7 @@ respectively) by the same factor.
|
||||
|
||||
The joint rotation-translation matrix \f$[R|t]\f$ is the matrix product of a projective
|
||||
transformation and a homogeneous transformation. The 3-by-4 projective transformation maps 3D points
|
||||
represented in camera coordinates to 2D poins in the image plane and represented in normalized
|
||||
represented in camera coordinates to 2D points in the image plane and represented in normalized
|
||||
camera coordinates \f$x' = X_c / Z_c\f$ and \f$y' = Y_c / Z_c\f$:
|
||||
|
||||
\f[Z_c \begin{bmatrix}
|
||||
|
@ -153,9 +153,8 @@ void CV_ChessboardSubpixelTest::run( int )
|
||||
|
||||
vector<Point2f> test_corners;
|
||||
bool result = findChessboardCorners(chessboard_image, pattern_size, test_corners, 15);
|
||||
if(!result)
|
||||
if (!result && cvtest::debugLevel > 0)
|
||||
{
|
||||
#if 0
|
||||
ts->printf(cvtest::TS::LOG, "Warning: chessboard was not detected! Writing image to test.png\n");
|
||||
ts->printf(cvtest::TS::LOG, "Size = %d, %d\n", pattern_size.width, pattern_size.height);
|
||||
ts->printf(cvtest::TS::LOG, "Intrinsic params: fx = %f, fy = %f, cx = %f, cy = %f\n",
|
||||
@ -167,7 +166,9 @@ void CV_ChessboardSubpixelTest::run( int )
|
||||
distortion_coeffs_.at<double>(0, 4));
|
||||
|
||||
imwrite("test.png", chessboard_image);
|
||||
#endif
|
||||
}
|
||||
if (!result)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
|
@ -551,7 +551,10 @@ TEST_F(fisheyeTest, stereoRectify)
|
||||
<< "Q =" << std::endl << Q << std::endl;
|
||||
}
|
||||
|
||||
#if 1 // Debug code
|
||||
if (cvtest::debugLevel == 0)
|
||||
return;
|
||||
// DEBUG code is below
|
||||
|
||||
cv::Mat lmapx, lmapy, rmapx, rmapy;
|
||||
//rewrite for fisheye
|
||||
cv::fisheye::initUndistortRectifyMap(K1, D1, R1, P1, requested_size, CV_32F, lmapx, lmapy);
|
||||
@ -584,7 +587,6 @@ TEST_F(fisheyeTest, stereoRectify)
|
||||
|
||||
cv::imwrite(cv::format("fisheye_rectification_AB_%03d.png", i), rectification);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
TEST_F(fisheyeTest, stereoCalibrate)
|
||||
|
@ -2397,20 +2397,11 @@ public:
|
||||
UMat(const UMat& m, const Rect& roi);
|
||||
UMat(const UMat& m, const Range* ranges);
|
||||
UMat(const UMat& m, const std::vector<Range>& ranges);
|
||||
|
||||
// FIXIT copyData=false is not implemented, drop this in favor of cv::Mat (OpenCV 5.0)
|
||||
//! builds matrix from std::vector with or without copying the data
|
||||
template<typename _Tp> explicit UMat(const std::vector<_Tp>& vec, bool copyData=false);
|
||||
|
||||
//! builds matrix from cv::Vec; the data is copied by default
|
||||
template<typename _Tp, int n> explicit UMat(const Vec<_Tp, n>& vec, bool copyData=true);
|
||||
//! builds matrix from cv::Matx; the data is copied by default
|
||||
template<typename _Tp, int m, int n> explicit UMat(const Matx<_Tp, m, n>& mtx, bool copyData=true);
|
||||
//! builds matrix from a 2D point
|
||||
template<typename _Tp> explicit UMat(const Point_<_Tp>& pt, bool copyData=true);
|
||||
//! builds matrix from a 3D point
|
||||
template<typename _Tp> explicit UMat(const Point3_<_Tp>& pt, bool copyData=true);
|
||||
//! builds matrix from comma initializer
|
||||
template<typename _Tp> explicit UMat(const MatCommaInitializer_<_Tp>& commaInitializer);
|
||||
|
||||
//! destructor - calls release()
|
||||
~UMat();
|
||||
//! assignment operators
|
||||
|
@ -62,11 +62,9 @@ static bool ipp_countNonZero( Mat &src, int &res )
|
||||
{
|
||||
CV_INSTRUMENT_REGION_IPP();
|
||||
|
||||
#if defined __APPLE__ || (defined _MSC_VER && defined _M_IX86)
|
||||
// see https://github.com/opencv/opencv/issues/17453
|
||||
if (src.dims <= 2 && src.step > 520000)
|
||||
if (src.dims <= 2 && src.step > 520000 && cv::ipp::getIppTopFeatures() == ippCPUID_SSE42)
|
||||
return false;
|
||||
#endif
|
||||
|
||||
#if IPP_VERSION_X100 < 201801
|
||||
// Poor performance of SSE42
|
||||
|
@ -152,10 +152,10 @@ float normL2Sqr_(const float* a, const float* b, int n)
|
||||
{
|
||||
v_float32 t0 = vx_load(a + j) - vx_load(b + j);
|
||||
v_float32 t1 = vx_load(a + j + v_float32::nlanes) - vx_load(b + j + v_float32::nlanes);
|
||||
v_float32 t2 = vx_load(a + j + 2 * v_float32::nlanes) - vx_load(b + j + 2 * v_float32::nlanes);
|
||||
v_float32 t3 = vx_load(a + j + 3 * v_float32::nlanes) - vx_load(b + j + 3 * v_float32::nlanes);
|
||||
v_d0 = v_muladd(t0, t0, v_d0);
|
||||
v_float32 t2 = vx_load(a + j + 2 * v_float32::nlanes) - vx_load(b + j + 2 * v_float32::nlanes);
|
||||
v_d1 = v_muladd(t1, t1, v_d1);
|
||||
v_float32 t3 = vx_load(a + j + 3 * v_float32::nlanes) - vx_load(b + j + 3 * v_float32::nlanes);
|
||||
v_d2 = v_muladd(t2, t2, v_d2);
|
||||
v_d3 = v_muladd(t3, t3, v_d3);
|
||||
}
|
||||
|
@ -2365,6 +2365,13 @@ public:
|
||||
ippTopFeatures = ippCPUID_SSE42;
|
||||
|
||||
pIppLibInfo = ippiGetLibVersion();
|
||||
|
||||
// workaround: https://github.com/opencv/opencv/issues/12959
|
||||
std::string ippName(pIppLibInfo->Name ? pIppLibInfo->Name : "");
|
||||
if (ippName.find("SSE4.2") != std::string::npos)
|
||||
{
|
||||
ippTopFeatures = ippCPUID_SSE42;
|
||||
}
|
||||
}
|
||||
|
||||
public:
|
||||
@ -2396,16 +2403,12 @@ unsigned long long getIppFeatures()
|
||||
#endif
|
||||
}
|
||||
|
||||
unsigned long long getIppTopFeatures();
|
||||
|
||||
#ifdef HAVE_IPP
|
||||
unsigned long long getIppTopFeatures()
|
||||
{
|
||||
#ifdef HAVE_IPP
|
||||
return getIPPSingleton().ippTopFeatures;
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
#endif
|
||||
|
||||
void setIppStatus(int status, const char * const _funcname, const char * const _filename, int _line)
|
||||
{
|
||||
|
@ -535,7 +535,8 @@ protected:
|
||||
img->copyTo(sub);
|
||||
shift += img->size().height + 1;
|
||||
}
|
||||
//imwrite("/tmp/all_fonts.png", result);
|
||||
if (cvtest::debugLevel > 0)
|
||||
imwrite("all_fonts.png", result);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -1,13 +1,19 @@
|
||||
# ----------------------------------------------------------------------------
|
||||
# CMake file for js support
|
||||
# ----------------------------------------------------------------------------
|
||||
set(the_description "The js bindings")
|
||||
|
||||
if(NOT BUILD_opencv_js) # should be enabled explicitly (by build_js.py script)
|
||||
ocv_module_disable(js)
|
||||
if(OPENCV_INITIAL_PASS)
|
||||
# generator for Objective-C source code and documentation signatures
|
||||
add_subdirectory(generator)
|
||||
endif()
|
||||
|
||||
if(NOT BUILD_opencv_js) # should be enabled explicitly (by build_js.py script)
|
||||
return()
|
||||
endif()
|
||||
|
||||
set(the_description "The JavaScript(JS) bindings")
|
||||
|
||||
set(OPENCV_JS "opencv.js")
|
||||
set(JS_HELPER "${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.js")
|
||||
|
||||
find_path(EMSCRIPTEN_INCLUDE_DIR
|
||||
emscripten/bind.h
|
||||
@ -28,59 +34,18 @@ if(NOT EMSCRIPTEN_INCLUDE_DIR OR NOT PYTHON_DEFAULT_AVAILABLE)
|
||||
ocv_module_disable(js)
|
||||
endif()
|
||||
|
||||
ocv_add_module(js BINDINGS)
|
||||
ocv_add_module(js BINDINGS PRIVATE_REQUIRED opencv_js_bindings_generator)
|
||||
|
||||
ocv_module_include_directories(${EMSCRIPTEN_INCLUDE_DIR})
|
||||
|
||||
# get list of modules to wrap
|
||||
# message(STATUS "Wrapped in js:")
|
||||
set(OPENCV_JS_MODULES)
|
||||
foreach(m ${OPENCV_MODULES_BUILD})
|
||||
if(";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";js;" AND HAVE_${m})
|
||||
list(APPEND OPENCV_JS_MODULES ${m})
|
||||
# message(STATUS "\t${m}")
|
||||
endif()
|
||||
endforeach()
|
||||
|
||||
set(opencv_hdrs "")
|
||||
foreach(m ${OPENCV_JS_MODULES})
|
||||
list(APPEND opencv_hdrs ${OPENCV_MODULE_${m}_HEADERS})
|
||||
endforeach(m)
|
||||
|
||||
# header blacklist
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*.h$")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/opengl.hpp")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/ocl.hpp")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cudev")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker.hpp") # Conditional compilation
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/utils/.*")
|
||||
|
||||
file(WRITE "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}")
|
||||
|
||||
set(bindings_cpp "${CMAKE_CURRENT_BINARY_DIR}/bindings.cpp")
|
||||
|
||||
set(scripts_hdr_parser "${CMAKE_CURRENT_SOURCE_DIR}/../python/src2/hdr_parser.py")
|
||||
|
||||
set(JS_HELPER "${CMAKE_CURRENT_SOURCE_DIR}/src/helpers.js")
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${bindings_cpp}
|
||||
COMMAND ${PYTHON_DEFAULT_EXECUTABLE} "${CMAKE_CURRENT_SOURCE_DIR}/src/embindgen.py" ${scripts_hdr_parser} ${bindings_cpp} "${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${CMAKE_CURRENT_SOURCE_DIR}/src/core_bindings.cpp"
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/core_bindings.cpp
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/embindgen.py
|
||||
DEPENDS ${CMAKE_CURRENT_SOURCE_DIR}/src/templates.py
|
||||
DEPENDS ${scripts_hdr_parser}
|
||||
#(not needed - generated by CMake) DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
|
||||
DEPENDS ${opencv_hdrs}
|
||||
DEPENDS ${JS_HELPER})
|
||||
|
||||
add_definitions("-std=c++11")
|
||||
|
||||
link_libraries(${OPENCV_MODULE_${the_module}_DEPS})
|
||||
set(deps ${OPENCV_MODULE_${the_module}_DEPS})
|
||||
list(REMOVE_ITEM deps opencv_js_bindings_generator) # don't add dummy module
|
||||
link_libraries(${deps})
|
||||
|
||||
set(bindings_cpp "${OPENCV_JS_BINDINGS_DIR}/gen/bindings.cpp")
|
||||
set_source_files_properties(${bindings_cpp} PROPERTIES GENERATED TRUE)
|
||||
|
||||
OCV_OPTION(BUILD_WASM_INTRIN_TESTS "Build WASM intrin tests" OFF )
|
||||
if(BUILD_WASM_INTRIN_TESTS)
|
||||
@ -94,6 +59,8 @@ else()
|
||||
ocv_add_executable(${the_module} ${bindings_cpp})
|
||||
endif()
|
||||
|
||||
add_dependencies(${the_module} gen_opencv_js_source)
|
||||
|
||||
set(COMPILE_FLAGS "")
|
||||
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "MSVC")
|
||||
set(COMPILE_FLAGS "${COMPILE_FLAGS} -Wno-missing-prototypes")
|
||||
@ -101,6 +68,7 @@ endif()
|
||||
if(COMPILE_FLAGS)
|
||||
set_target_properties(${the_module} PROPERTIES COMPILE_FLAGS ${COMPILE_FLAGS})
|
||||
endif()
|
||||
|
||||
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} --memory-init-file 0 -s TOTAL_MEMORY=128MB -s WASM_MEM_MAX=1GB -s ALLOW_MEMORY_GROWTH=1")
|
||||
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s MODULARIZE=1 -s SINGLE_FILE=1")
|
||||
set(EMSCRIPTEN_LINK_FLAGS "${EMSCRIPTEN_LINK_FLAGS} -s EXPORT_NAME=\"'cv'\" -s DEMANGLE_SUPPORT=1")
|
||||
@ -155,7 +123,7 @@ add_custom_command(OUTPUT "${opencv_test_js_bin_dir}/${test_data}"
|
||||
)
|
||||
list(APPEND opencv_test_js_file_deps "${test_data_path}" "${opencv_test_js_bin_dir}/${test_data}")
|
||||
|
||||
add_custom_target(${PROJECT_NAME}_test ALL
|
||||
add_custom_target(${PROJECT_NAME}_test
|
||||
DEPENDS ${OCV_JS_PATH} ${opencv_test_js_file_deps})
|
||||
|
||||
# perf
|
||||
@ -178,7 +146,7 @@ foreach(f ${perf_files})
|
||||
list(APPEND opencv_perf_js_file_deps "${perf_dir}/${f}" "${opencv_perf_js_bin_dir}/${f}")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${PROJECT_NAME}_perf ALL
|
||||
add_custom_target(${PROJECT_NAME}_perf
|
||||
DEPENDS ${OCV_JS_PATH} ${opencv_perf_js_file_deps})
|
||||
|
||||
#loader
|
||||
@ -198,4 +166,6 @@ add_custom_command(
|
||||
list(APPEND opencv_loader_js_file_deps "${loader_dir}/loader.js" "${opencv_loader_js_bin_dir}/loader.js")
|
||||
|
||||
add_custom_target(${PROJECT_NAME}_loader ALL
|
||||
DEPENDS ${OCV_JS_PATH} ${opencv_loader_js_file_deps})
|
||||
DEPENDS ${OCV_JS_PATH} ${opencv_loader_js_file_deps})
|
||||
|
||||
add_custom_target(opencv_test_js ALL DEPENDS opencv_js_test opencv_js_perf opencv_js_loader)
|
||||
|
13
modules/js/common.cmake
Normal file
13
modules/js/common.cmake
Normal file
@ -0,0 +1,13 @@
|
||||
# get list of modules to wrap
|
||||
if(HAVE_opencv_js)
|
||||
message(STATUS "Wrapped in JavaScript(js):")
|
||||
endif()
|
||||
set(OPENCV_JS_MODULES "")
|
||||
foreach(m ${OPENCV_MODULES_BUILD})
|
||||
if(";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";js;" AND HAVE_${m})
|
||||
list(APPEND OPENCV_JS_MODULES ${m})
|
||||
if(HAVE_opencv_js)
|
||||
message(STATUS " ${m}")
|
||||
endif()
|
||||
endif()
|
||||
endforeach()
|
74
modules/js/generator/CMakeLists.txt
Normal file
74
modules/js/generator/CMakeLists.txt
Normal file
@ -0,0 +1,74 @@
|
||||
set(MODULE_NAME "js_bindings_generator")
|
||||
set(OPENCV_MODULE_IS_PART_OF_WORLD FALSE)
|
||||
ocv_add_module(${MODULE_NAME} INTERNAL)
|
||||
|
||||
set(OPENCV_JS_BINDINGS_DIR "${CMAKE_CURRENT_BINARY_DIR}" CACHE INTERNAL "")
|
||||
file(REMOVE_RECURSE "${OPENCV_JS_BINDINGS_DIR}/gen")
|
||||
file(MAKE_DIRECTORY "${OPENCV_JS_BINDINGS_DIR}/gen")
|
||||
file(REMOVE "${OPENCV_DEPHELPER}/gen_opencv_js_source") # force re-run after CMake
|
||||
|
||||
# This file is included from a subdirectory
|
||||
set(JS_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/..")
|
||||
include(${JS_SOURCE_DIR}/common.cmake) # fill OPENCV_JS_MODULES
|
||||
|
||||
set(opencv_hdrs "")
|
||||
foreach(m ${OPENCV_JS_MODULES})
|
||||
list(APPEND opencv_hdrs ${OPENCV_MODULE_${m}_HEADERS})
|
||||
endforeach(m)
|
||||
|
||||
# header blacklist
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*.h$")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/cuda")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/opencl")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/opengl.hpp")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/ocl.hpp")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cuda.*")
|
||||
ocv_list_filterout(opencv_hdrs "modules/cudev")
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/.*/hal/")
|
||||
ocv_list_filterout(opencv_hdrs "modules/.*/detection_based_tracker.hpp") # Conditional compilation
|
||||
ocv_list_filterout(opencv_hdrs "modules/core/include/opencv2/core/utils/.*")
|
||||
|
||||
ocv_update_file("${CMAKE_CURRENT_BINARY_DIR}/headers.txt" "${opencv_hdrs}")
|
||||
|
||||
set(bindings_cpp "${OPENCV_JS_BINDINGS_DIR}/gen/bindings.cpp")
|
||||
|
||||
set(scripts_hdr_parser "${JS_SOURCE_DIR}/../python/src2/hdr_parser.py")
|
||||
|
||||
if(DEFINED ENV{OPENCV_JS_WHITELIST})
|
||||
set(OPENCV_JS_WHITELIST_FILE "$ENV{OPENCV_JS_WHITELIST}")
|
||||
else()
|
||||
set(OPENCV_JS_WHITELIST_FILE "${OpenCV_SOURCE_DIR}/platforms/js/opencv_js.config.py")
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
OUTPUT ${bindings_cpp} "${OPENCV_DEPHELPER}/gen_opencv_js_source"
|
||||
COMMAND
|
||||
${PYTHON_DEFAULT_EXECUTABLE}
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/embindgen.py"
|
||||
"${scripts_hdr_parser}"
|
||||
"${bindings_cpp}"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/headers.txt"
|
||||
"${JS_SOURCE_DIR}/src/core_bindings.cpp"
|
||||
"${OPENCV_JS_WHITELIST_FILE}"
|
||||
COMMAND
|
||||
${CMAKE_COMMAND} -E touch "${OPENCV_DEPHELPER}/gen_opencv_js_source"
|
||||
WORKING_DIRECTORY
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/gen"
|
||||
DEPENDS
|
||||
${JS_SOURCE_DIR}/src/core_bindings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/embindgen.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/templates.py
|
||||
${scripts_hdr_parser}
|
||||
#(not needed - generated by CMake) ${CMAKE_CURRENT_BINARY_DIR}/headers.txt
|
||||
${opencv_hdrs}
|
||||
COMMENT "Generate source files for JavaScript bindings"
|
||||
)
|
||||
|
||||
add_custom_target(gen_opencv_js_source
|
||||
# excluded from all: ALL
|
||||
DEPENDS ${bindings_cpp} "${OPENCV_DEPHELPER}/gen_opencv_js_source"
|
||||
SOURCES
|
||||
${JS_SOURCE_DIR}/src/core_bindings.cpp
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/embindgen.py
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/templates.py
|
||||
)
|
@ -104,8 +104,6 @@ def makeWhiteList(module_list):
|
||||
return wl
|
||||
|
||||
white_list = None
|
||||
exec(open(os.environ["OPENCV_JS_WHITELIST"]).read())
|
||||
assert(white_list)
|
||||
|
||||
# Features to be exported
|
||||
export_enums = False
|
||||
@ -891,10 +889,10 @@ class JSWrapperGenerator(object):
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
if len(sys.argv) < 4:
|
||||
if len(sys.argv) < 5:
|
||||
print("Usage:\n", \
|
||||
os.path.basename(sys.argv[0]), \
|
||||
"<full path to hdr_parser.py> <bindings.cpp> <headers.txt> <core_bindings.cpp>")
|
||||
"<full path to hdr_parser.py> <bindings.cpp> <headers.txt> <core_bindings.cpp> <opencv_js.config.py>")
|
||||
print("Current args are: ", ", ".join(["'"+a+"'" for a in sys.argv]))
|
||||
exit(0)
|
||||
|
||||
@ -908,5 +906,9 @@ if __name__ == "__main__":
|
||||
bindingsCpp = sys.argv[2]
|
||||
headers = open(sys.argv[3], 'r').read().split(';')
|
||||
coreBindings = sys.argv[4]
|
||||
whiteListFile = sys.argv[5]
|
||||
exec(open(whiteListFile).read())
|
||||
assert(white_list)
|
||||
|
||||
generator = JSWrapperGenerator()
|
||||
generator.gen(bindingsCpp, headers, coreBindings)
|
@ -88,7 +88,7 @@ using namespace emscripten;
|
||||
using namespace cv;
|
||||
|
||||
#ifdef HAVE_OPENCV_DNN
|
||||
using namespace dnn;
|
||||
using namespace cv::dnn;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_OPENCV_ARUCO
|
||||
|
@ -11,7 +11,7 @@ set(PYTHON_SOURCE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/../")
|
||||
# get list of modules to wrap
|
||||
set(OPENCV_PYTHON_MODULES)
|
||||
foreach(m ${OPENCV_MODULES_BUILD})
|
||||
if (";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";${MODULE_NAME};" AND HAVE_${m})
|
||||
if (";${OPENCV_MODULE_${m}_WRAPPERS};" MATCHES ";python;" AND HAVE_${m})
|
||||
list(APPEND OPENCV_PYTHON_MODULES ${m})
|
||||
#message(STATUS "\t${m}")
|
||||
endif()
|
||||
|
@ -18,6 +18,10 @@ except ImportError:
|
||||
|
||||
def bootstrap():
|
||||
import sys
|
||||
|
||||
import copy
|
||||
save_sys_path = copy.copy(sys.path)
|
||||
|
||||
if hasattr(sys, 'OpenCV_LOADER'):
|
||||
print(sys.path)
|
||||
raise ImportError('ERROR: recursion is detected during loading of "cv2" binary extensions. Check OpenCV installation.')
|
||||
@ -85,6 +89,8 @@ def bootstrap():
|
||||
del sys.modules['cv2']
|
||||
import cv2
|
||||
|
||||
sys.path = save_sys_path # multiprocessing should start from bootstrap code (https://github.com/opencv/opencv/issues/18502)
|
||||
|
||||
try:
|
||||
import sys
|
||||
del sys.OpenCV_LOADER
|
||||
|
@ -13,6 +13,7 @@ void checkIppStatus();
|
||||
extern bool skipUnstableTests;
|
||||
extern bool runBigDataTests;
|
||||
extern int testThreads;
|
||||
extern int debugLevel; //< 0 - no debug, 1 - basic test debug information, >1 - extra debug information
|
||||
|
||||
void testSetUp();
|
||||
void testTearDown();
|
||||
|
@ -774,6 +774,7 @@ static bool checkTestData = cv::utils::getConfigurationParameterBool("OPENCV_TES
|
||||
bool skipUnstableTests = false;
|
||||
bool runBigDataTests = false;
|
||||
int testThreads = 0;
|
||||
int debugLevel = (int)cv::utils::getConfigurationParameterSizeT("OPENCV_TEST_DEBUG", 0);
|
||||
|
||||
|
||||
static size_t memory_usage_base = 0;
|
||||
@ -883,6 +884,7 @@ void parseCustomOptions(int argc, char **argv)
|
||||
"{ test_threads |-1 |the number of worker threads, if parallel execution is enabled}"
|
||||
"{ skip_unstable |false |skip unstable tests }"
|
||||
"{ test_bigdata |false |run BigData tests (>=2Gb) }"
|
||||
"{ test_debug | |0 - no debug (default), 1 - basic test debug information, >1 - extra debug information }"
|
||||
"{ test_require_data |") + (checkTestData ? "true" : "false") + string("|fail on missing non-required test data instead of skip (env:OPENCV_TEST_REQUIRE_DATA)}"
|
||||
CV_TEST_TAGS_PARAMS
|
||||
"{ h help |false |print help info }"
|
||||
@ -909,6 +911,14 @@ void parseCustomOptions(int argc, char **argv)
|
||||
|
||||
skipUnstableTests = parser.get<bool>("skip_unstable");
|
||||
runBigDataTests = parser.get<bool>("test_bigdata");
|
||||
if (parser.has("test_debug"))
|
||||
{
|
||||
cv::String s = parser.get<cv::String>("test_debug");
|
||||
if (s.empty() || s == "true")
|
||||
debugLevel = 1;
|
||||
else
|
||||
debugLevel = parser.get<int>("test_debug");
|
||||
}
|
||||
if (parser.has("test_require_data"))
|
||||
checkTestData = parser.get<bool>("test_require_data");
|
||||
|
||||
@ -1122,7 +1132,9 @@ void SystemInfoCollector::OnTestProgramStart(const testing::UnitTest&)
|
||||
}
|
||||
recordPropertyVerbose("cv_cpu_features", "CPU features", cv::getCPUFeaturesLine());
|
||||
#ifdef HAVE_IPP
|
||||
recordPropertyVerbose("cv_ipp_version", "Intel(R) IPP version", cv::ipp::useIPP() ? cv::ipp::getIppVersion() : "disabled");
|
||||
recordPropertyVerbose("cv_ipp_version", "Intel(R) IPP version", cv::ipp::useIPP() ? cv::ipp::getIppVersion() : "disabled");
|
||||
if (cv::ipp::useIPP())
|
||||
recordPropertyVerbose("cv_ipp_features", "Intel(R) IPP features code", cv::format("0x%llx", cv::ipp::getIppTopFeatures()));
|
||||
#endif
|
||||
#ifdef HAVE_OPENCL
|
||||
cv::dumpOpenCLInformation();
|
||||
|
@ -116,6 +116,8 @@ double MotionJpegCapture::getProperty(int property) const
|
||||
{
|
||||
case CAP_PROP_POS_FRAMES:
|
||||
return (double)getFramePos();
|
||||
case CAP_PROP_POS_MSEC:
|
||||
return (double)getFramePos() * (1000. / m_fps);
|
||||
case CAP_PROP_POS_AVI_RATIO:
|
||||
return double(getFramePos())/m_mjpeg_frames.size();
|
||||
case CAP_PROP_FRAME_WIDTH:
|
||||
|
@ -351,8 +351,6 @@ public:
|
||||
|
||||
STDMETHODIMP OnReadSample(HRESULT hrStatus, DWORD dwStreamIndex, DWORD dwStreamFlags, LONGLONG llTimestamp, IMFSample *pSample) CV_OVERRIDE
|
||||
{
|
||||
CV_UNUSED(llTimestamp);
|
||||
|
||||
HRESULT hr = 0;
|
||||
cv::AutoLock lock(m_mutex);
|
||||
|
||||
@ -365,6 +363,7 @@ public:
|
||||
{
|
||||
CV_LOG_DEBUG(NULL, "videoio(MSMF): drop frame (not processed)");
|
||||
}
|
||||
m_lastSampleTimestamp = llTimestamp;
|
||||
m_lastSample = pSample;
|
||||
}
|
||||
}
|
||||
@ -444,6 +443,7 @@ public:
|
||||
|
||||
IMFSourceReader *m_reader;
|
||||
DWORD m_dwStreamIndex;
|
||||
LONGLONG m_lastSampleTimestamp;
|
||||
_ComPtr<IMFSample> m_lastSample;
|
||||
};
|
||||
|
||||
@ -917,6 +917,7 @@ bool CvCapture_MSMF::grabFrame()
|
||||
CV_LOG_WARNING(NULL, "videoio(MSMF): EOS signal. Capture stream is lost");
|
||||
return false;
|
||||
}
|
||||
sampleTime = reader->m_lastSampleTimestamp;
|
||||
return true;
|
||||
}
|
||||
else if (isOpen)
|
||||
|
@ -12,21 +12,51 @@
|
||||
|
||||
namespace opencv_test { namespace {
|
||||
|
||||
static void test_readFrames(/*const*/ VideoCapture& capture, const int N = 100, Mat* lastFrame = NULL)
|
||||
static void test_readFrames(/*const*/ VideoCapture& capture, const int N = 100, Mat* lastFrame = NULL, bool testTimestamps = true)
|
||||
{
|
||||
Mat frame;
|
||||
int64 time0 = cv::getTickCount();
|
||||
int64 sysTimePrev = time0;
|
||||
const double cvTickFreq = cv::getTickFrequency();
|
||||
|
||||
double camTimePrev = 0.0;
|
||||
const double fps = capture.get(cv::CAP_PROP_FPS);
|
||||
const double framePeriod = fps == 0.0 ? 1. : 1.0 / fps;
|
||||
|
||||
const bool validTickAndFps = cvTickFreq != 0 && fps != 0.;
|
||||
testTimestamps &= validTickAndFps;
|
||||
|
||||
for (int i = 0; i < N; i++)
|
||||
{
|
||||
SCOPED_TRACE(cv::format("frame=%d", i));
|
||||
|
||||
capture >> frame;
|
||||
const int64 sysTimeCurr = cv::getTickCount();
|
||||
const double camTimeCurr = capture.get(cv::CAP_PROP_POS_MSEC);
|
||||
ASSERT_FALSE(frame.empty());
|
||||
|
||||
// Do we have a previous frame?
|
||||
if (i > 0 && testTimestamps)
|
||||
{
|
||||
const double sysTimeElapsedSecs = (sysTimeCurr - sysTimePrev) / cvTickFreq;
|
||||
const double camTimeElapsedSecs = (camTimeCurr - camTimePrev) / 1000.;
|
||||
|
||||
// Check that the time between two camera frames and two system time calls
|
||||
// are within 1.5 frame periods of one another.
|
||||
//
|
||||
// 1.5x is chosen to accomodate for a dropped frame, and an additional 50%
|
||||
// to account for drift in the scale of the camera and system time domains.
|
||||
EXPECT_NEAR(sysTimeElapsedSecs, camTimeElapsedSecs, framePeriod * 1.5);
|
||||
}
|
||||
|
||||
EXPECT_GT(cvtest::norm(frame, NORM_INF), 0) << "Complete black image has been received";
|
||||
|
||||
sysTimePrev = sysTimeCurr;
|
||||
camTimePrev = camTimeCurr;
|
||||
}
|
||||
|
||||
int64 time1 = cv::getTickCount();
|
||||
printf("Processed %d frames on %.2f FPS\n", N, (N * cv::getTickFrequency()) / (time1 - time0 + 1));
|
||||
printf("Processed %d frames on %.2f FPS\n", N, (N * cvTickFreq) / (time1 - time0 + 1));
|
||||
if (lastFrame) *lastFrame = frame.clone();
|
||||
}
|
||||
|
||||
|
@ -233,6 +233,34 @@ public:
|
||||
else
|
||||
std::cout << "Frames counter is not available. Actual frames: " << count_actual << ". SKIP check." << std::endl;
|
||||
}
|
||||
|
||||
void doTimestampTest()
|
||||
{
|
||||
if (!isBackendAvailable(apiPref, cv::videoio_registry::getStreamBackends()))
|
||||
throw SkipTestException(cv::String("Backend is not available/disabled: ") + cv::videoio_registry::getBackendName(apiPref));
|
||||
|
||||
if (((apiPref == CAP_FFMPEG) && ((ext == "h264") || (ext == "h265"))))
|
||||
throw SkipTestException(cv::String("Backend ") + cv::videoio_registry::getBackendName(apiPref) +
|
||||
cv::String(" does not support CAP_PROP_POS_MSEC option"));
|
||||
|
||||
VideoCapture cap;
|
||||
EXPECT_NO_THROW(cap.open(video_file, apiPref));
|
||||
if (!cap.isOpened())
|
||||
throw SkipTestException(cv::String("Backend ") + cv::videoio_registry::getBackendName(apiPref) +
|
||||
cv::String(" can't open the video: ") + video_file);
|
||||
|
||||
Mat img;
|
||||
for(int i = 0; i < 10; i++)
|
||||
{
|
||||
double timestamp = 0;
|
||||
ASSERT_NO_THROW(cap >> img);
|
||||
EXPECT_NO_THROW(timestamp = cap.get(CAP_PROP_POS_MSEC));
|
||||
const double frame_period = 1000.f/bunny_param.getFps();
|
||||
// NOTE: eps == frame_period, because videoCapture returns frame begining timestamp or frame end
|
||||
// timestamp depending on codec and back-end. So the first frame has timestamp 0 or frame_period.
|
||||
EXPECT_NEAR(timestamp, i*frame_period, frame_period);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
//==================================================================================================
|
||||
@ -353,6 +381,8 @@ TEST_P(videoio_bunny, read_position) { doTest(); }
|
||||
|
||||
TEST_P(videoio_bunny, frame_count) { doFrameCountTest(); }
|
||||
|
||||
TEST_P(videoio_bunny, frame_timestamp) { doTimestampTest(); }
|
||||
|
||||
INSTANTIATE_TEST_CASE_P(videoio, videoio_bunny,
|
||||
testing::Combine(
|
||||
testing::ValuesIn(bunny_params),
|
||||
|
@ -131,11 +131,9 @@ class Builder:
|
||||
"-DBUILD_opencv_superres=OFF",
|
||||
"-DBUILD_opencv_stitching=OFF",
|
||||
"-DBUILD_opencv_java=OFF",
|
||||
"-DBUILD_opencv_java_bindings_generator=OFF",
|
||||
"-DBUILD_opencv_js=ON",
|
||||
"-DBUILD_opencv_python2=OFF",
|
||||
"-DBUILD_opencv_python3=OFF",
|
||||
"-DBUILD_opencv_python_bindings_generator=OFF",
|
||||
"-DBUILD_EXAMPLES=OFF",
|
||||
"-DBUILD_PACKAGE=OFF",
|
||||
"-DBUILD_TESTS=OFF",
|
||||
|
Loading…
Reference in New Issue
Block a user