git clone https://github.com/opencv/opencv.git
emcmake python ./opencv/platforms/js/build_js.py build_wasm --build_wasm
cd ./build_wasm/bin/ && open .
接著打開loader.js會如下:
async function loadOpenCV(paths, onloadCallback) {
let OPENCV_URL = "";
let asmPath = "";
let wasmPath = "";
let simdPath = "";
let threadsPath = "";
let threadsSimdPath = "";
if(!(paths instanceof Object)) {
throw new Error("The first input should be a object that points the path to the OpenCV.js");
}
if ("asm" in paths) {
asmPath = paths["asm"];
}
if ("wasm" in paths) {
wasmPath = paths["wasm"];
}
if ("threads" in paths) {
threadsPath = paths["threads"];
}
if ("simd" in paths) {
simdPath = paths["simd"];
}
if ("threadsSimd" in paths) {
threadsSimdPath = paths["threadsSimd"];
}
let wasmSupported = !(typeof WebAssembly === 'undefined');
if (!wasmSupported && OPENCV_URL === "" && asmPath != "") {
OPENCV_URL = asmPath;
console.log("The OpenCV.js for Asm.js is loaded now");
} else if (!wasmSupported && asmPath == ""){
throw new Error("The browser supports the Asm.js only, but the path of OpenCV.js for Asm.js is empty");
}
let simdSupported = wasmSupported ? await wasmFeatureDetect.simd() : false;
let threadsSupported = wasmSupported ? await wasmFeatureDetect.threads() : false;
if (simdSupported && threadsSupported && threadsSimdPath != "") {
OPENCV_URL = threadsSimdPath;
console.log("The OpenCV.js with simd and threads optimization is loaded now");
} else if (simdSupported && simdPath != "") {
if (threadsSupported && threadsSimdPath === "") {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
OPENCV_URL = simdPath;
console.log("The OpenCV.js with simd optimization is loaded now.");
} else if (threadsSupported && threadsPath != "") {
if (simdSupported && threadsSimdPath === "") {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
OPENCV_URL = threadsPath;
console.log("The OpenCV.js with threads optimization is loaded now");
} else if (wasmSupported && wasmPath != "") {
if(simdSupported && threadsSupported) {
console.log("The browser supports simd and threads, but the path of OpenCV.js with simd and threads optimization is empty");
}
if (simdSupported) {
console.log("The browser supports simd optimization, but the path of OpenCV.js with simd optimization is empty");
}
if (threadsSupported) {
console.log("The browser supports threads optimization, but the path of OpenCV.js with threads optimization is empty");
}
OPENCV_URL = wasmPath;
console.log("The OpenCV.js for wasm is loaded now");
} else if (wasmSupported) {
console.log("The browser supports wasm, but the path of OpenCV.js for wasm is empty");
}
if (OPENCV_URL === "") {
throw new Error("No available OpenCV.js, please check your paths");
}
let script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('type', 'text/javascript');
script.addEventListener('load', () => {
onloadCallback();
});
script.addEventListener('error', () => {
console.log('Failed to load opencv.js');
});
script.src = OPENCV_URL;
let node = document.getElementsByTagName('script')[0];
if (node.src != OPENCV_URL) {
node.parentNode.insertBefore(script, node);
}
}
接著修改為為如下代碼:
async function loadOpenCV(onloadCallback) {
const OPENCV_URL = './opencv.js'
let script = document.createElement('script');
script.setAttribute('async', '');
script.setAttribute('type', 'text/javascript');
script.addEventListener('load', async () => {
if (cv.getBuildInformation) {
onloadCallback()
} else {
if (cv instanceof Promise) {
cv = await cv
console.log(cv.getBuildInformation())
onloadCallback()
} else {
cv['onRuntimeInitialized'] = () => {
onloadCallback()
}
}
}
onloadCallback();
});
script.addEventListener('error', () => {
console.log('Failed to load opencv.js')
});
script.src = OPENCV_URL;
let node = document.getElementsByTagName('script')[0]
if (node.src !== OPENCV_URL) {
node.parentNode.insertBefore(script, node)
}
}
OpenCV的Hello world當然非圖片轉灰階莫屬,所以接著將示範代碼複製到bin資料夾的index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>Opencv 4.7.0 to WebAssembly by Follow Fang</title>
<script src="./loader.js"></script>
<script>
let isLoadCV = false
let originImg
let grayImg
const reader = new FileReader()
async function onLoad() {
await loadOpenCV(loadCV)
}
const loadCV = () => {
isLoadCV = true
originImg = document.getElementById('originImg')
grayImg = document.getElementById('grayImg')
originImg.onload = () => imgLoad()
}
const imgLoad = () => {
const src = cv.imread(originImg)
const gray = new cv.Mat()
cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY)
cv.imshow('grayImg', gray)
src.delete()
}
const uploadImage = (e) => reader.readAsDataURL(e.target.files[0]);
reader.onload = () => {
originImg.src = reader.result
}
</script>
</head>
<body onload="onLoad()">
<div>
<input type="file" accept="image/*" onchange="uploadImage(event)"><br>upload images<br>
<img id="originImg" alt=""/>
</div>
<canvas id="grayImg" alt=""/>
</div>
</body>
</html>
效果圖如下:
參考資料:
Build OpenCV.js