├── README.md ├── index.html ├── index.js ├── model └── haarcascade_frontalface_default.xml ├── opencv.js └── opencv_js.wasm /README.md: -------------------------------------------------------------------------------- 1 | # 使用OpenCV在前端进行人脸检测的实践 2 | 3 | ## 预览 4 | 5 | https://tidusinspira.github.io/opencv-wasm-example/ 6 | 7 | ## 运行 8 | 9 | ```bash 10 | php -S 0.0.0.0:9999 或 放在nginx、apache等其他web服务器里运行 11 | ``` 12 | 13 | ## 构建过程 14 | 15 | ### 安装Emscripten SDK 16 | ```bash 17 | git clone https://github.com/juj/emsdk.git 18 | cd emsdk 19 | ./emsdk install latest 20 | ./emsdk activate latest 21 | source ./emsdk_env.sh 22 | ``` 23 | 24 | ### 获取OpenCV 25 | ```bash 26 | wget https://github.com/opencv/opencv/archive/3.4.1.zip 27 | unzip 3.4.1.zip 28 | cd opencv-3.4.1 29 | # 将OpenCV编译为WASM版本 30 | python ./platform/js/build_js.py build_wasm --build_wasm 31 | 32 | # 编译后的文件将生成在build_wasm/bin目录内,得到需要的opencv_js.wasm和opencv.js文件 33 | ``` 34 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | Document 8 | 9 | 10 | 11 |
12 | 13 | 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | let videoWidth = 640; 2 | let videoHeight = 480; 3 | let outputCanvas = document.createElement('canvas'); 4 | 5 | let cap = null; 6 | let faceCascade = null; 7 | let src = null; 8 | let gray = null; 9 | 10 | navigator.getUserMedia = 11 | navigator.getUserMedia || 12 | navigator.webkitGetUserMedia || 13 | navigator.mozGetUserMedia || 14 | navigator.msGetUserMeida; 15 | 16 | function run() { 17 | faceCascade = new cv.CascadeClassifier(); 18 | faceCascade.load('face.xml'); 19 | 20 | cap = new cv.VideoCapture(video); 21 | src = new cv.Mat(videoHeight, videoWidth, cv.CV_8UC4); 22 | gray = new cv.Mat(videoHeight, videoWidth, cv.CV_8UC1); 23 | 24 | startCamera(); 25 | requestAnimationFrame(detectFace); 26 | } 27 | 28 | function startCamera() { 29 | navigator.getUserMedia( 30 | { 31 | video: true 32 | }, 33 | function(stream) { 34 | video.srcObject = stream; 35 | video.play(); 36 | }, 37 | function(error) { 38 | console.error(error.name || error); 39 | } 40 | ); 41 | } 42 | 43 | function saveImage(canvas, filename) { 44 | var image = canvas 45 | .toDataURL('image/png') 46 | .replace('image/png', 'image/octet-stream'); 47 | let imgList = document.querySelector('#imgList'); 48 | appendImage(image, imgList); 49 | } 50 | 51 | function appendImage(url, node) { 52 | var image = document.createElement('img'); 53 | image.src = url; 54 | image.style.width = '100px'; 55 | node.appendChild(image); 56 | } 57 | 58 | function detectFace() { 59 | // Capture a frame 60 | cap.read(src); 61 | 62 | // Convert to greyscale 63 | cv.cvtColor(src, gray, cv.COLOR_RGBA2GRAY); 64 | 65 | // Downsample 66 | let downSampled = new cv.Mat(); 67 | cv.pyrDown(gray, downSampled); 68 | cv.pyrDown(downSampled, downSampled); 69 | 70 | // Detect faces 71 | let faces = new cv.RectVector(); 72 | faceCascade.detectMultiScale(downSampled, faces); 73 | 74 | // Draw boxes 75 | let size = downSampled.size(); 76 | let xRatio = videoWidth / size.width; 77 | let yRatio = videoHeight / size.height; 78 | for (let i = 0; i < faces.size(); ++i) { 79 | let face = faces.get(i); 80 | let point1 = new cv.Point(face.x * xRatio, face.y * yRatio); 81 | let point2 = new cv.Point( 82 | (face.x + face.width) * xRatio, 83 | (face.y + face.height) * xRatio 84 | ); 85 | cv.rectangle(src, point1, point2, [255, 0, 0, 255]); 86 | saveImage(outputCanvas); 87 | } 88 | // Free memory 89 | downSampled.delete(); 90 | faces.delete(); 91 | 92 | // Show image 93 | cv.imshow(outputCanvas, src); 94 | 95 | requestAnimationFrame(detectFace); 96 | } 97 | 98 | // Config OpenCV 99 | var Module = { 100 | locateFile: function(name) { 101 | let files = { 102 | 'opencv_js.wasm': 'opencv_js.wasm' 103 | }; 104 | return files[name]; 105 | }, 106 | preRun: [ 107 | () => { 108 | Module.FS_createPreloadedFile( 109 | '/', 110 | 'face.xml', 111 | 'model/haarcascade_frontalface_default.xml', 112 | true, 113 | false 114 | ); 115 | } 116 | ], 117 | postRun: [run] 118 | }; 119 | -------------------------------------------------------------------------------- /opencv_js.wasm: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/TidusInSpira/opencv-wasm-example/0ec8fbec31dbd211d958ad795d0f862b134fca48/opencv_js.wasm --------------------------------------------------------------------------------