簡單使用TensorFlow.js在瀏覽器進行視訊實時目標識別(基於YOLO V3)
阿新 • • 發佈:2020-10-12
背景
在GitHub檢視 TensorFlow.js 的專案時,...
繼上次的官方例項之後,又在GitHub發現了新的實現方式.
GitHub地址: https://github.com/zqingr/tfjs-yolov3
執行原理
使用 TensorFlow.js 匯入轉換後的 YOLO-V3 模型,
對視訊或者圖片進行檢測,拿到對應的座標之後顯示.
在這裡我是使用div絕對定位顯示對於的框框.
(有一個巨大的BUG,一段時間後會佔滿GPU,然後黑屏)
大概流程:
- 使用video標籤載入MP4檔案
- 使用TensorFlow.js 載入 YOLO-V3 模型
- 呼叫模型檢測方法,獲取座標並顯示到頁面
- 使用setTimeout進行延遲後進行下一次檢測
- (也可以requestAnimationFrame,不過有時會卡住)
執行效果
截圖:
GIF:
執行方式
推薦放到web軟體容器當中
例如: Nginx
我自己是使用 http-server 啟動的web服務
然後訪問相對應的地址就好了.
關於http-server
http-server需要先安裝 Node.js 和 npm
然後執行npm安裝命令:
npm install http-server -g
安裝完之後,去指定資料夾執行命令,就可以啟動一個靜態檔案伺服器
例如
http-server . -p 2333
其中的 .
代表當前目錄
-p 指定埠,後面的 2333 表示使用 2333 埠
程式碼
相關檔案我放到網盤和QQ群
群號: 492781269
城通網盤: https://306t.com/file/29360148-466426046
下面直接公示程式碼.
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <title>TensorFlow.js Demo</title> <style> #big-box { position: relative; } #img-box { position: absolute; top: 0px; left: 0px; } #img-box .rect { position: absolute; border: 2px solid #f00; pointer-events: none; } #img-box .rect .className { position: absolute; top: 0; /* background: #f00; */ color: #fff; } #myPlayer { max-width: 600px; width: 100%; } </style> </head> <body> <script src="tfjs-m.min.js"></script> <script src="config.js"></script> <script src="yolo-tfjs-m.js"></script> <div id="showBox">等待模型載入...</div> <br> <div id="big-box"> <video id="myPlayer" muted="true" autoplay src="demo01.mp4" controls="" playsinline="" webkit-playsinline=""> </video> <!-- 用於展示識別框 --> <div id="img-box"> </div> </div> <script> var myModel = null; var V = null; var requestAnimationFrameIndex = null; var myPlayer = document.getElementById("myPlayer"); var videoHeight = 0; var videoWidth = 0; var clientHeight = 0; var clientWidth = 0; var modelLoad = false; var videoLoad = false; var anchors = ANCHORS_TINY; var modelUrl = 'yolov3-tiny/model.json'; var modelPromise = tf.loadLayersModel(modelUrl); window.onload = function () { // 當視訊準備好了就準備開始識別吧 myPlayer.addEventListener("canplay", function () { videoHeight = myPlayer.videoHeight; videoWidth = myPlayer.videoWidth; clientHeight = myPlayer.clientHeight; clientWidth = myPlayer.clientWidth; V = this; videoLoad = true; }) loadModel(); } // 載入模型檔案 function loadModel() { if (modelLoad) { return; } // Load the model. modelPromise.then(model => { var showBox = document.getElementById("showBox"); showBox.innerHTML = "載入成功"; myModel = model; detectImage(); modelLoad = true; }); } // 識別圖片,並在頁面展示 function detectImage() { var showBox = document.getElementById("showBox"); showBox.innerHTML = "識別中..."; if (videoLoad) { // 準備用於識別的樣本 var sample = tf.stack([ tf.div(tf.cast(tf.browser.fromPixels(V), 'float32'), 255) ]) // 獲取到識別的結果 let output = (myModel.predict(sample)); // output = output.map(feats => feats.reshape(feats.shape.slice(1)) ) var boxes = yoloEval( output, tf.tensor1d(anchors).reshape([-1, 2]), COCO_CLASSESS.length, [videoHeight, videoWidth] ) boxes.then(myBoxes => { showBox.innerHTML = "識別完畢"; var $imgbox = document.getElementById('img-box'); $imgbox.innerHTML = ""; myBoxes.forEach(box => { var $div = document.createElement('div'); $div.className = 'rect'; var heightScale = (clientHeight / videoHeight); var widthScale = (clientWidth / videoWidth); var transformTop = box.top * heightScale; var transformLeft = box.left * widthScale; var transformWidth = box.width * widthScale; var transformHeight = box.height * heightScale; $div.style.top = transformTop + 'px'; $div.style.left = transformLeft + 'px'; $div.style.width = transformWidth + 'px'; $div.style.height = transformHeight + 'px'; $div.innerHTML = `<span class='className'>${box.classes} ${box.scores}</span>`; $imgbox.appendChild($div); }) setTimeout(function () { detectImage(); }, 10); }) } } </script> </body> </html>
PS:
如有錯誤,還請多多指出來~
– Nick
– 2020/10/12