!!! 完全忘記當時是怎么寫了,我不會了 !!!
背景
在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