简单使用TensorFlow.js在浏览器进行视频实时目标识别(基于YOLO V3)

!!! 完全忘记当时是怎么写了,我不会了 !!!

背景

在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

posted @ 2020-10-12 18:22  iNick  阅读(2414)  评论(0编辑  收藏  举报