提交 6fdb7aee 编写于 作者: A Alexander Alekhin

Merge remote-tracking branch 'upstream/3.4' into merge-3.4

......@@ -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
......
set(OPENCV_SKIP_LINK_AS_NEEDED 1)
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);
}
}
<!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>
\ No newline at end of file
{
"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"
}
]
}
\ No newline at end of file
<!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>
\ No newline at end of file
<!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>
\ No newline at end of file
{
"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"
}
]
}
\ No newline at end of file
<!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>
\ No newline at end of file
<!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>
\ No newline at end of file
{
"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"
}
]
}
\ No newline at end of file
<!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>
\ No newline at end of file
{
"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"
}
]
}
\ No newline at end of file
<!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>
\ No newline at end of file
{
"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"
}
]
}
\ No newline at end of file
......@@ -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();
}
}
}
});
......
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
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
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
\ No newline at end of file
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:
![](images/videoCompressSelect.png)
......
......@@ -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);
}
};
......
# ----------------------------------------------------------------------------
# CMake file for js support
# ----------------------------------------------------------------------------
set(the_description "The js bindings")
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)
ocv_module_disable(js)
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})
\ No newline at end of file
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)
# 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()
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",
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册